aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/RelNotes-1.6.0.3.txt35
-rw-r--r--Documentation/RelNotes-1.6.1.txt58
-rw-r--r--Documentation/config.txt9
-rw-r--r--Documentation/diff-options.txt3
-rw-r--r--Documentation/git-check-attr.txt50
-rw-r--r--Documentation/git-checkout.txt2
-rw-r--r--Documentation/git-commit.txt3
-rw-r--r--Documentation/git-grep.txt6
-rw-r--r--Documentation/git-prune.txt5
-rw-r--r--Documentation/git-push.txt24
-rw-r--r--Documentation/git-send-email.txt242
-rw-r--r--Documentation/git-svn.txt24
-rw-r--r--Documentation/gitattributes.txt2
-rw-r--r--Documentation/gittutorial-2.txt15
-rw-r--r--Documentation/howto/rebase-and-edit.txt79
-rw-r--r--Makefile5
-rw-r--r--archive-tar.c6
-rw-r--r--archive.c6
-rw-r--r--builtin-add.c4
-rw-r--r--builtin-apply.c35
-rw-r--r--builtin-blame.c3
-rw-r--r--builtin-branch.c3
-rw-r--r--builtin-cat-file.c3
-rw-r--r--builtin-checkout-index.c4
-rw-r--r--builtin-checkout.c15
-rw-r--r--builtin-clean.c6
-rw-r--r--builtin-clone.c9
-rw-r--r--builtin-commit.c30
-rw-r--r--builtin-diff.c4
-rw-r--r--builtin-fetch--tool.c3
-rw-r--r--builtin-fmt-merge-msg.c53
-rw-r--r--builtin-grep.c8
-rw-r--r--builtin-help.c4
-rw-r--r--builtin-init-db.c12
-rw-r--r--builtin-log.c13
-rw-r--r--builtin-merge-base.c37
-rw-r--r--builtin-merge-file.c68
-rw-r--r--builtin-merge.c44
-rw-r--r--builtin-pack-objects.c4
-rw-r--r--builtin-prune.c10
-rw-r--r--builtin-push.c2
-rw-r--r--builtin-remote.c8
-rw-r--r--builtin-rev-list.c3
-rw-r--r--builtin-rev-parse.c4
-rw-r--r--builtin-rm.c1
-rw-r--r--builtin-show-branch.c3
-rw-r--r--builtin-stripspace.c3
-rw-r--r--builtin-tag.c3
-rw-r--r--builtin-unpack-objects.c3
-rw-r--r--builtin-update-index.c12
-rw-r--r--cache.h3
-rw-r--r--combine-diff.c3
-rw-r--r--compat/cygwin.c127
-rw-r--r--compat/cygwin.h9
-rw-r--r--compat/mingw.c42
-rw-r--r--compat/win32.h34
-rw-r--r--config.c6
-rwxr-xr-xcontrib/completion/git-completion.bash3
-rwxr-xr-xcontrib/examples/git-remote.perl2
-rw-r--r--contrib/hooks/pre-auto-gc-battery3
-rwxr-xr-xcontrib/stats/packinfo.pl14
-rw-r--r--convert.c3
-rw-r--r--csum-file.c18
-rw-r--r--csum-file.h1
-rw-r--r--date.c26
-rw-r--r--diff.c25
-rw-r--r--editor.c3
-rw-r--r--environment.c5
-rw-r--r--exec_cmd.c4
-rw-r--r--fsck.c3
-rw-r--r--git-compat-util.h1
-rwxr-xr-xgit-rebase--interactive.sh20
-rwxr-xr-xgit-send-email.perl117
-rwxr-xr-xgit-stash.sh22
-rwxr-xr-xgit-svn.perl47
-rw-r--r--git.c3
-rw-r--r--gitweb/gitweb.css4
-rwxr-xr-xgitweb/gitweb.perl214
-rw-r--r--graph.c13
-rw-r--r--grep.c14
-rw-r--r--grep.h1
-rw-r--r--hash-object.c4
-rw-r--r--imap-send.c3
-rw-r--r--index-pack.c11
-rw-r--r--log-tree.c3
-rw-r--r--merge-recursive.c5
-rw-r--r--merge-tree.c3
-rw-r--r--mktag.c3
-rw-r--r--mktree.c6
-rw-r--r--pretty.c3
-rw-r--r--read-cache.c38
-rw-r--r--remote.c15
-rw-r--r--rerere.c4
-rw-r--r--sha1_file.c18
-rwxr-xr-xt/t0001-init.sh32
-rwxr-xr-xt/t1301-shared-repo.sh3
-rwxr-xr-xt/t2203-add-intent.sh36
-rwxr-xr-xt/t3404-rebase-interactive.sh11
-rwxr-xr-xt/t3600-rm.sh25
-rwxr-xr-xt/t4013-diff-various.sh1
-rw-r--r--t/t4013/diff.diff_master_master^_side29
-rwxr-xr-xt/t4018-diff-funcname.sh11
-rwxr-xr-xt/t4128-apply-root.sh52
-rwxr-xr-xt/t7600-merge.sh33
-rwxr-xr-xt/t9001-send-email.sh2
-rwxr-xr-xt/t9128-git-svn-cmd-branch.sh59
-rw-r--r--t/test-lib.sh3
-rw-r--r--walker.c3
-rw-r--r--ws.c3
-rw-r--r--wt-status.c10
-rw-r--r--xdiff-interface.c22
111 files changed, 1448 insertions, 781 deletions
diff --git a/Documentation/RelNotes-1.6.0.3.txt b/Documentation/RelNotes-1.6.0.3.txt
index edd5e45c9..c0f037d6d 100644
--- a/Documentation/RelNotes-1.6.0.3.txt
+++ b/Documentation/RelNotes-1.6.0.3.txt
@@ -16,12 +16,20 @@ Fixes since v1.6.0.2
* "git rebase -i" now honors the pre-rebase hook, just like the
other rebase implementations "git rebase" and "git rebase -m".
+* "git rebase -i" incorrectly aborted when there is no commit to replay.
+
* Behaviour of "git diff --quiet" was inconsistent with "diff --exit-code"
with the output redirected to /dev/null.
* "git diff --no-index" on binary files no longer outputs a bogus
"diff --git" header line.
+* "git diff" hunk header patterns with multiple elements separated by LF
+ were not used correctly.
+
+* "git gc" when ejecting otherwise unreachable objects from packfiles into
+ loose form leaked memory.
+
* Hunk headers in "git diff" default to using extended regular
expressions, fixing some of the internal patterns on non-GNU
platforms.
@@ -29,6 +37,9 @@ Fixes since v1.6.0.2
* New config "diff.*.xfuncname" exposes extended regular expressions
for user specified hunk header patterns.
+* "git index-pack" was recently broken and mishandled objects added by
+ thin-pack completion processing under memory pressure.
+
* "git stash apply sash@{1}" was fixed to error out. Prior versions
would have applied stash@{0} incorrectly.
@@ -42,6 +53,8 @@ Fixes since v1.6.0.2
* "git remote show -v" now displays all URLs of a remote.
+* "git checkout -b branch" was confused when branch already existed.
+
* "git checkout -q" once again suppresses the locally modified file list.
* "git clone -q", "git fetch -q" asks remote side to not send
@@ -53,12 +66,18 @@ Fixes since v1.6.0.2
* Stale temporary files under $GIT_DIR/objects/pack are now cleaned up
automatically by "git prune".
-* "git merge" once agrain removes directories after the last file has
+* "git merge" once again removes directories after the last file has
been removed from it during the merge.
+* "git merge" did not allocate enough memory for the structure itself when
+ enumerating the parents of the resulting commit.
+
* "git blame -C -C" no longer segfaults while trying to pass blame if
it encounters a submodule reference.
+* "git rm" incorrectly claimed that you have local modifications when a
+ path was merely stat-dirty.
+
* "git svn" fixed to display an error message when 'set-tree' failed,
instead of a Perl compile error.
@@ -68,10 +87,16 @@ Fixes since v1.6.0.2
* The "git commit" error message when there are still unmerged
files present was clarified to match "git write-tree".
-* Some segfaults due to uncaught NULL pointers were fixed multiple
+* "git init" was confused when core.bare or core.sharedRepository are set
+ in system or user global configuration file by mistake. When --bare or
+ --shared is given from the command line, these now override such
+ settings made outside the repositories.
+
+* Some segfaults due to uncaught NULL pointers were fixed in multiple
tools such as apply, reset, update-index.
-* Solaris bulds now default to OLD_ICONV=1 to avoid compile warnings.
+* Solaris builds now default to OLD_ICONV=1 to avoid compile warnings;
+ Solaris 8 does not define NEEDS_LIBICONV by default.
* "Git.pm" tests relied on unnecessarily more recent version of Perl.
@@ -80,7 +105,7 @@ Fixes since v1.6.0.2
* "gitweb" triggered undef warnings on missing trees.
* "gitweb" now removes PATH_INFO from its URLs so users don't have
- to manually set the url in the gitweb configuration.
+ to manually set the URL in the gitweb configuration.
* Bash completion removed support for legacy "git-fetch", "git-push"
and "git-pull" as these are no longer installed. Dashless form
@@ -90,6 +115,6 @@ Many other documentation updates.
--
exec >/var/tmp/1
-O=v1.6.0.2-76-gd70b4a8
+O=v1.6.0.2-110-gf07c3c5
echo O=$(git describe maint)
git shortlog --no-merges $O..maint
diff --git a/Documentation/RelNotes-1.6.1.txt b/Documentation/RelNotes-1.6.1.txt
index 906932cfa..afd1150ea 100644
--- a/Documentation/RelNotes-1.6.1.txt
+++ b/Documentation/RelNotes-1.6.1.txt
@@ -16,13 +16,16 @@ on.
* gitk can call out to git-gui to view "git blame" output; git-gui in turn
can run gitk from its blame view.
-(portability)
+* Various git-gui updates including updated translations.
+
+* Various gitweb updates from repo.or.cz installation.
-* ...
+(portability)
-(documentation)
+* A few test scripts used nonportable "grep" that did not work well on
+ some platforms, e.g. Solaris.
-* ...
+* Sample pre-auto-gc script has OS X support.
(performance)
@@ -35,6 +38,14 @@ on.
* Bash completion of refnames in a repository with massive number of
refs has been optimized.
+* Cygwin port uses native stat/lstat implementations when applicable,
+ which leads to improved performance.
+
+* "git push" pays attention to alternate repositories to avoid sending
+ unnecessary objects.
+
+* "git svn" can rebuild an out-of-date rev_map file.
+
(usability, bells and whistles)
* When you mistype a command name, git helpfully suggests what it guesses
@@ -42,6 +53,12 @@ on.
to a non-zero value to accept the suggestion when git can uniquely
guess.
+* "git add -N path..." adds the named paths as an empty blob, so that
+ subsequent "git diff" will show a diff as if they are creation events.
+
+* "git apply" learned --include=paths option, similar to the existing
+ --exclude=paths option.
+
* "git bisect" is careful about a user mistake and suggests testing of
merge base first when good is not a strict ancestor of bad.
@@ -49,11 +66,20 @@ on.
DWIMs to create a corresponding local branch "hack", i.e. acts as if you
said "git checkout --track -b hack origin/hack".
+* "git checkout --ours/--theirs" can be used to check out one side of a
+ conflicting merge during conflict resolution.
+
+* "git checkout -m" can be used to recreate the initial conflicted state
+ during conflict resolution.
+
* "git cherry-pick" can also utilize rerere for conflict resolution.
* "git commit --author=$name" can look up author name from existing
commits.
+* output from "git commit" has been reworded in a more concise and yet
+ more informative way.
+
* "git count-objects" reports the on-disk footprint for packfiles and
their corresponding idx files.
@@ -62,15 +88,22 @@ on.
* "git diff" learned to mimic --suppress-blank-empty from GNU diff via a
configuration option.
-* "git diff" learned to put more sensible hunk headers for Python and
- HTML contents.
+* "git diff" learned to put more sensible hunk headers for Python,
+ HTML and ObjC contents.
* "git diff" learned to vary the a/ vs b/ prefix depending on what are
being compared, controlled by diff.mnemonicprefix configuration.
+* "git diff" learned --dirstat-by-file to count changed files, not number
+ of lines, when summarizing the global picture.
+
+* "git diff" hunk header pattern for ObjC has been added.
+
* "git for-each-ref" learned "refname:short" token that gives an
unambiguously abbreviated refname.
+* "git grep" learned to accept -z similar to GNU grep.
+
* "git help" learned to use GIT_MAN_VIEWER environment variable before
using "man" program.
@@ -103,12 +136,18 @@ on.
* "git submodule sync" subcommands allows you to update the origin URL
recorded in submodule directories from the toplevel .gitmodules file.
+* "git svn branch" can create new branches on the other end.
+
(internal)
* "git hash-object" learned to lie about the path being hashed, so that
correct gitattributes processing can be done while hashing contents
stored in a temporary file.
+* various callers of git-merge-recursive avoid forking it as an external
+ process.
+
+
Fixes since v1.6.0
------------------
@@ -124,6 +163,11 @@ release, unless otherwise noted.
but we dropped support for such a use case long time ago. This has
been resurrected.
+* Giving 3 or more tree-ish to "git diff" is supposed to show the combined
+ diff from second and subsequent trees to the first one. b75271d ("git
+ diff <tree>{3,}": do not reverse order of arguments, 2008-10-10) needs
+ to be cherry-picked to 'maint'.
+
* "git filter-branch" failed to rewrite a tag name with slashes in it.
* "git push --tags --all $there" failed with generic usage message without
@@ -135,6 +179,6 @@ release, unless otherwise noted.
--
exec >/var/tmp/1
-O=v1.6.0.2-295-g34a5d35
+O=v1.6.0.2-553-g58e0fa5
echo O=$(git describe master)
git shortlog --no-merges $O..master ^maint
diff --git a/Documentation/config.txt b/Documentation/config.txt
index bbe38ccaa..da18a5458 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -117,6 +117,15 @@ core.fileMode::
the working copy are ignored; useful on broken filesystems like FAT.
See linkgit:git-update-index[1]. True by default.
+core.ignoreCygwinFSTricks::
+ This option is only used by Cygwin implementation of Git. If false,
+ the Cygwin stat() and lstat() functions are used. This may be useful
+ if your repository consists of a few separate directories joined in
+ one hierarchy using Cygwin mount. If true, Git uses native Win32 API
+ whenever it is possible and falls back to Cygwin functions only to
+ handle symbol links. The native mode is more than twice faster than
+ normal Cygwin l/stat() functions. True by default.
+
core.trustctime::
If false, the ctime differences between the index and the
working copy are ignored; useful when the inode change time
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 7788d4fa4..c62b45cdb 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -137,7 +137,8 @@ endif::git-format-patch[]
--diff-filter=[ACDMRTUXB*]::
Select only files that are Added (`A`), Copied (`C`),
Deleted (`D`), Modified (`M`), Renamed (`R`), have their
- type (mode) changed (`T`), are Unmerged (`U`), are
+ type (i.e. regular file, symlink, submodule, ...) changed (`T`),
+ are Unmerged (`U`), are
Unknown (`X`), or have had their pairing Broken (`B`).
Any combination of the filter characters may be used.
When `*` (All-or-none) is added to the combination, all
diff --git a/Documentation/git-check-attr.txt b/Documentation/git-check-attr.txt
index 2b821f2a1..4b3c2b0b0 100644
--- a/Documentation/git-check-attr.txt
+++ b/Documentation/git-check-attr.txt
@@ -22,6 +22,56 @@ OPTIONS
arguments as path names. If not supplied, only the first argument will
be treated as an attribute.
+OUTPUT
+------
+
+The output is of the form:
+<path> COLON SP <attribute> COLON SP <info> LF
+
+Where <path> is the path of a file being queried, <attribute> is an attribute
+being queried and <info> can be either:
+
+'unspecified';; when the attribute is not defined for the path.
+'unset';; when the attribute is defined to false.
+'set';; when the attribute is defined to true.
+<value>;; when a value has been assigned to the attribute.
+
+EXAMPLES
+--------
+
+In the examples, the following '.gitattributes' file is used:
+---------------
+*.java diff=java -crlf myAttr
+NoMyAttr.java !myAttr
+README caveat=unspecified
+---------------
+
+* Listing a single attribute:
+---------------
+$ git check-attr diff org/example/MyClass.java
+org/example/MyClass.java: diff: java
+---------------
+
+* Listing multiple attributes for a file:
+---------------
+$ git check-attr crlf diff myAttr -- org/example/MyClass.java
+org/example/MyClass.java: crlf: unset
+org/example/MyClass.java: diff: java
+org/example/MyClass.java: myAttr: set
+---------------
+
+* Listing attribute for multiple files:
+---------------
+$ git check-attr myAttr -- org/example/MyClass.java org/example/NoMyAttr.java
+org/example/MyClass.java: myAttr: set
+org/example/NoMyAttr.java: myAttr: unspecified
+---------------
+
+* Not all values are equally unambiguous:
+---------------
+$ git check-attr caveat README
+README: caveat: unspecified
+---------------
SEE ALSO
--------
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 82e154de4..168333a58 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -88,7 +88,7 @@ This would tell us to use "hack" as the local branch when branching
off of "origin/hack" (or "remotes/origin/hack", or even
"refs/remotes/origin/hack"). If the given name has no slash, or the above
guessing results in an empty name, the guessing is aborted. You can
-exlicitly give a name with '-b' in such a case.
+explicitly give a name with '-b' in such a case.
--no-track::
Ignore the branch.autosetupmerge configuration variable.
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index eb05b0f49..41809eeca 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -94,7 +94,8 @@ OPTIONS
-s::
--signoff::
- Add Signed-off-by line at the end of the commit message.
+ Add Signed-off-by line by the commiter at the end of the commit
+ log message.
-n::
--no-verify::
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index fa4d133c1..553da6cbb 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -15,6 +15,7 @@ SYNOPSIS
[-E | --extended-regexp] [-G | --basic-regexp]
[-F | --fixed-strings] [-n]
[-l | --files-with-matches] [-L | --files-without-match]
+ [-z | --null]
[-c | --count] [--all-match]
[-A <post-context>] [-B <pre-context>] [-C <context>]
[-f <file>] [-e] <pattern>
@@ -94,6 +95,11 @@ OPTIONS
For better compatibility with 'git-diff', --name-only is a
synonym for --files-with-matches.
+-z::
+--null::
+ Output \0 instead of the character that normally follows a
+ file name.
+
-c::
--count::
Instead of showing every matched line, show the number of
diff --git a/Documentation/git-prune.txt b/Documentation/git-prune.txt
index 54f1dab38..da6055d4b 100644
--- a/Documentation/git-prune.txt
+++ b/Documentation/git-prune.txt
@@ -8,7 +8,7 @@ git-prune - Prune all unreachable objects from the object database
SYNOPSIS
--------
-'git-prune' [-n] [--expire <expire>] [--] [<head>...]
+'git-prune' [-n] [-v] [--expire <expire>] [--] [<head>...]
DESCRIPTION
-----------
@@ -34,6 +34,9 @@ OPTIONS
Do not remove anything; just report what it would
remove.
+-v::
+ Report all removed objects.
+
\--::
Do not interpret any more arguments as options.
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 45c96435f..6150b1b95 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -9,8 +9,8 @@ git-push - Update remote refs along with associated objects
SYNOPSIS
--------
[verse]
-'git push' [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>]
- [--repo=all] [-f | --force] [-v | --verbose]
+'git push' [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>]
+ [--repo=<repository>] [-f | --force] [-v | --verbose]
[<repository> <refspec>...]
DESCRIPTION
@@ -101,9 +101,23 @@ nor in any Push line of the corresponding remotes file---see below).
This flag disables the check. This can cause the
remote repository to lose commits; use it with care.
---repo=<repo>::
- When no repository is specified the command defaults to
- "origin"; this overrides it.
+--repo=<repository>::
+ This option is only relevant if no <repository> argument is
+ passed in the invocation. In this case, 'git-push' derives the
+ remote name from the current branch: If it tracks a remote
+ branch, then that remote repository is pushed to. Otherwise,
+ the name "origin" is used. For this latter case, this option
+ can be used to override the name "origin". In other words,
+ the difference between these two commands
++
+--------------------------
+git push public #1
+git push --repo=public #2
+--------------------------
++
+is that #1 always pushes to "public" whereas #2 pushes to "public"
+only if the current branch does not track a remote branch. This is
+useful if you write an alias or script around 'git-push'.
--thin::
--no-thin::
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index 3c3e1b0e7..82f505686 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -11,7 +11,6 @@ SYNOPSIS
'git send-email' [options] <file|directory> [... file|directory]
-
DESCRIPTION
-----------
Takes the patches given on the command line and emails them out.
@@ -20,12 +19,16 @@ The header of the email is configurable by command line options. If not
specified on the command line, the user will be prompted with a ReadLine
enabled interface to provide the necessary information.
+
OPTIONS
-------
-The options available are:
+
+Composing
+~~~~~~~~~
--bcc::
- Specify a "Bcc:" value for each email.
+ Specify a "Bcc:" value for each email. Default is the value of
+ 'sendemail.bcc'.
+
The --bcc option must be repeated for each user you want on the bcc list.
@@ -34,22 +37,6 @@ The --bcc option must be repeated for each user you want on the bcc list.
+
The --cc option must be repeated for each user you want on the cc list.
---cc-cmd::
- Specify a command to execute once per patch file which
- should generate patch file specific "Cc:" entries.
- Output of this command must be single email address per line.
- Default is the value of 'sendemail.cccmd' configuration value.
-
---chain-reply-to::
---no-chain-reply-to::
- If this is set, each email will be sent as a reply to the previous
- email sent. If disabled with "--no-chain-reply-to", all emails after
- the first will be sent as replies to the first email sent. When using
- this, it is recommended that the first file given be an overview of the
- entire patch series.
- Default is the value of the 'sendemail.chainreplyto' configuration
- value; if that is unspecified, default to --chain-reply-to.
-
--compose::
Use $GIT_EDITOR, core.editor, $VISUAL, or $EDITOR to edit an
introductory message for the patch series.
@@ -66,22 +53,47 @@ The --cc option must be repeated for each user you want on the cc list.
Only necessary if --compose is also set. If --compose
is not set, this will be prompted for.
---signed-off-by-cc::
---no-signed-off-by-cc::
- If this is set, add emails found in Signed-off-by: or Cc: lines to the
- cc list.
- Default is the value of 'sendemail.signedoffcc' configuration value;
- if that is unspecified, default to --signed-off-by-cc.
+--subject::
+ Specify the initial subject of the email thread.
+ Only necessary if --compose is also set. If --compose
+ is not set, this will be prompted for.
+
+--to::
+ Specify the primary recipient of the emails generated. Generally, this
+ will be the upstream maintainer of the project involved. Default is the
+ value of the 'sendemail.to' configuration value; if that is unspecified,
+ this will be prompted for.
++
+The --to option must be repeated for each user you want on the to list.
---quiet::
- Make git-send-email less verbose. One line per email should be
- all that is output.
---identity::
- A configuration identity. When given, causes values in the
- 'sendemail.<identity>' subsection to take precedence over
- values in the 'sendemail' section. The default identity is
- the value of 'sendemail.identity'.
+Sending
+~~~~~~~
+
+--envelope-sender::
+ Specify the envelope sender used to send the emails.
+ This is useful if your default address is not the address that is
+ subscribed to a list. If you use the sendmail binary, you must have
+ suitable privileges for the -f parameter. Default is the value of
+ the 'sendemail.envelopesender' configuration variable; if that is
+ unspecified, choosing the envelope sender is left to your MTA.
+
+--smtp-encryption::
+ Specify the encryption to use, either 'ssl' or 'tls'. Any other
+ value reverts to plain SMTP. Default is the value of
+ 'sendemail.smtpencryption'.
+
+--smtp-pass::
+ Password for SMTP-AUTH. The argument is optional: If no
+ argument is specified, then the empty string is used as
+ the password. Default is the value of 'sendemail.smtppass',
+ however '--smtp-pass' always overrides this value.
++
+Furthermore, passwords need not be specified in configuration files
+or on the command line. If a username has been specified (with
+'--smtp-user' or a 'sendemail.smtpuser'), but no password has been
+specified (with '--smtp-pass' or 'sendemail.smtppass'), then the
+user is prompted for a password while the input is masked for privacy.
--smtp-server::
If set, specifies the outgoing SMTP server to use (e.g.
@@ -96,61 +108,44 @@ The --cc option must be repeated for each user you want on the cc list.
--smtp-server-port::
Specifies a port different from the default port (SMTP
servers typically listen to smtp port 25 and ssmtp port
- 465).
+ 465). This can be set with 'sendemail.smtpserverport'.
+
+--smtp-ssl::
+ Legacy alias for '--smtp-encryption ssl'.
--smtp-user::
- Username for SMTP-AUTH. In place of this option, the following
- configuration variables can be specified:
-+
---
- * sendemail.smtpuser
- * sendemail.<identity>.smtpuser (see sendemail.identity).
---
-+
-However, --smtp-user always overrides these variables.
-+
-If a username is not specified (with --smtp-user or a
-configuration variable), then authentication is not attempted.
+ Username for SMTP-AUTH. Default is the value of 'sendemail.smtpuser';
+ if a username is not specified (with '--smtp-user' or 'sendemail.smtpuser'),
+ then authentication is not attempted.
---smtp-pass::
- Password for SMTP-AUTH. The argument is optional: If no
- argument is specified, then the empty string is used as
- the password.
-+
-In place of this option, the following configuration variables
-can be specified:
-+
---
- * sendemail.smtppass
- * sendemail.<identity>.smtppass (see sendemail.identity).
---
-+
-However, --smtp-pass always overrides these variables.
-+
-Furthermore, passwords need not be specified in configuration files
-or on the command line. If a username has been specified (with
---smtp-user or a configuration variable), but no password has been
-specified (with --smtp-pass or a configuration variable), then the
-user is prompted for a password while the input is masked for privacy.
---smtp-encryption::
- Specify the encryption to use, either 'ssl' or 'tls'. Any other
- value reverts to plain SMTP. Default is the value of
- 'sendemail.smtpencryption'.
+Automating
+~~~~~~~~~~
---smtp-ssl::
- Legacy alias for '--smtp-encryption=ssl'.
+--cc-cmd::
+ Specify a command to execute once per patch file which
+ should generate patch file specific "Cc:" entries.
+ Output of this command must be single email address per line.
+ Default is the value of 'sendemail.cccmd' configuration value.
---subject::
- Specify the initial subject of the email thread.
- Only necessary if --compose is also set. If --compose
- is not set, this will be prompted for.
+--[no-]chain-reply-to::
+ If this is set, each email will be sent as a reply to the previous
+ email sent. If disabled with "--no-chain-reply-to", all emails after
+ the first will be sent as replies to the first email sent. When using
+ this, it is recommended that the first file given be an overview of the
+ entire patch series. Default is the value of the 'sendemail.chainreplyto'
+ configuration value; if that is unspecified, default to --chain-reply-to.
+
+--identity::
+ A configuration identity. When given, causes values in the
+ 'sendemail.<identity>' subsection to take precedence over
+ values in the 'sendemail' section. The default identity is
+ the value of 'sendemail.identity'.
---suppress-from::
---no-suppress-from::
- If this is set, do not add the From: address to the cc: list.
- Default is the value of 'sendemail.suppressfrom' configuration value;
- if that is unspecified, default to --no-suppress-from.
+--[no-]signed-off-by-cc::
+ If this is set, add emails found in Signed-off-by: or Cc: lines to the
+ cc list. Default is the value of 'sendemail.signedoffbycc' configuration
+ value; if that is unspecified, default to --signed-off-by-cc.
--suppress-cc::
Specify an additional category of recipients to suppress the
@@ -163,44 +158,43 @@ user is prompted for a password while the input is masked for privacy.
if that is unspecified, default to 'self' if --suppress-from is
specified, as well as 'sob' if --no-signed-off-cc is specified.
---thread::
---no-thread::
+--[no-]suppress-from::
+ If this is set, do not add the From: address to the cc: list.
+ Default is the value of 'sendemail.suppressfrom' configuration
+ value; if that is unspecified, default to --no-suppress-from.
+
+--[no-]thread::
If this is set, the In-Reply-To header will be set on each email sent.
If disabled with "--no-thread", no emails will have the In-Reply-To
- header set.
- Default is the value of the 'sendemail.thread' configuration value;
- if that is unspecified, default to --thread.
+ header set. Default is the value of the 'sendemail.thread' configuration
+ value; if that is unspecified, default to --thread.
+
+
+Administering
+~~~~~~~~~~~~~
--dry-run::
Do everything except actually send the emails.
---envelope-sender::
- Specify the envelope sender used to send the emails.
- This is useful if your default address is not the address that is
- subscribed to a list. If you use the sendmail binary, you must have
- suitable privileges for the -f parameter.
- Default is the value of the 'sendemail.envelopesender' configuration
- variable; if that is unspecified, choosing the envelope sender is left
- to your MTA.
+--quiet::
+ Make git-send-email less verbose. One line per email should be
+ all that is output.
---to::
- Specify the primary recipient of the emails generated.
- Generally, this will be the upstream maintainer of the
- project involved.
- Default is the value of the 'sendemail.to' configuration value;
- if that is unspecified, this will be prompted for.
+--[no-]validate::
+ Perform sanity checks on patches.
+ Currently, validation means the following:
+
-The --to option must be repeated for each user you want on the to list.
+--
+ * Warn of patches that contain lines longer than 998 characters; this
+ is due to SMTP limits as described by http://www.ietf.org/rfc/rfc2821.txt.
+--
++
+Default is the value of 'sendemail.validate'; if this is not set,
+default to '--validate'.
CONFIGURATION
-------------
-sendemail.identity::
- The default configuration identity. When specified,
- 'sendemail.<identity>.<item>' will have higher precedence than
- 'sendemail.<item>'. This is useful to declare multiple SMTP
- identities and to hoist sensitive authentication information
- out of the repository and into the global configuration file.
sendemail.aliasesfile::
To avoid typing long email addresses, point this to one or more
@@ -210,38 +204,6 @@ sendemail.aliasfiletype::
Format of the file(s) specified in sendemail.aliasesfile. Must be
one of 'mutt', 'mailrc', 'pine', or 'gnus'.
-sendemail.to::
- Email address (or alias) to always send to.
-
-sendemail.cccmd::
- Command to execute to generate per patch file specific "Cc:"s.
-
-sendemail.bcc::
- Email address (or alias) to always bcc.
-
-sendemail.chainreplyto::
- Boolean value specifying the default to the '--chain_reply_to'
- parameter.
-
-sendemail.smtpserver::
- Default SMTP server to use.
-
-sendemail.smtpserverport::
- Default SMTP server port to use.
-
-sendemail.smtpuser::
- Default SMTP-AUTH username.
-
-sendemail.smtppass::
- Default SMTP-AUTH password.
-
-sendemail.smtpencryption::
- Default encryption method. Use 'ssl' for SSL (and specify an
- appropriate port), or 'tls' for TLS. Takes precedence over
- 'smtpssl' if both are specified.
-
-sendemail.smtpssl::
- Legacy boolean that sets 'smtpencryption=ssl' if enabled.
Author
------
@@ -250,10 +212,12 @@ Written by Ryan Anderson <ryan@michonline.com>
git-send-email is originally based upon
send_lots_of_email.pl by Greg Kroah-Hartman.
+
Documentation
--------------
Documentation by Ryan Anderson
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index 82d03b4ce..84c8f3cde 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -149,6 +149,22 @@ and have no uncommitted changes.
is very strongly discouraged.
--
+'branch'::
+ Create a branch in the SVN repository.
+
+-m;;
+--message;;
+ Allows to specify the commit message.
+
+-t;;
+--tag;;
+ Create a tag by using the tags_subdir instead of the branches_subdir
+ specified during git svn init.
+
+'tag'::
+ Create a tag in the SVN repository. This is a shorthand for
+ 'branch -t'.
+
'log'::
This should make it easy to look up svn log messages when svn
users refer to -r/--revision numbers.
@@ -372,7 +388,8 @@ Passed directly to 'git-rebase' when using 'dcommit' if a
-n::
--dry-run::
-This can be used with the 'dcommit' and 'rebase' commands.
+This can be used with the 'dcommit', 'rebase', 'branch' and 'tag'
+commands.
For 'dcommit', print out the series of git arguments that would show
which diffs would be committed to SVN.
@@ -381,6 +398,9 @@ For 'rebase', display the local branch associated with the upstream svn
repository associated with the current branch and the URL of svn
repository that will be fetched from.
+For 'branch' and 'tag', display the urls that will be used for copying when
+creating the branch or tag.
+
--
ADVANCED OPTIONS
@@ -498,6 +518,8 @@ Tracking and contributing to an entire Subversion-managed project
git svn clone http://svn.example.com/project -T trunk -b branches -t tags
# View all branches and tags you have cloned:
git branch -r
+# Create a new branch in SVN
+ git svn branch waldo
# Reset your master to trunk (or any other branch, replacing 'trunk'
# with the appropriate name):
git reset --hard remotes/trunk
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 2ae771f2f..26945593c 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -315,6 +315,8 @@ patterns are available:
- `java` suitable for source code in the Java language.
+- `objc` suitable for source code in the Objective-C language.
+
- `pascal` suitable for source code in the Pascal/Delphi language.
- `php` suitable for source code in the PHP language.
diff --git a/Documentation/gittutorial-2.txt b/Documentation/gittutorial-2.txt
index 660904686..bab0f34b4 100644
--- a/Documentation/gittutorial-2.txt
+++ b/Documentation/gittutorial-2.txt
@@ -32,22 +32,27 @@ Initialized empty Git repository in .git/
$ echo 'hello world' > file.txt
$ git add .
$ git commit -a -m "initial commit"
-Created initial commit 54196cc2703dc165cbd373a65a4dcf22d50ae7f7
+[master (root-commit)] created 54196cc: "initial commit"
+ 1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 file.txt
$ echo 'hello world!' >file.txt
$ git commit -a -m "add emphasis"
-Created commit c4d59f390b9cfd4318117afde11d601c1085f241
+[master] created c4d59f3: "add emphasis"
+ 1 files changed, 1 insertions(+), 1 deletions(-)
------------------------------------------------
-What are the 40 digits of hex that git responded to the commit with?
+What are the 7 digits of hex that git responded to the commit with?
We saw in part one of the tutorial that commits have names like this.
It turns out that every object in the git history is stored under
-such a 40-digit hex name. That name is the SHA1 hash of the object's
+a 40-digit hex name. That name is the SHA1 hash of the object's
contents; among other things, this ensures that git will never store
the same data twice (since identical data is given an identical SHA1
name), and that the contents of a git object will never change (since
-that would change the object's name as well).
+that would change the object's name as well). The 7 char hex strings
+here are simply the abbreviation of such 40 character long strings.
+Abbreviations can be used everywhere where the 40 character strings
+can be used, so long as they are unambiguous.
It is expected that the content of the commit object you created while
following the example above generates a different SHA1 hash than
diff --git a/Documentation/howto/rebase-and-edit.txt b/Documentation/howto/rebase-and-edit.txt
deleted file mode 100644
index 554909fe0..000000000
--- a/Documentation/howto/rebase-and-edit.txt
+++ /dev/null
@@ -1,79 +0,0 @@
-Date: Sat, 13 Aug 2005 22:16:02 -0700 (PDT)
-From: Linus Torvalds <torvalds@osdl.org>
-To: Steve French <smfrench@austin.rr.com>
-cc: git@vger.kernel.org
-Subject: Re: sending changesets from the middle of a git tree
-Abstract: In this article, Linus demonstrates how a broken commit
- in a sequence of commits can be removed by rewinding the head and
- reapplying selected changes.
-
-On Sat, 13 Aug 2005, Linus Torvalds wrote:
-
-> That's correct. Same things apply: you can move a patch over, and create a
-> new one with a modified comment, but basically the _old_ commit will be
-> immutable.
-
-Let me clarify.
-
-You can entirely _drop_ old branches, so commits may be immutable, but
-nothing forces you to keep them. Of course, when you drop a commit, you'll
-always end up dropping all the commits that depended on it, and if you
-actually got somebody else to pull that commit you can't drop it from
-_their_ repository, but undoing things is not impossible.
-
-For example, let's say that you've made a mess of things: you've committed
-three commits "old->a->b->c", and you notice that "a" was broken, but you
-want to save "b" and "c". What you can do is
-
- # Create a branch "broken" that is the current code
- # for reference
- git branch broken
-
- # Reset the main branch to three parents back: this
- # effectively undoes the three top commits
- git reset HEAD^^^
- git checkout -f
-
- # Check the result visually to make sure you know what's
- # going on
- gitk --all
-
- # Re-apply the two top ones from "broken"
- #
- # First "parent of broken" (aka b):
- git-diff-tree -p broken^ | git-apply --index
- git commit --reedit=broken^
-
- # Then "top of broken" (aka c):
- git-diff-tree -p broken | git-apply --index
- git commit --reedit=broken
-
-and you've now re-applied (and possibly edited the comments) the two
-commits b/c, and commit "a" is basically gone (it still exists in the
-"broken" branch, of course).
-
-Finally, check out the end result again:
-
- # Look at the new commit history
- gitk --all
-
-to see that everything looks sensible.
-
-And then, you can just remove the broken branch if you decide you really
-don't want it:
-
- # remove 'broken' branch
- git branch -d broken
-
- # Prune old objects if you're really really sure
- git prune
-
-And yeah, I'm sure there are other ways of doing this. And as usual, the
-above is totally untested, and I just wrote it down in this email, so if
-I've done something wrong, you'll have to figure it out on your own ;)
-
- Linus
--
-To unsubscribe from this list: send the line "unsubscribe git" in
-the body of a message to majordomo@vger.kernel.org
-More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/Makefile b/Makefile
index 15ca6599a..308dc70b5 100644
--- a/Makefile
+++ b/Makefile
@@ -346,6 +346,7 @@ LIB_H += cache.h
LIB_H += cache-tree.h
LIB_H += commit.h
LIB_H += compat/mingw.h
+LIB_H += compat/cygwin.h
LIB_H += csum-file.h
LIB_H += decorate.h
LIB_H += delta.h
@@ -650,7 +651,6 @@ ifeq ($(uname_S),SunOS)
NO_MKDTEMP = YesPlease
OLD_ICONV = UnfortunatelyYes
ifeq ($(uname_R),5.8)
- NEEDS_LIBICONV = YesPlease
NO_UNSETENV = YesPlease
NO_SETENV = YesPlease
NO_C99_FORMAT = YesPlease
@@ -749,6 +749,9 @@ ifeq ($(uname_S),HP-UX)
NO_SYS_SELECT_H = YesPlease
SNPRINTF_RETURNS_BOGUS = YesPlease
endif
+ifneq (,$(findstring CYGWIN,$(uname_S)))
+ COMPAT_OBJS += compat/cygwin.o
+endif
ifneq (,$(findstring MINGW,$(uname_S)))
NO_MMAP = YesPlease
NO_PREAD = YesPlease
diff --git a/archive-tar.c b/archive-tar.c
index 13029619e..ba890ebde 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -124,11 +124,10 @@ static int write_tar_entry(struct archiver_args *args,
unsigned int mode, void *buffer, unsigned long size)
{
struct ustar_header header;
- struct strbuf ext_header;
+ struct strbuf ext_header = STRBUF_INIT;
int err = 0;
memset(&header, 0, sizeof(header));
- strbuf_init(&ext_header, 0);
if (!sha1) {
*header.typeflag = TYPEFLAG_GLOBAL_HEADER;
@@ -211,10 +210,9 @@ static int write_tar_entry(struct archiver_args *args,
static int write_global_extended_header(struct archiver_args *args)
{
const unsigned char *sha1 = args->commit_sha1;
- struct strbuf ext_header;
+ struct strbuf ext_header = STRBUF_INIT;
int err;
- strbuf_init(&ext_header, 0);
strbuf_append_ext_header(&ext_header, "comment", sha1_to_hex(sha1), 40);
err = write_tar_entry(args, NULL, NULL, 0, 0, ext_header.buf,
ext_header.len);
diff --git a/archive.c b/archive.c
index 44ab00803..849eed553 100644
--- a/archive.c
+++ b/archive.c
@@ -29,11 +29,10 @@ static void format_subst(const struct commit *commit,
struct strbuf *buf)
{
char *to_free = NULL;
- struct strbuf fmt;
+ struct strbuf fmt = STRBUF_INIT;
if (src == buf->buf)
to_free = strbuf_detach(buf, NULL);
- strbuf_init(&fmt, 0);
for (;;) {
const char *b, *c;
@@ -65,10 +64,9 @@ static void *sha1_file_to_archive(const char *path, const unsigned char *sha1,
buffer = read_sha1_file(sha1, type, sizep);
if (buffer && S_ISREG(mode)) {
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
size_t size = 0;
- strbuf_init(&buf, 0);
strbuf_attach(&buf, buffer, *sizep, *sizep + 1);
convert_to_working_tree(path, buf.buf, buf.len, &buf);
if (commit)
diff --git a/builtin-add.c b/builtin-add.c
index 7c874e311..ea4e77169 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -166,7 +166,7 @@ static const char ignore_error[] =
"The following paths are ignored by one of your .gitignore files:\n";
static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
-static int ignore_add_errors, addremove;
+static int ignore_add_errors, addremove, intent_to_add;
static struct option builtin_add_options[] = {
OPT__DRY_RUN(&show_only),
@@ -176,6 +176,7 @@ static struct option builtin_add_options[] = {
OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
OPT_BOOLEAN('f', "force", &ignored_too, "allow adding otherwise ignored files"),
OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"),
+ OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact that the path will be added later"),
OPT_BOOLEAN('A', "all", &addremove, "add all, noticing removal of tracked files"),
OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, "just skip files which cannot be added because of errors"),
@@ -246,6 +247,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
(show_only ? ADD_CACHE_PRETEND : 0) |
+ (intent_to_add ? ADD_CACHE_INTENT : 0) |
(ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
(!(addremove || take_worktree_changes)
? ADD_CACHE_IGNORE_REMOVAL : 0));
diff --git a/builtin-apply.c b/builtin-apply.c
index 342f2fe5e..cfd8fceb9 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -321,13 +321,12 @@ static char *find_name(const char *line, char *def, int p_value, int terminate)
const char *start = line;
if (*line == '"') {
- struct strbuf name;
+ struct strbuf name = STRBUF_INIT;
/*
* Proposed "new-style" GNU patch/diff format; see
* http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
*/
- strbuf_init(&name, 0);
if (!unquote_c_style(&name, line, NULL)) {
char *cp;
@@ -675,11 +674,8 @@ static char *git_header_name(char *line, int llen)
if (*line == '"') {
const char *cp;
- struct strbuf first;
- struct strbuf sp;
-
- strbuf_init(&first, 0);
- strbuf_init(&sp, 0);
+ struct strbuf first = STRBUF_INIT;
+ struct strbuf sp = STRBUF_INIT;
if (unquote_c_style(&first, line, &second))
goto free_and_fail1;
@@ -741,10 +737,9 @@ static char *git_header_name(char *line, int llen)
*/
for (second = name; second < line + llen; second++) {
if (*second == '"') {
- struct strbuf sp;
+ struct strbuf sp = STRBUF_INIT;
const char *np;
- strbuf_init(&sp, 0);
if (unquote_c_style(&sp, second, NULL))
goto free_and_fail2;
@@ -810,6 +805,13 @@ static int parse_git_header(char *line, int len, unsigned int size, struct patch
* the default name from the header.
*/
patch->def_name = git_header_name(line, len);
+ if (patch->def_name && root) {
+ char *s = xmalloc(root_len + strlen(patch->def_name) + 1);
+ strcpy(s, root);
+ strcpy(s + root_len, patch->def_name);
+ free(patch->def_name);
+ patch->def_name = s;
+ }
line += len;
size -= len;
@@ -1508,11 +1510,10 @@ static const char minuses[]=
static void show_stats(struct patch *patch)
{
- struct strbuf qname;
+ struct strbuf qname = STRBUF_INIT;
char *cp = patch->new_name ? patch->new_name : patch->old_name;
int max, add, del;
- strbuf_init(&qname, 0);
quote_c_style(cp, &qname, NULL, 0);
/*
@@ -1697,7 +1698,7 @@ static int match_fragment(struct image *img,
fixlen = ws_fix_copy(buf, orig, oldlen, ws_rule, NULL);
/* Try fixing the line in the target */
- if (sizeof(tgtfixbuf) < tgtlen)
+ if (sizeof(tgtfixbuf) > tgtlen)
tgtfix = tgtfixbuf;
else
tgtfix = xmalloc(tgtlen);
@@ -2292,14 +2293,12 @@ static void add_to_fn_table(struct patch *patch)
static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
{
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
struct image image;
size_t len;
char *img;
struct patch *tpatch;
- strbuf_init(&buf, 0);
-
if (!(patch->is_copy || patch->is_rename) &&
((tpatch = in_fn_table(patch->old_name)) != NULL)) {
if (tpatch == (struct patch *) -1) {
@@ -2779,7 +2778,7 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size)
{
int fd;
- struct strbuf nbuf;
+ struct strbuf nbuf = STRBUF_INIT;
if (S_ISGITLINK(mode)) {
struct stat st;
@@ -2798,7 +2797,6 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf,
if (fd < 0)
return -1;
- strbuf_init(&nbuf, 0);
if (convert_to_working_tree(path, buf, size, &nbuf)) {
size = nbuf.len;
buf = nbuf.buf;
@@ -3060,13 +3058,12 @@ static void prefix_patches(struct patch *p)
static int apply_patch(int fd, const char *filename, int options)
{
size_t offset;
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
struct patch *list = NULL, **listp = &list;
int skipped_patch = 0;
/* FIXME - memory leak when using multiple patch files as inputs */
memset(&fn_table, 0, sizeof(struct string_list));
- strbuf_init(&buf, 0);
patch_input_file = filename;
read_patch_file(&buf, fd);
offset = 0;
diff --git a/builtin-blame.c b/builtin-blame.c
index df537593d..48cc0c175 100644
--- a/builtin-blame.c
+++ b/builtin-blame.c
@@ -2062,7 +2062,7 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
struct commit *commit;
struct origin *origin;
unsigned char head_sha1[20];
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
const char *ident;
time_t now;
int size, len;
@@ -2082,7 +2082,6 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
origin = make_origin(commit, path);
- strbuf_init(&buf, 0);
if (!contents_from || strcmp("-", contents_from)) {
struct stat st;
const char *read_from;
diff --git a/builtin-branch.c b/builtin-branch.c
index b1a2ad7a6..8d634ff57 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -334,11 +334,10 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
}
if (verbose) {
- struct strbuf subject;
+ struct strbuf subject = STRBUF_INIT;
const char *sub = " **** invalid ref ****";
char stat[128];
- strbuf_init(&subject, 0);
stat[0] = '\0';
commit = item->commit;
diff --git a/builtin-cat-file.c b/builtin-cat-file.c
index 3fba6b9e7..30d00a666 100644
--- a/builtin-cat-file.c
+++ b/builtin-cat-file.c
@@ -189,9 +189,8 @@ static int batch_one_object(const char *obj_name, int print_contents)
static int batch_objects(int print_contents)
{
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
- strbuf_init(&buf, 0);
while (strbuf_getline(&buf, stdin, '\n') != EOF) {
int error = batch_one_object(buf.buf, print_contents);
if (error)
diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c
index 55b7aafe0..4ba27024c 100644
--- a/builtin-checkout-index.c
+++ b/builtin-checkout-index.c
@@ -268,13 +268,11 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
}
if (read_from_stdin) {
- struct strbuf buf, nbuf;
+ struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;
if (all)
die("git checkout-index: don't mix '--all' and '--stdin'");
- strbuf_init(&buf, 0);
- strbuf_init(&nbuf, 0);
while (strbuf_getline(&buf, stdin, line_termination) != EOF) {
const char *p;
if (line_termination && buf.buf[0] == '"') {
diff --git a/builtin-checkout.c b/builtin-checkout.c
index 3762f71aa..57b94d282 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -310,8 +310,7 @@ static void show_local_changes(struct object *head)
static void describe_detached_head(char *msg, struct commit *commit)
{
- struct strbuf sb;
- strbuf_init(&sb, 0);
+ struct strbuf sb = STRBUF_INIT;
parse_commit(commit);
pretty_print_commit(CMIT_FMT_ONELINE, commit, &sb, 0, NULL, NULL, 0, 0);
fprintf(stderr, "%s %s... %s\n", msg,
@@ -360,8 +359,7 @@ struct branch_info {
static void setup_branch_path(struct branch_info *branch)
{
- struct strbuf buf;
- strbuf_init(&buf, 0);
+ struct strbuf buf = STRBUF_INIT;
strbuf_addstr(&buf, "refs/heads/");
strbuf_addstr(&buf, branch->name);
branch->path = strbuf_detach(&buf, NULL);
@@ -484,7 +482,7 @@ static void update_refs_for_switch(struct checkout_opts *opts,
struct branch_info *old,
struct branch_info *new)
{
- struct strbuf msg;
+ struct strbuf msg = STRBUF_INIT;
const char *old_desc;
if (opts->new_branch) {
create_branch(old->name, opts->new_branch, new->name, 0,
@@ -493,7 +491,6 @@ static void update_refs_for_switch(struct checkout_opts *opts,
setup_branch_path(new);
}
- strbuf_init(&msg, 0);
old_desc = old->name;
if (!old_desc)
old_desc = sha1_to_hex(old->commit->object.sha1);
@@ -638,9 +635,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
}
- if (!opts.new_branch && (opts.track != git_branch_track))
- die("git checkout: --track and --no-track require -b");
-
if (opts.force && opts.merge)
die("git checkout: -f and -m are incompatible");
@@ -738,8 +732,7 @@ no_reference:
}
if (opts.new_branch) {
- struct strbuf buf;
- strbuf_init(&buf, 0);
+ struct strbuf buf = STRBUF_INIT;
strbuf_addstr(&buf, "refs/heads/");
strbuf_addstr(&buf, opts.new_branch);
if (!get_sha1(buf.buf, rev))
diff --git a/builtin-clean.c b/builtin-clean.c
index 48bf29f40..f78c2fb10 100644
--- a/builtin-clean.c
+++ b/builtin-clean.c
@@ -31,11 +31,11 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
int i;
int show_only = 0, remove_directories = 0, quiet = 0, ignored = 0;
int ignored_only = 0, baselen = 0, config_set = 0, errors = 0;
- struct strbuf directory;
+ struct strbuf directory = STRBUF_INIT;
struct dir_struct dir;
const char *path, *base;
static const char **pathspec;
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
const char *qname;
char *seen = NULL;
struct option options[] = {
@@ -58,7 +58,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, options, builtin_clean_usage, 0);
- strbuf_init(&buf, 0);
memset(&dir, 0, sizeof(dir));
if (ignored_only)
dir.show_ignored = 1;
@@ -88,7 +87,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
if (baselen)
path = base = xmemdupz(*pathspec, baselen);
read_directory(&dir, path, base, baselen, pathspec);
- strbuf_init(&directory, 0);
if (pathspec)
seen = xmalloc(argc > 0 ? argc : 1);
diff --git a/builtin-clone.c b/builtin-clone.c
index 49d2eb9c2..1ddc14b9c 100644
--- a/builtin-clone.c
+++ b/builtin-clone.c
@@ -264,10 +264,9 @@ pid_t junk_pid;
static void remove_junk(void)
{
- struct strbuf sb;
+ struct strbuf sb = STRBUF_INIT;
if (getpid() != junk_pid)
return;
- strbuf_init(&sb, 0);
if (junk_git_dir) {
strbuf_addstr(&sb, junk_git_dir);
remove_dir_recursively(&sb, 0);
@@ -354,7 +353,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
char *path, *dir;
const struct ref *refs, *head_points_at, *remote_head, *mapped_refs;
char branch_top[256], key[256], value[256];
- struct strbuf reflog_msg;
+ struct strbuf reflog_msg = STRBUF_INIT;
struct transport *transport = NULL;
char *src_ref_prefix = "refs/heads/";
@@ -404,7 +403,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (!stat(dir, &buf))
die("destination directory '%s' already exists.", dir);
- strbuf_init(&reflog_msg, 0);
strbuf_addf(&reflog_msg, "clone: from %s", repo);
if (option_bare)
@@ -526,7 +524,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
create_symref("HEAD", head_points_at->name, NULL);
if (!option_bare) {
- struct strbuf head_ref;
+ struct strbuf head_ref = STRBUF_INIT;
const char *head = head_points_at->name;
if (!prefixcmp(head, "refs/heads/"))
@@ -539,7 +537,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
head_points_at->old_sha1,
NULL, 0, DIE_ON_ERR);
- strbuf_init(&head_ref, 0);
strbuf_addstr(&head_ref, branch_top);
strbuf_addstr(&head_ref, "HEAD");
diff --git a/builtin-commit.c b/builtin-commit.c
index b92025752..2c33af276 100644
--- a/builtin-commit.c
+++ b/builtin-commit.c
@@ -448,7 +448,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
{
struct stat statbuf;
int commitable, saved_color_setting;
- struct strbuf sb;
+ struct strbuf sb = STRBUF_INIT;
char *buffer;
FILE *fp;
const char *hook_arg1 = NULL;
@@ -458,7 +458,6 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
if (!no_verify && run_hook(index_file, "pre-commit", NULL))
return 0;
- strbuf_init(&sb, 0);
if (message.len) {
strbuf_addbuf(&sb, &message);
hook_arg1 = "message";
@@ -511,10 +510,9 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
stripspace(&sb, 0);
if (signoff) {
- struct strbuf sob;
+ struct strbuf sob = STRBUF_INIT;
int i;
- strbuf_init(&sob, 0);
strbuf_addstr(&sob, sign_off_header);
strbuf_addstr(&sob, fmt_name(getenv("GIT_COMMITTER_NAME"),
getenv("GIT_COMMITTER_EMAIL")));
@@ -672,7 +670,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
*/
static int message_is_empty(struct strbuf *sb)
{
- struct strbuf tmpl;
+ struct strbuf tmpl = STRBUF_INIT;
const char *nl;
int eol, i, start = 0;
@@ -680,7 +678,6 @@ static int message_is_empty(struct strbuf *sb)
return 0;
/* See if the template is just a prefix of the message. */
- strbuf_init(&tmpl, 0);
if (template_file && strbuf_read_file(&tmpl, template_file, 0) > 0) {
stripspace(&tmpl, cleanup_mode == CLEANUP_ALL);
if (start + tmpl.len <= sb->len &&
@@ -882,6 +879,9 @@ static void print_summary(const char *prefix, const unsigned char *sha1)
{
struct rev_info rev;
struct commit *commit;
+ static const char *format = "format:%h: \"%s\"";
+ unsigned char junk_sha1[20];
+ const char *head = resolve_ref("HEAD", junk_sha1, 0, NULL);
commit = lookup_commit(sha1);
if (!commit)
@@ -899,18 +899,24 @@ static void print_summary(const char *prefix, const unsigned char *sha1)
rev.verbose_header = 1;
rev.show_root_diff = 1;
- get_commit_format("format:%h: %s", &rev);
+ get_commit_format(format, &rev);
rev.always_show_header = 0;
rev.diffopt.detect_rename = 1;
rev.diffopt.rename_limit = 100;
rev.diffopt.break_opt = 0;
diff_setup_done(&rev.diffopt);
- printf("Created %scommit ", initial_commit ? "initial " : "");
+ printf("[%s%s]: created ",
+ !prefixcmp(head, "refs/heads/") ?
+ head + 11 :
+ !strcmp(head, "HEAD") ?
+ "detached HEAD" :
+ head,
+ initial_commit ? " (root-commit)" : "");
if (!log_tree_commit(&rev, commit)) {
struct strbuf buf = STRBUF_INIT;
- format_commit_message(commit, "%h: %s", &buf, DATE_NORMAL);
+ format_commit_message(commit, format + 7, &buf, DATE_NORMAL);
printf("%s\n", buf.buf);
strbuf_release(&buf);
}
@@ -931,7 +937,7 @@ static const char commit_utf8_warn[] =
int cmd_commit(int argc, const char **argv, const char *prefix)
{
- struct strbuf sb;
+ struct strbuf sb = STRBUF_INIT;
const char *index_file, *reflog_msg;
char *nl, *p;
unsigned char commit_sha1[20];
@@ -966,12 +972,11 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
for (c = commit->parents; c; c = c->next)
pptr = &commit_list_insert(c->item, pptr)->next;
} else if (in_merge) {
- struct strbuf m;
+ struct strbuf m = STRBUF_INIT;
FILE *fp;
reflog_msg = "commit (merge)";
pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next;
- strbuf_init(&m, 0);
fp = fopen(git_path("MERGE_HEAD"), "r");
if (fp == NULL)
die("could not open %s for reading: %s",
@@ -991,7 +996,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
parents = reduce_heads(parents);
/* Finally, get the commit message */
- strbuf_init(&sb, 0);
if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) {
rollback_index_files();
die("could not read commit message");
diff --git a/builtin-diff.c b/builtin-diff.c
index 35da366f4..9c8c29573 100644
--- a/builtin-diff.c
+++ b/builtin-diff.c
@@ -177,10 +177,8 @@ static int builtin_diff_combined(struct rev_info *revs,
if (!revs->dense_combined_merges && !revs->combine_merges)
revs->dense_combined_merges = revs->combine_merges = 1;
parent = xmalloc(ents * sizeof(*parent));
- /* Again, the revs are all reverse */
for (i = 0; i < ents; i++)
- hashcpy((unsigned char *)(parent + i),
- ent[ents - 1 - i].item->sha1);
+ hashcpy((unsigned char *)(parent + i), ent[i].item->sha1);
diff_tree_combined(parent[0], parent + 1, ents - 1,
revs->dense_combined_merges, revs);
return 0;
diff --git a/builtin-fetch--tool.c b/builtin-fetch--tool.c
index 7460ab7fc..469b07e24 100644
--- a/builtin-fetch--tool.c
+++ b/builtin-fetch--tool.c
@@ -5,8 +5,7 @@
static char *get_stdin(void)
{
- struct strbuf buf;
- strbuf_init(&buf, 0);
+ struct strbuf buf = STRBUF_INIT;
if (strbuf_read(&buf, 0, 1024) < 0) {
die("error reading standard input: %s", strerror(errno));
}
diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c
index df02ba7af..df18f4070 100644
--- a/builtin-fmt-merge-msg.c
+++ b/builtin-fmt-merge-msg.c
@@ -5,8 +5,10 @@
#include "revision.h"
#include "tag.h"
-static const char *fmt_merge_msg_usage =
- "git fmt-merge-msg [--log] [--no-log] [--file <file>]";
+static const char * const fmt_merge_msg_usage[] = {
+ "git fmt-merge-msg [--log|--no-log] [--file <file>]",
+ NULL
+};
static int merge_summary;
@@ -347,46 +349,35 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
{
+ const char *inpath = NULL;
+ struct option options[] = {
+ OPT_BOOLEAN(0, "log", &merge_summary, "populate log with the shortlog"),
+ OPT_BOOLEAN(0, "summary", &merge_summary, "alias for --log"),
+ OPT_STRING('F', "file", &inpath, "file", "file to read from"),
+ OPT_END()
+ };
+
FILE *in = stdin;
- struct strbuf input, output;
+ struct strbuf input = STRBUF_INIT, output = STRBUF_INIT;
int ret;
git_config(fmt_merge_msg_config, NULL);
-
- while (argc > 1) {
- if (!strcmp(argv[1], "--log") || !strcmp(argv[1], "--summary"))
- merge_summary = 1;
- else if (!strcmp(argv[1], "--no-log")
- || !strcmp(argv[1], "--no-summary"))
- merge_summary = 0;
- else if (!strcmp(argv[1], "-F") || !strcmp(argv[1], "--file")) {
- if (argc < 3)
- die ("Which file?");
- if (!strcmp(argv[2], "-"))
- in = stdin;
- else {
- fclose(in);
- in = fopen(argv[2], "r");
- if (!in)
- die("cannot open %s", argv[2]);
- }
- argc--; argv++;
- } else
- break;
- argc--; argv++;
+ argc = parse_options(argc, argv, options, fmt_merge_msg_usage, 0);
+ if (argc > 0)
+ usage_with_options(fmt_merge_msg_usage, options);
+
+ if (inpath && strcmp(inpath, "-")) {
+ in = fopen(inpath, "r");
+ if (!in)
+ die("cannot open %s", inpath);
}
- if (argc > 1)
- usage(fmt_merge_msg_usage);
-
- strbuf_init(&input, 0);
if (strbuf_read(&input, fileno(in), 0) < 0)
die("could not read input file %s", strerror(errno));
- strbuf_init(&output, 0);
ret = fmt_merge_msg(merge_summary, &input, &output);
if (ret)
return ret;
- printf("%s", output.buf);
+ write_in_full(STDOUT_FILENO, output.buf, output.len);
return 0;
}
diff --git a/builtin-grep.c b/builtin-grep.c
index 3a51662a3..624f86e28 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -295,6 +295,9 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
push_arg("-l");
if (opt->unmatch_name_only)
push_arg("-L");
+ if (opt->null_following_name)
+ /* in GNU grep git's "-z" translates to "-Z" */
+ push_arg("-Z");
if (opt->count)
push_arg("-c");
if (opt->post_context || opt->pre_context) {
@@ -599,6 +602,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
opt.unmatch_name_only = 1;
continue;
}
+ if (!strcmp("-z", arg) ||
+ !strcmp("--null", arg)) {
+ opt.null_following_name = 1;
+ continue;
+ }
if (!strcmp("-c", arg) ||
!strcmp("--count", arg)) {
opt.count = 1;
diff --git a/builtin-help.c b/builtin-help.c
index 64207cbfe..f076efa92 100644
--- a/builtin-help.c
+++ b/builtin-help.c
@@ -322,11 +322,9 @@ static const char *cmd_to_page(const char *git_cmd)
static void setup_man_path(void)
{
- struct strbuf new_path;
+ struct strbuf new_path = STRBUF_INIT;
const char *old_path = getenv("MANPATH");
- strbuf_init(&new_path, 0);
-
/* We should always put ':' after our path. If there is no
* old_path, the ':' at the end will let 'man' to try
* system-wide paths after ours to find the manual page. If
diff --git a/builtin-init-db.c b/builtin-init-db.c
index 8140c1299..d30c3fe2c 100644
--- a/builtin-init-db.c
+++ b/builtin-init-db.c
@@ -17,6 +17,9 @@
#define TEST_FILEMODE 1
#endif
+static int init_is_bare_repository = 0;
+static int init_shared_repository = -1;
+
static void safe_create_dir(const char *dir, int share)
{
if (mkdir(dir, 0777) < 0) {
@@ -191,6 +194,9 @@ static int create_default_files(const char *template_path)
copy_templates(template_path);
git_config(git_default_config, NULL);
+ is_bare_repository_cfg = init_is_bare_repository;
+ if (init_shared_repository != -1)
+ shared_repository = init_shared_repository;
/*
* We would have created the above under user's umask -- under
@@ -277,6 +283,8 @@ int init_db(const char *template_dir, unsigned int flags)
safe_create_dir(get_git_dir(), 0);
+ init_is_bare_repository = is_bare_repository();
+
/* Check to see if the repository version is right.
* Note that a newly created repository does not have
* config file, so this will not fail. What we are catching
@@ -381,9 +389,9 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir,
sizeof(git_dir)), 0);
} else if (!strcmp(arg, "--shared"))
- shared_repository = PERM_GROUP;
+ init_shared_repository = PERM_GROUP;
else if (!prefixcmp(arg, "--shared="))
- shared_repository = git_config_perm("arg", arg+9);
+ init_shared_repository = git_config_perm("arg", arg+9);
else if (!strcmp(arg, "-q") || !strcmp(arg, "--quiet"))
flags |= INIT_DB_QUIET;
else
diff --git a/builtin-log.c b/builtin-log.c
index fc5e4da82..794821f6b 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -628,10 +628,9 @@ static void gen_message_id(struct rev_info *info, char *base)
const char *committer = git_committer_info(IDENT_WARN_ON_NO_NAME);
const char *email_start = strrchr(committer, '<');
const char *email_end = strrchr(committer, '>');
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
if (!email_start || !email_end || email_start > email_end - 1)
die("Could not extract email from committer identity.");
- strbuf_init(&buf, 0);
strbuf_addf(&buf, "%s.%lu.git.%.*s", base,
(unsigned long) time(NULL),
(int)(email_end - email_start - 1), email_start + 1);
@@ -650,7 +649,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
const char *msg;
const char *extra_headers = rev->extra_headers;
struct shortlog log;
- struct strbuf sb;
+ struct strbuf sb = STRBUF_INIT;
int i;
const char *encoding = "utf-8";
struct diff_options opts;
@@ -671,7 +670,6 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
committer = git_committer_info(0);
msg = body;
- strbuf_init(&sb, 0);
pp_user_info(NULL, CMIT_FMT_EMAIL, &sb, committer, DATE_RFC2822,
encoding);
pp_title_line(CMIT_FMT_EMAIL, &msg, &sb, subject_start, extra_headers,
@@ -753,7 +751,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
const char *in_reply_to = NULL;
struct patch_ids ids;
char *add_signoff = NULL;
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
git_config(git_format_config, NULL);
init_revisions(&rev, prefix);
@@ -861,8 +859,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
}
argc = j;
- strbuf_init(&buf, 0);
-
for (i = 0; i < extra_hdr_nr; i++) {
strbuf_addstr(&buf, extra_hdr[i]);
strbuf_addch(&buf, '\n');
@@ -1139,8 +1135,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
sign = '-';
if (verbose) {
- struct strbuf buf;
- strbuf_init(&buf, 0);
+ struct strbuf buf = STRBUF_INIT;
pretty_print_commit(CMIT_FMT_ONELINE, commit,
&buf, 0, NULL, NULL, 0, 0);
printf("%c %s %s\n", sign,
diff --git a/builtin-merge-base.c b/builtin-merge-base.c
index b08da516e..03fc1c211 100644
--- a/builtin-merge-base.c
+++ b/builtin-merge-base.c
@@ -1,6 +1,7 @@
#include "builtin.h"
#include "cache.h"
#include "commit.h"
+#include "parse-options.h"
static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
{
@@ -21,8 +22,10 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
return 0;
}
-static const char merge_base_usage[] =
-"git merge-base [--all] <commit-id> <commit-id>...";
+static const char * const merge_base_usage[] = {
+ "git merge-base [--all] <commit-id> <commit-id>...",
+ NULL
+};
static struct commit *get_commit_reference(const char *arg)
{
@@ -44,25 +47,17 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)
int rev_nr = 0;
int show_all = 0;
- git_config(git_default_config, NULL);
-
- while (1 < argc && argv[1][0] == '-') {
- const char *arg = argv[1];
- if (!strcmp(arg, "-a") || !strcmp(arg, "--all"))
- show_all = 1;
- else
- usage(merge_base_usage);
- argc--; argv++;
- }
- if (argc < 3)
- usage(merge_base_usage);
-
- rev = xmalloc((argc - 1) * sizeof(*rev));
-
- do {
- rev[rev_nr++] = get_commit_reference(argv[1]);
- argc--; argv++;
- } while (argc > 1);
+ struct option options[] = {
+ OPT_BOOLEAN('a', "all", &show_all, "outputs all common ancestors"),
+ OPT_END()
+ };
+ git_config(git_default_config, NULL);
+ argc = parse_options(argc, argv, options, merge_base_usage, 0);
+ if (argc < 2)
+ usage_with_options(merge_base_usage, options);
+ rev = xmalloc(argc * sizeof(*rev));
+ while (argc-- > 0)
+ rev[rev_nr++] = get_commit_reference(*argv++);
return show_merge_base(rev, rev_nr, show_all);
}
diff --git a/builtin-merge-file.c b/builtin-merge-file.c
index 45c98538c..9d4e87480 100644
--- a/builtin-merge-file.c
+++ b/builtin-merge-file.c
@@ -2,21 +2,44 @@
#include "cache.h"
#include "xdiff/xdiff.h"
#include "xdiff-interface.h"
+#include "parse-options.h"
-static const char merge_file_usage[] =
-"git merge-file [-p | --stdout] [--diff3] [-q | --quiet] [-L name1 [-L orig [-L name2]]] file1 orig_file file2";
+static const char *const merge_file_usage[] = {
+ "git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file file2",
+ NULL
+};
+
+static int label_cb(const struct option *opt, const char *arg, int unset)
+{
+ static int label_count = 0;
+ const char **names = (const char **)opt->value;
+
+ if (label_count >= 3)
+ return error("too many labels on the command line");
+ names[label_count++] = arg;
+ return 0;
+}
int cmd_merge_file(int argc, const char **argv, const char *prefix)
{
- const char *names[3];
+ const char *names[3] = { NULL, NULL, NULL };
mmfile_t mmfs[3];
mmbuffer_t result = {NULL, 0};
xpparam_t xpp = {XDF_NEED_MINIMAL};
int ret = 0, i = 0, to_stdout = 0;
int merge_level = XDL_MERGE_ZEALOUS_ALNUM;
- int merge_style = 0;
+ int merge_style = 0, quiet = 0;
int nongit;
+ struct option options[] = {
+ OPT_BOOLEAN('p', "stdout", &to_stdout, "send results to standard output"),
+ OPT_SET_INT(0, "diff3", &merge_style, "use a diff3 based merge", XDL_MERGE_DIFF3),
+ OPT__QUIET(&quiet),
+ OPT_CALLBACK('L', NULL, names, "name",
+ "set labels for file1/orig_file/file2", &label_cb),
+ OPT_END(),
+ };
+
prefix = setup_git_directory_gently(&nongit);
if (!nongit) {
/* Read the configuration file */
@@ -25,37 +48,20 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
merge_style = git_xmerge_style;
}
- while (argc > 4) {
- if (!strcmp(argv[1], "-L") && i < 3) {
- names[i++] = argv[2];
- argc--;
- argv++;
- } else if (!strcmp(argv[1], "-p") ||
- !strcmp(argv[1], "--stdout"))
- to_stdout = 1;
- else if (!strcmp(argv[1], "-q") ||
- !strcmp(argv[1], "--quiet"))
- freopen("/dev/null", "w", stderr);
- else if (!strcmp(argv[1], "--diff3"))
- merge_style = XDL_MERGE_DIFF3;
- else
- usage(merge_file_usage);
- argc--;
- argv++;
- }
-
- if (argc != 4)
- usage(merge_file_usage);
-
- for (; i < 3; i++)
- names[i] = argv[i + 1];
+ argc = parse_options(argc, argv, options, merge_file_usage, 0);
+ if (argc != 3)
+ usage_with_options(merge_file_usage, options);
+ if (quiet)
+ freopen("/dev/null", "w", stderr);
for (i = 0; i < 3; i++) {
- if (read_mmfile(mmfs + i, argv[i + 1]))
+ if (!names[i])
+ names[i] = argv[i];
+ if (read_mmfile(mmfs + i, argv[i]))
return -1;
if (buffer_is_binary(mmfs[i].ptr, mmfs[i].size))
return error("Cannot merge binary files: %s\n",
- argv[i + 1]);
+ argv[i]);
}
ret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],
@@ -65,7 +71,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
free(mmfs[i].ptr);
if (ret >= 0) {
- const char *filename = argv[1];
+ const char *filename = argv[0];
FILE *f = to_stdout ? stdout : fopen(filename, "wb");
if (!f)
diff --git a/builtin-merge.c b/builtin-merge.c
index 5c65a5869..5e2b7f12c 100644
--- a/builtin-merge.c
+++ b/builtin-merge.c
@@ -123,8 +123,7 @@ static struct strategy *get_strategy(const char *name)
exit(1);
}
- ret = xmalloc(sizeof(struct strategy));
- memset(ret, 0, sizeof(struct strategy));
+ ret = xcalloc(1, sizeof(struct strategy));
ret->name = xstrdup(name);
return ret;
}
@@ -227,7 +226,7 @@ static void reset_hard(unsigned const char *sha1, int verbose)
static void restore_state(void)
{
- struct strbuf sb;
+ struct strbuf sb = STRBUF_INIT;
const char *args[] = { "stash", "apply", NULL, NULL };
if (is_null_sha1(stash))
@@ -235,7 +234,6 @@ static void restore_state(void)
reset_hard(head, 1);
- strbuf_init(&sb, 0);
args[2] = sha1_to_hex(stash);
/*
@@ -259,7 +257,7 @@ static void squash_message(void)
{
struct rev_info rev;
struct commit *commit;
- struct strbuf out;
+ struct strbuf out = STRBUF_INIT;
struct commit_list *j;
int fd;
@@ -283,7 +281,6 @@ static void squash_message(void)
if (prepare_revision_walk(&rev))
die("revision walk setup failed");
- strbuf_init(&out, 0);
strbuf_addstr(&out, "Squashed commit of the following:\n");
while ((commit = get_revision(&rev)) != NULL) {
strbuf_addch(&out, '\n');
@@ -328,9 +325,8 @@ static int run_hook(const char *name)
static void finish(const unsigned char *new_head, const char *msg)
{
- struct strbuf reflog_message;
+ struct strbuf reflog_message = STRBUF_INIT;
- strbuf_init(&reflog_message, 0);
if (!msg)
strbuf_addstr(&reflog_message, getenv("GIT_REFLOG_ACTION"));
else {
@@ -381,7 +377,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
{
struct object *remote_head;
unsigned char branch_head[20], buf_sha[20];
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
const char *ptr;
int len, early;
@@ -390,7 +386,6 @@ static void merge_name(const char *remote, struct strbuf *msg)
if (!remote_head)
die("'%s' does not point to a commit", remote);
- strbuf_init(&buf, 0);
strbuf_addstr(&buf, "refs/heads/");
strbuf_addstr(&buf, remote);
resolve_ref(buf.buf, branch_head, 0, 0);
@@ -445,10 +440,9 @@ static void merge_name(const char *remote, struct strbuf *msg)
if (!strcmp(remote, "FETCH_HEAD") &&
!access(git_path("FETCH_HEAD"), R_OK)) {
FILE *fp;
- struct strbuf line;
+ struct strbuf line = STRBUF_INIT;
char *ptr;
- strbuf_init(&line, 0);
fp = fopen(git_path("FETCH_HEAD"), "r");
if (!fp)
die("could not open %s for reading: %s",
@@ -546,7 +540,17 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
const char **args;
int i = 0, ret;
struct commit_list *j;
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
+ int index_fd;
+ struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
+
+ index_fd = hold_locked_index(lock, 1);
+ refresh_cache(REFRESH_QUIET);
+ if (active_cache_changed &&
+ (write_cache(index_fd, active_cache, active_nr) ||
+ commit_locked_index(lock)))
+ return error("Unable to write index.");
+ rollback_lock_file(lock);
if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) {
int clean;
@@ -583,7 +587,6 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
} else {
args = xmalloc((4 + commit_list_count(common) +
commit_list_count(remoteheads)) * sizeof(char *));
- strbuf_init(&buf, 0);
strbuf_addf(&buf, "merge-%s", strategy);
args[i++] = buf.buf;
for (j = common; j; j = j->next)
@@ -723,12 +726,12 @@ static void add_strategies(const char *string, unsigned attr)
static int merge_trivial(void)
{
unsigned char result_tree[20], result_commit[20];
- struct commit_list *parent = xmalloc(sizeof(struct commit_list *));
+ struct commit_list *parent = xmalloc(sizeof(*parent));
write_tree_trivial(result_tree);
printf("Wonderful.\n");
parent->item = lookup_commit(head);
- parent->next = xmalloc(sizeof(struct commit_list *));
+ parent->next = xmalloc(sizeof(*parent->next));
parent->next->item = remoteheads->item;
parent->next->next = NULL;
commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL);
@@ -838,7 +841,7 @@ static int evaluate_result(void)
int cmd_merge(int argc, const char **argv, const char *prefix)
{
unsigned char result_tree[20];
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
const char *head_arg;
int flag, head_invalid = 0, i;
int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0;
@@ -887,7 +890,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* Traditional format never would have "-m" so it is an
* additional safety measure to check for it.
*/
- strbuf_init(&buf, 0);
if (!have_message && is_old_style_invocation(argc, argv)) {
strbuf_addstr(&merge_msg, argv[0]);
@@ -917,7 +919,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
reset_hard(remote_head->sha1, 0);
return 0;
} else {
- struct strbuf msg;
+ struct strbuf msg = STRBUF_INIT;
/* We are invoked directly as the first-class UI. */
head_arg = "HEAD";
@@ -930,7 +932,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* codepath so we discard the error in this
* loop.
*/
- strbuf_init(&msg, 0);
for (i = 0; i < argc; i++)
merge_name(argv[i], &msg);
fmt_merge_msg(option_log, &msg, &merge_msg);
@@ -1005,7 +1006,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
!common->next &&
!hashcmp(common->item->object.sha1, head)) {
/* Again the most common case of merging one remote. */
- struct strbuf msg;
+ struct strbuf msg = STRBUF_INIT;
struct object *o;
char hex[41];
@@ -1015,7 +1016,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
hex,
find_unique_abbrev(remoteheads->item->object.sha1,
DEFAULT_ABBREV));
- strbuf_init(&msg, 0);
strbuf_addstr(&msg, "Fast forward");
if (have_message)
strbuf_addstr(&msg,
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index 1158e42cb..59c30d1ca 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -1369,12 +1369,10 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
int window, int depth, unsigned *processed)
{
uint32_t i, idx = 0, count = 0;
- unsigned int array_size = window * sizeof(struct unpacked);
struct unpacked *array;
unsigned long mem_usage = 0;
- array = xmalloc(array_size);
- memset(array, 0, array_size);
+ array = xcalloc(window, sizeof(struct unpacked));
for (;;) {
struct object_entry *entry = *list++;
diff --git a/builtin-prune.c b/builtin-prune.c
index 1663f8bdb..7b4ec80e6 100644
--- a/builtin-prune.c
+++ b/builtin-prune.c
@@ -7,10 +7,11 @@
#include "parse-options.h"
static const char * const prune_usage[] = {
- "git prune [-n] [--expire <time>] [--] [<head>...]",
+ "git prune [-n] [-v] [--expire <time>] [--] [<head>...]",
NULL
};
static int show_only;
+static int verbose;
static unsigned long expire;
static int prune_tmp_object(const char *path, const char *filename)
@@ -39,11 +40,12 @@ static int prune_object(char *path, const char *filename, const unsigned char *s
if (st.st_mtime > expire)
return 0;
}
- if (show_only) {
+ if (show_only || verbose) {
enum object_type type = sha1_object_info(sha1, NULL);
printf("%s %s\n", sha1_to_hex(sha1),
(type > 0) ? typename(type) : "unknown");
- } else
+ }
+ if (!show_only)
unlink(fullpath);
return 0;
}
@@ -135,6 +137,8 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
const struct option options[] = {
OPT_BOOLEAN('n', NULL, &show_only,
"do not remove, show only"),
+ OPT_BOOLEAN('v', NULL, &verbose,
+ "report pruned objects"),
OPT_DATE(0, "expire", &expire,
"expire objects older than <time>"),
OPT_END()
diff --git a/builtin-push.c b/builtin-push.c
index cc6666f75..122fdcfbd 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -10,7 +10,7 @@
#include "parse-options.h"
static const char * const push_usage[] = {
- "git push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]",
+ "git push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]",
NULL,
};
diff --git a/builtin-remote.c b/builtin-remote.c
index 90a4e3582..6b3325dfa 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -54,7 +54,7 @@ static int add(int argc, const char **argv)
struct string_list track = { NULL, 0, 0 };
const char *master = NULL;
struct remote *remote;
- struct strbuf buf, buf2;
+ struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
const char *name, *url;
int i;
@@ -81,9 +81,6 @@ static int add(int argc, const char **argv)
remote->fetch_refspec_nr))
die("remote %s already exists.", name);
- strbuf_init(&buf, 0);
- strbuf_init(&buf2, 0);
-
strbuf_addf(&buf2, "refs/heads/test:refs/remotes/%s/test", name);
if (!valid_fetch_refspec(buf2.buf))
die("'%s' is not a valid remote name", name);
@@ -352,7 +349,7 @@ static int rm(int argc, const char **argv)
OPT_END()
};
struct remote *remote;
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
struct known_remotes known_remotes = { NULL, NULL };
struct string_list branches = { NULL, 0, 0, 1 };
struct branches_for_remote cb_data = { NULL, &branches, &known_remotes };
@@ -368,7 +365,6 @@ static int rm(int argc, const char **argv)
known_remotes.to_delete = remote;
for_each_remote(add_known_remote, &known_remotes);
- strbuf_init(&buf, 0);
strbuf_addf(&buf, "remote.%s", remote->name);
if (git_config_rename_section(buf.buf, NULL) < 1)
return error("Could not remove config section '%s'", buf.buf);
diff --git a/builtin-rev-list.c b/builtin-rev-list.c
index facaff288..06cdeb7eb 100644
--- a/builtin-rev-list.c
+++ b/builtin-rev-list.c
@@ -107,8 +107,7 @@ static void show_commit(struct commit *commit)
putchar('\n');
if (revs.verbose_header && commit->buffer) {
- struct strbuf buf;
- strbuf_init(&buf, 0);
+ struct strbuf buf = STRBUF_INIT;
pretty_print_commit(revs.commit_format, commit,
&buf, revs.abbrev, NULL, NULL,
revs.date_mode, 0);
diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c
index 9aa049ec1..81d5a6ffc 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -307,19 +307,17 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
OPT_END(),
};
- struct strbuf sb, parsed;
+ struct strbuf sb = STRBUF_INIT, parsed = STRBUF_INIT;
const char **usage = NULL;
struct option *opts = NULL;
int onb = 0, osz = 0, unb = 0, usz = 0;
- strbuf_init(&parsed, 0);
strbuf_addstr(&parsed, "set --");
argc = parse_options(argc, argv, parseopt_opts, parseopt_usage,
PARSE_OPT_KEEP_DASHDASH);
if (argc < 1 || strcmp(argv[0], "--"))
usage_with_options(parseopt_usage, parseopt_opts);
- strbuf_init(&sb, 0);
/* get the usage up to the first line with a -- on it */
for (;;) {
if (strbuf_getline(&sb, stdin, '\n') == EOF)
diff --git a/builtin-rm.c b/builtin-rm.c
index 50ae6d540..e06640cf8 100644
--- a/builtin-rm.c
+++ b/builtin-rm.c
@@ -137,6 +137,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
if (read_cache() < 0)
die("index file corrupt");
+ refresh_cache(REFRESH_QUIET);
pathspec = get_pathspec(prefix, argv);
seen = NULL;
diff --git a/builtin-show-branch.c b/builtin-show-branch.c
index 233eed499..306b850c7 100644
--- a/builtin-show-branch.c
+++ b/builtin-show-branch.c
@@ -259,11 +259,10 @@ static void join_revs(struct commit_list **list_p,
static void show_one_commit(struct commit *commit, int no_name)
{
- struct strbuf pretty;
+ struct strbuf pretty = STRBUF_INIT;
const char *pretty_str = "(unavailable)";
struct commit_name *name = commit->util;
- strbuf_init(&pretty, 0);
if (commit->object.parsed) {
pretty_print_commit(CMIT_FMT_ONELINE, commit,
&pretty, 0, NULL, NULL, 0, 0);
diff --git a/builtin-stripspace.c b/builtin-stripspace.c
index c0b21301b..d6e3896c0 100644
--- a/builtin-stripspace.c
+++ b/builtin-stripspace.c
@@ -70,14 +70,13 @@ void stripspace(struct strbuf *sb, int skip_comments)
int cmd_stripspace(int argc, const char **argv, const char *prefix)
{
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
int strip_comments = 0;
if (argc > 1 && (!strcmp(argv[1], "-s") ||
!strcmp(argv[1], "--strip-comments")))
strip_comments = 1;
- strbuf_init(&buf, 0);
if (strbuf_read(&buf, 0, 1024) < 0)
die("could not read the input");
diff --git a/builtin-tag.c b/builtin-tag.c
index f2853d08c..b13fa34d8 100644
--- a/builtin-tag.c
+++ b/builtin-tag.c
@@ -338,7 +338,7 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
int cmd_tag(int argc, const char **argv, const char *prefix)
{
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
unsigned char object[20], prev[20];
char ref[PATH_MAX];
const char *object_ref, *tag;
@@ -388,7 +388,6 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (verify)
return for_each_tag_name(argv, verify_tag);
- strbuf_init(&buf, 0);
if (msg.given || msgfile) {
if (msg.given && msgfile)
die("only one -F or -m option is allowed.");
diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c
index d2796b630..9f4bdd329 100644
--- a/builtin-unpack-objects.c
+++ b/builtin-unpack-objects.c
@@ -477,8 +477,7 @@ static void unpack_all(void)
if (!quiet)
progress = start_progress("Unpacking objects", nr_objects);
- obj_list = xmalloc(nr_objects * sizeof(*obj_list));
- memset(obj_list, 0, nr_objects * sizeof(*obj_list));
+ obj_list = xcalloc(nr_objects, sizeof(*obj_list));
for (i = 0; i < nr_objects; i++) {
unpack_one(i);
display_progress(progress, i + 1);
diff --git a/builtin-update-index.c b/builtin-update-index.c
index 417f9724a..65d577510 100644
--- a/builtin-update-index.c
+++ b/builtin-update-index.c
@@ -218,7 +218,7 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
struct cache_entry *ce;
if (!verify_path(path))
- return -1;
+ return error("Invalid path '%s'", path);
len = strlen(path);
size = cache_entry_size(len);
@@ -297,11 +297,9 @@ static void update_one(const char *path, const char *prefix, int prefix_length)
static void read_index_info(int line_termination)
{
- struct strbuf buf;
- struct strbuf uq;
+ struct strbuf buf = STRBUF_INIT;
+ struct strbuf uq = STRBUF_INIT;
- strbuf_init(&buf, 0);
- strbuf_init(&uq, 0);
while (strbuf_getline(&buf, stdin, line_termination) != EOF) {
char *ptr, *tab;
char *path_name;
@@ -717,10 +715,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
free((char*)p);
}
if (read_from_stdin) {
- struct strbuf buf, nbuf;
+ struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;
- strbuf_init(&buf, 0);
- strbuf_init(&nbuf, 0);
setup_work_tree();
while (strbuf_getline(&buf, stdin, line_termination) != EOF) {
const char *p;
diff --git a/cache.h b/cache.h
index 9f4e5c0d4..991544cf0 100644
--- a/cache.h
+++ b/cache.h
@@ -319,6 +319,7 @@ extern int is_bare_repository(void);
extern int is_inside_git_dir(void);
extern char *git_work_tree_cfg;
extern int is_inside_work_tree(void);
+extern int have_git_dir(void);
extern const char *get_git_dir(void);
extern char *get_object_directory(void);
extern char *get_index_file(void);
@@ -377,6 +378,7 @@ extern int index_name_pos(const struct index_state *, const char *name, int name
#define ADD_CACHE_OK_TO_REPLACE 2 /* Ok to replace file/directory */
#define ADD_CACHE_SKIP_DFCHECK 4 /* Ok to skip DF conflict checks */
#define ADD_CACHE_JUST_APPEND 8 /* Append only; tree.c::read_tree() */
+#define ADD_CACHE_NEW_ONLY 16 /* Do not replace existing ones */
extern int add_index_entry(struct index_state *, struct cache_entry *ce, int option);
extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name);
@@ -386,6 +388,7 @@ extern int remove_file_from_index(struct index_state *, const char *path);
#define ADD_CACHE_PRETEND 2
#define ADD_CACHE_IGNORE_ERRORS 4
#define ADD_CACHE_IGNORE_REMOVAL 8
+#define ADD_CACHE_INTENT 16
extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
extern int add_file_to_index(struct index_state *, const char *path, int flags);
extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
diff --git a/combine-diff.c b/combine-diff.c
index de83c6972..5aa1104d3 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -742,9 +742,8 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
/* If not a fake symlink, apply filters, e.g. autocrlf */
if (is_file) {
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
- strbuf_init(&buf, 0);
if (convert_to_git(elem->path, result, len, &buf, safe_crlf)) {
free(result);
result = strbuf_detach(&buf, &len);
diff --git a/compat/cygwin.c b/compat/cygwin.c
new file mode 100644
index 000000000..423ff20b0
--- /dev/null
+++ b/compat/cygwin.c
@@ -0,0 +1,127 @@
+#define WIN32_LEAN_AND_MEAN
+#include "../git-compat-util.h"
+#include "win32.h"
+#include "../cache.h" /* to read configuration */
+
+static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
+{
+ long long winTime = ((long long)ft->dwHighDateTime << 32) +
+ ft->dwLowDateTime;
+ winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */
+ /* convert 100-nsecond interval to seconds and nanoseconds */
+ ts->tv_sec = (time_t)(winTime/10000000);
+ ts->tv_nsec = (long)(winTime - ts->tv_sec*10000000LL) * 100;
+}
+
+#define size_to_blocks(s) (((s)+511)/512)
+
+/* do_stat is a common implementation for cygwin_lstat and cygwin_stat.
+ *
+ * To simplify its logic, in the case of cygwin symlinks, this implementation
+ * falls back to the cygwin version of stat/lstat, which is provided as the
+ * last argument.
+ */
+static int do_stat(const char *file_name, struct stat *buf, stat_fn_t cygstat)
+{
+ WIN32_FILE_ATTRIBUTE_DATA fdata;
+
+ if (file_name[0] == '/')
+ return cygstat (file_name, buf);
+
+ if (!(errno = get_file_attr(file_name, &fdata))) {
+ /*
+ * If the system attribute is set and it is not a directory then
+ * it could be a symbol link created in the nowinsymlinks mode.
+ * Normally, Cygwin works in the winsymlinks mode, so this situation
+ * is very unlikely. For the sake of simplicity of our code, let's
+ * Cygwin to handle it.
+ */
+ if ((fdata.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) &&
+ !(fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ return cygstat(file_name, buf);
+
+ /* fill out the stat structure */
+ buf->st_dev = buf->st_rdev = 0; /* not used by Git */
+ buf->st_ino = 0;
+ buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
+ buf->st_nlink = 1;
+ buf->st_uid = buf->st_gid = 0;
+#ifdef __CYGWIN_USE_BIG_TYPES__
+ buf->st_size = ((_off64_t)fdata.nFileSizeHigh << 32) +
+ fdata.nFileSizeLow;
+#else
+ buf->st_size = (off_t)fdata.nFileSizeLow;
+#endif
+ buf->st_blocks = size_to_blocks(buf->st_size);
+ filetime_to_timespec(&fdata.ftLastAccessTime, &buf->st_atim);
+ filetime_to_timespec(&fdata.ftLastWriteTime, &buf->st_mtim);
+ filetime_to_timespec(&fdata.ftCreationTime, &buf->st_ctim);
+ return 0;
+ } else if (errno == ENOENT) {
+ /*
+ * In the winsymlinks mode (which is the default), Cygwin
+ * emulates symbol links using Windows shortcut files. These
+ * files are formed by adding .lnk extension. So, if we have
+ * not found the specified file name, it could be that it is
+ * a symbol link. Let's Cygwin to deal with that.
+ */
+ return cygstat(file_name, buf);
+ }
+ return -1;
+}
+
+/* We provide our own lstat/stat functions, since the provided Cygwin versions
+ * of these functions are too slow. These stat functions are tailored for Git's
+ * usage, and therefore they are not meant to be complete and correct emulation
+ * of lstat/stat functionality.
+ */
+static int cygwin_lstat(const char *path, struct stat *buf)
+{
+ return do_stat(path, buf, lstat);
+}
+
+static int cygwin_stat(const char *path, struct stat *buf)
+{
+ return do_stat(path, buf, stat);
+}
+
+
+/*
+ * At start up, we are trying to determine whether Win32 API or cygwin stat
+ * functions should be used. The choice is determined by core.ignorecygwinfstricks.
+ * Reading this option is not always possible immediately as git_dir may be
+ * not be set yet. So until it is set, use cygwin lstat/stat functions.
+ */
+static int native_stat = 1;
+
+static int git_cygwin_config(const char *var, const char *value, void *cb)
+{
+ if (!strcmp(var, "core.ignorecygwinfstricks"))
+ native_stat = git_config_bool(var, value);
+ return 0;
+}
+
+static int init_stat(void)
+{
+ if (have_git_dir()) {
+ git_config(git_cygwin_config, NULL);
+ cygwin_stat_fn = native_stat ? cygwin_stat : stat;
+ cygwin_lstat_fn = native_stat ? cygwin_lstat : lstat;
+ return 0;
+ }
+ return 1;
+}
+
+static int cygwin_stat_stub(const char *file_name, struct stat *buf)
+{
+ return (init_stat() ? stat : *cygwin_stat_fn)(file_name, buf);
+}
+
+static int cygwin_lstat_stub(const char *file_name, struct stat *buf)
+{
+ return (init_stat() ? lstat : *cygwin_lstat_fn)(file_name, buf);
+}
+
+stat_fn_t cygwin_stat_fn = cygwin_stat_stub;
+stat_fn_t cygwin_lstat_fn = cygwin_lstat_stub;
+
diff --git a/compat/cygwin.h b/compat/cygwin.h
new file mode 100644
index 000000000..a3229f5b4
--- /dev/null
+++ b/compat/cygwin.h
@@ -0,0 +1,9 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+
+typedef int (*stat_fn_t)(const char*, struct stat*);
+extern stat_fn_t cygwin_stat_fn;
+extern stat_fn_t cygwin_lstat_fn;
+
+#define stat(path, buf) (*cygwin_stat_fn)(path, buf)
+#define lstat(path, buf) (*cygwin_lstat_fn)(path, buf)
diff --git a/compat/mingw.c b/compat/mingw.c
index fc45d240f..09858f6c5 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1,4 +1,5 @@
#include "../git-compat-util.h"
+#include "win32.h"
#include "../strbuf.h"
unsigned int _CRT_fmode = _O_BINARY;
@@ -39,46 +40,19 @@ static int do_lstat(const char *file_name, struct stat *buf)
{
WIN32_FILE_ATTRIBUTE_DATA fdata;
- if (GetFileAttributesExA(file_name, GetFileExInfoStandard, &fdata)) {
- int fMode = S_IREAD;
- if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- fMode |= S_IFDIR;
- else
- fMode |= S_IFREG;
- if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
- fMode |= S_IWRITE;
-
+ if (!(errno = get_file_attr(file_name, &fdata))) {
buf->st_ino = 0;
buf->st_gid = 0;
buf->st_uid = 0;
buf->st_nlink = 1;
- buf->st_mode = fMode;
+ buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
- errno = 0;
return 0;
}
-
- switch (GetLastError()) {
- case ERROR_ACCESS_DENIED:
- case ERROR_SHARING_VIOLATION:
- case ERROR_LOCK_VIOLATION:
- case ERROR_SHARING_BUFFER_EXCEEDED:
- errno = EACCES;
- break;
- case ERROR_BUFFER_OVERFLOW:
- errno = ENAMETOOLONG;
- break;
- case ERROR_NOT_ENOUGH_MEMORY:
- errno = ENOMEM;
- break;
- default:
- errno = ENOENT;
- break;
- }
return -1;
}
@@ -130,19 +104,11 @@ int mingw_fstat(int fd, struct stat *buf)
return fstat(fd, buf);
if (GetFileInformationByHandle(fh, &fdata)) {
- int fMode = S_IREAD;
- if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- fMode |= S_IFDIR;
- else
- fMode |= S_IFREG;
- if (!(fdata.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
- fMode |= S_IWRITE;
-
buf->st_ino = 0;
buf->st_gid = 0;
buf->st_uid = 0;
buf->st_nlink = 1;
- buf->st_mode = fMode;
+ buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
diff --git a/compat/win32.h b/compat/win32.h
new file mode 100644
index 000000000..c26384e59
--- /dev/null
+++ b/compat/win32.h
@@ -0,0 +1,34 @@
+/* common Win32 functions for MinGW and Cygwin */
+#include <windows.h>
+
+static inline int file_attr_to_st_mode (DWORD attr)
+{
+ int fMode = S_IREAD;
+ if (attr & FILE_ATTRIBUTE_DIRECTORY)
+ fMode |= S_IFDIR;
+ else
+ fMode |= S_IFREG;
+ if (!(attr & FILE_ATTRIBUTE_READONLY))
+ fMode |= S_IWRITE;
+ return fMode;
+}
+
+static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fdata)
+{
+ if (GetFileAttributesExA(fname, GetFileExInfoStandard, fdata))
+ return 0;
+
+ switch (GetLastError()) {
+ case ERROR_ACCESS_DENIED:
+ case ERROR_SHARING_VIOLATION:
+ case ERROR_LOCK_VIOLATION:
+ case ERROR_SHARING_BUFFER_EXCEEDED:
+ return EACCES;
+ case ERROR_BUFFER_OVERFLOW:
+ return ENAMETOOLONG;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ return ENOMEM;
+ default:
+ return ENOENT;
+ }
+}
diff --git a/config.c b/config.c
index 18d305c89..b8d289d21 100644
--- a/config.c
+++ b/config.c
@@ -753,9 +753,8 @@ static int store_write_section(int fd, const char* key)
{
const char *dot;
int i, success;
- struct strbuf sb;
+ struct strbuf sb = STRBUF_INIT;
- strbuf_init(&sb, 0);
dot = memchr(key, '.', store.baselen);
if (dot) {
strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
@@ -780,7 +779,7 @@ static int store_write_pair(int fd, const char* key, const char* value)
int i, success;
int length = strlen(key + store.baselen + 1);
const char *quote = "";
- struct strbuf sb;
+ struct strbuf sb = STRBUF_INIT;
/*
* Check to see if the value needs to be surrounded with a dq pair.
@@ -797,7 +796,6 @@ static int store_write_pair(int fd, const char* key, const char* value)
if (i && value[i - 1] == ' ')
quote = "\"";
- strbuf_init(&sb, 0);
strbuf_addf(&sb, "\t%.*s = %s",
length, key + store.baselen + 1, quote);
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 15073d4c9..d192927c2 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1123,7 +1123,8 @@ _git_send_email ()
--no-suppress-from --no-thread --quiet
--signed-off-by-cc --smtp-pass --smtp-server
--smtp-server-port --smtp-ssl --smtp-user --subject
- --suppress-cc --suppress-from --thread --to"
+ --suppress-cc --suppress-from --thread --to
+ --validate --no-validate"
return
;;
esac
diff --git a/contrib/examples/git-remote.perl b/contrib/examples/git-remote.perl
index 36bd54c98..b17952a78 100755
--- a/contrib/examples/git-remote.perl
+++ b/contrib/examples/git-remote.perl
@@ -309,7 +309,7 @@ sub update_remote {
}
}
} else {
- print STDERR "Remote group $name does not exists.\n";
+ print STDERR "Remote group $name does not exist.\n";
exit(1);
}
for (@remotes) {
diff --git a/contrib/hooks/pre-auto-gc-battery b/contrib/hooks/pre-auto-gc-battery
index b0a8caae9..1f914c94a 100644
--- a/contrib/hooks/pre-auto-gc-battery
+++ b/contrib/hooks/pre-auto-gc-battery
@@ -30,6 +30,9 @@ then
elif grep -q '0x01$' /proc/apm 2>/dev/null
then
exit 0
+elif grep -q "AC Power \+: 1" /proc/pmu/info 2>/dev/null
+then
+ exit 0
elif test -x /usr/bin/pmset && /usr/bin/pmset -g batt |
grep -q "Currently drawing from 'AC Power'"
then
diff --git a/contrib/stats/packinfo.pl b/contrib/stats/packinfo.pl
index f4a7b62cd..be188c0f1 100755
--- a/contrib/stats/packinfo.pl
+++ b/contrib/stats/packinfo.pl
@@ -1,9 +1,9 @@
#!/usr/bin/perl
#
# This tool will print vaguely pretty information about a pack. It
-# expects the output of "git-verify-pack -v" as input on stdin.
+# expects the output of "git verify-pack -v" as input on stdin.
#
-# $ git-verify-pack -v | packinfo.pl
+# $ git verify-pack -v | packinfo.pl
#
# This prints some full-pack statistics; currently "all sizes", "all
# path sizes", "tree sizes", "tree path sizes", and "depths".
@@ -20,7 +20,7 @@
#
# When run as:
#
-# $ git-verify-pack -v | packinfo.pl -tree
+# $ git verify-pack -v | packinfo.pl -tree
#
# the trees of objects are output along with the stats. This looks
# like:
@@ -43,7 +43,7 @@
#
# When run as:
#
-# $ git-verify-pack -v | packinfo.pl -tree -filenames
+# $ git verify-pack -v | packinfo.pl -tree -filenames
#
# it adds filenames to the tree. Getting this information is slow:
#
@@ -58,7 +58,7 @@
#
# When run as:
#
-# $ git-verify-pack -v | packinfo.pl -dump
+# $ git verify-pack -v | packinfo.pl -dump
#
# it prints out "sha1 size pathsize depth" for each sha1 in lexical
# order.
@@ -106,7 +106,7 @@ while (<STDIN>) {
}
if ($filenames && ($tree || $dump)) {
- open(NAMES, "git-name-rev --all|");
+ open(NAMES, "git name-rev --all|");
while (<NAMES>) {
if (/^(\S+)\s+(.*)$/) {
my ($sha1, $name) = ($1, $2);
@@ -117,7 +117,7 @@ if ($filenames && ($tree || $dump)) {
for my $commit (@commits) {
my $name = $names{$commit};
- open(TREE, "git-ls-tree -t -r $commit|");
+ open(TREE, "git ls-tree -t -r $commit|");
print STDERR "Plumbing tree $name\n";
while (<TREE>) {
if (/^(\S+)\s+(\S+)\s+(\S+)\s+(.*)$/) {
diff --git a/convert.c b/convert.c
index 78efed800..1816e977b 100644
--- a/convert.c
+++ b/convert.c
@@ -281,7 +281,7 @@ static int apply_filter(const char *path, const char *src, size_t len,
* (child --> cmd) --> us
*/
int ret = 1;
- struct strbuf nbuf;
+ struct strbuf nbuf = STRBUF_INIT;
struct async async;
struct filter_params params;
@@ -299,7 +299,6 @@ static int apply_filter(const char *path, const char *src, size_t len,
if (start_async(&async))
return 0; /* error was already reported */
- strbuf_init(&nbuf, 0);
if (strbuf_read(&nbuf, async.out, len) < 0) {
error("read from external filter %s failed", cmd);
ret = 0;
diff --git a/csum-file.c b/csum-file.c
index 717d29fc0..2ddb12a0b 100644
--- a/csum-file.c
+++ b/csum-file.c
@@ -11,7 +11,7 @@
#include "progress.h"
#include "csum-file.h"
-static void sha1flush(struct sha1file *f, void *buf, unsigned int count)
+static void flush(struct sha1file *f, void * buf, unsigned int count)
{
for (;;) {
int ret = xwrite(f->fd, buf, count);
@@ -30,22 +30,28 @@ static void sha1flush(struct sha1file *f, void *buf, unsigned int count)
}
}
-int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags)
+void sha1flush(struct sha1file *f)
{
- int fd;
unsigned offset = f->offset;
if (offset) {
git_SHA1_Update(&f->ctx, f->buffer, offset);
- sha1flush(f, f->buffer, offset);
+ flush(f, f->buffer, offset);
f->offset = 0;
}
+}
+
+int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags)
+{
+ int fd;
+
+ sha1flush(f);
git_SHA1_Final(f->buffer, &f->ctx);
if (result)
hashcpy(result, f->buffer);
if (flags & (CSUM_CLOSE | CSUM_FSYNC)) {
/* write checksum and close fd */
- sha1flush(f, f->buffer, 20);
+ flush(f, f->buffer, 20);
if (flags & CSUM_FSYNC)
fsync_or_die(f->fd, f->name);
if (close(f->fd))
@@ -83,7 +89,7 @@ int sha1write(struct sha1file *f, void *buf, unsigned int count)
left -= nr;
if (!left) {
git_SHA1_Update(&f->ctx, data, offset);
- sha1flush(f, data, offset);
+ flush(f, data, offset);
offset = 0;
}
f->offset = offset;
diff --git a/csum-file.h b/csum-file.h
index 9e13342eb..294add2a9 100644
--- a/csum-file.h
+++ b/csum-file.h
@@ -24,6 +24,7 @@ extern struct sha1file *sha1fd(int fd, const char *name);
extern struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp);
extern int sha1close(struct sha1file *, unsigned char *, unsigned int);
extern int sha1write(struct sha1file *, void *, unsigned int);
+extern void sha1flush(struct sha1file *f);
extern void crc32_begin(struct sha1file *);
extern uint32_t crc32_end(struct sha1file *);
diff --git a/date.c b/date.c
index 35a52576c..950b88fdc 100644
--- a/date.c
+++ b/date.c
@@ -402,6 +402,15 @@ static int match_multi_number(unsigned long num, char c, const char *date, char
return end - date;
}
+/* Have we filled in any part of the time/date yet? */
+static inline int nodate(struct tm *tm)
+{
+ return tm->tm_year < 0 &&
+ tm->tm_mon < 0 &&
+ tm->tm_mday < 0 &&
+ !(tm->tm_hour | tm->tm_min | tm->tm_sec);
+}
+
/*
* We've seen a digit. Time? Year? Date?
*/
@@ -418,7 +427,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
* more than 8 digits. This is because we don't want to rule out
* numbers like 20070606 as a YYYYMMDD date.
*/
- if (num >= 100000000) {
+ if (num >= 100000000 && nodate(tm)) {
time_t time = num;
if (gmtime_r(&time, tm)) {
*tm_gmt = 1;
@@ -463,6 +472,13 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
}
/*
+ * Ignore lots of numerals. We took care of 4-digit years above.
+ * Days or months must be one or two digits.
+ */
+ if (n > 2)
+ return n;
+
+ /*
* NOTE! We will give precedence to day-of-month over month or
* year numbers in the 1-12 range. So 05 is always "mday 5",
* unless we already have a mday..
@@ -488,10 +504,6 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
if (num > 0 && num < 32) {
tm->tm_mday = num;
- } else if (num > 1900) {
- tm->tm_year = num - 1900;
- } else if (num > 70) {
- tm->tm_year = num;
} else if (num > 0 && num < 13) {
tm->tm_mon = num-1;
}
@@ -823,7 +835,9 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num)
}
}
- *num = number;
+ /* Accept zero-padding only for small numbers ("Dec 02", never "Dec 0002") */
+ if (date[0] != '0' || end - date <= 2)
+ *num = number;
return end;
}
diff --git a/diff.c b/diff.c
index 02e948c9d..1c6be897b 100644
--- a/diff.c
+++ b/diff.c
@@ -217,9 +217,8 @@ static char *quote_two(const char *one, const char *two)
{
int need_one = quote_c_style(one, NULL, NULL, 1);
int need_two = quote_c_style(two, NULL, NULL, 1);
- struct strbuf res;
+ struct strbuf res = STRBUF_INIT;
- strbuf_init(&res, 0);
if (need_one + need_two) {
strbuf_addch(&res, '"');
quote_c_style(one, &res, NULL, 1);
@@ -683,7 +682,7 @@ static char *pprint_rename(const char *a, const char *b)
{
const char *old = a;
const char *new = b;
- struct strbuf name;
+ struct strbuf name = STRBUF_INIT;
int pfx_length, sfx_length;
int len_a = strlen(a);
int len_b = strlen(b);
@@ -691,7 +690,6 @@ static char *pprint_rename(const char *a, const char *b)
int qlen_a = quote_c_style(a, NULL, NULL, 0);
int qlen_b = quote_c_style(b, NULL, NULL, 0);
- strbuf_init(&name, 0);
if (qlen_a || qlen_b) {
quote_c_style(a, &name, NULL, 0);
strbuf_addstr(&name, " => ");
@@ -834,8 +832,7 @@ static void fill_print_name(struct diffstat_file *file)
return;
if (!file->is_renamed) {
- struct strbuf buf;
- strbuf_init(&buf, 0);
+ struct strbuf buf = STRBUF_INIT;
if (quote_c_style(file->name, &buf, NULL, 0)) {
pname = strbuf_detach(&buf, NULL);
} else {
@@ -1429,6 +1426,16 @@ static const struct funcname_pattern_entry builtin_funcname_pattern[] = {
"!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n"
"^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$",
REG_EXTENDED },
+ { "objc",
+ /* Negate C statements that can look like functions */
+ "!^[ \t]*(do|for|if|else|return|switch|while)\n"
+ /* Objective-C methods */
+ "^[ \t]*([-+][ \t]*\\([ \t]*[A-Za-z_][A-Za-z_0-9* \t]*\\)[ \t]*[A-Za-z_].*)$\n"
+ /* C functions */
+ "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$\n"
+ /* Objective-C class/protocol definitions */
+ "^(@(implementation|interface|protocol)[ \t].*)$",
+ REG_EXTENDED },
{ "pascal",
"^((procedure|function|constructor|destructor|interface|"
"implementation|initialization|finalization)[ \t]*.*)$"
@@ -1810,10 +1817,9 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
static int populate_from_stdin(struct diff_filespec *s)
{
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
size_t size = 0;
- strbuf_init(&buf, 0);
if (strbuf_read(&buf, 0, 0) < 0)
return error("error while reading from stdin %s",
strerror(errno));
@@ -1865,7 +1871,7 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
if (!s->sha1_valid ||
reuse_worktree_file(s->path, s->sha1, 0)) {
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
struct stat st;
int fd;
@@ -1908,7 +1914,6 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
/*
* Convert from working tree format to canonical git format
*/
- strbuf_init(&buf, 0);
if (convert_to_git(s->path, s->data, s->size, &buf, safe_crlf)) {
size_t size = 0;
munmap(s->data, s->size);
diff --git a/editor.c b/editor.c
index eebc3e95f..4d469d076 100644
--- a/editor.c
+++ b/editor.c
@@ -26,9 +26,8 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en
int i = 0;
int failed;
const char *args[6];
- struct strbuf arg0;
+ struct strbuf arg0 = STRBUF_INIT;
- strbuf_init(&arg0, 0);
if (strcspn(editor, "$ \t'") != len) {
/* there are specials */
strbuf_addf(&arg0, "%s \"$@\"", editor);
diff --git a/environment.c b/environment.c
index 0c6d11f6a..0693cd9a4 100644
--- a/environment.c
+++ b/environment.c
@@ -80,6 +80,11 @@ int is_bare_repository(void)
return is_bare_repository_cfg && !get_git_work_tree();
}
+int have_git_dir(void)
+{
+ return !!git_dir;
+}
+
const char *get_git_dir(void)
{
if (!git_dir)
diff --git a/exec_cmd.c b/exec_cmd.c
index ce6741eb6..cdd35f919 100644
--- a/exec_cmd.c
+++ b/exec_cmd.c
@@ -59,9 +59,7 @@ static void add_path(struct strbuf *out, const char *path)
void setup_path(void)
{
const char *old_path = getenv("PATH");
- struct strbuf new_path;
-
- strbuf_init(&new_path, 0);
+ struct strbuf new_path = STRBUF_INIT;
add_path(&new_path, argv_exec_path);
add_path(&new_path, getenv(EXEC_PATH_ENVIRONMENT));
diff --git a/fsck.c b/fsck.c
index 797e3178a..0cf5f012b 100644
--- a/fsck.c
+++ b/fsck.c
@@ -307,9 +307,8 @@ int fsck_error_function(struct object *obj, int type, const char *fmt, ...)
{
va_list ap;
int len;
- struct strbuf sb;
+ struct strbuf sb = STRBUF_INIT;
- strbuf_init(&sb, 0);
strbuf_addf(&sb, "object %s:", obj->sha1?sha1_to_hex(obj->sha1):"(null)");
va_start(ap, fmt);
diff --git a/git-compat-util.h b/git-compat-util.h
index 2ac832f3b..e20b1e858 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -85,6 +85,7 @@
#undef _XOPEN_SOURCE
#include <grp.h>
#define _XOPEN_SOURCE 600
+#include "compat/cygwin.h"
#else
#undef _ALL_SOURCE /* AIX 5.3L defines a struct list with _ALL_SOURCE. */
#include <grp.h>
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index b0d757db5..86290f63b 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -280,7 +280,7 @@ do_next () {
"$DOTEST"/amend || exit
read command sha1 rest < "$TODO"
case "$command" in
- '#'*|'')
+ '#'*|''|noop)
mark_action_done
;;
pick|p)
@@ -317,23 +317,28 @@ do_next () {
mark_action_done
make_squash_message $sha1 > "$MSG"
+ failed=f
+ author_script=$(get_author_ident_from_commit HEAD)
+ output git reset --soft HEAD^
+ pick_one -n $sha1 || failed=t
case "$(peek_next_command)" in
squash|s)
EDIT_COMMIT=
USE_OUTPUT=output
+ MSG_OPT=-F
+ MSG_FILE="$MSG"
cp "$MSG" "$SQUASH_MSG"
;;
*)
EDIT_COMMIT=-e
USE_OUTPUT=
+ MSG_OPT=
+ MSG_FILE=
rm -f "$SQUASH_MSG" || exit
+ cp "$MSG" "$GIT_DIR"/SQUASH_MSG
+ rm -f "$GIT_DIR"/MERGE_MSG || exit
;;
esac
-
- failed=f
- author_script=$(get_author_ident_from_commit HEAD)
- output git reset --soft HEAD^
- pick_one -n $sha1 || failed=t
echo "$author_script" > "$DOTEST"/author-script
if test $failed = f
then
@@ -342,7 +347,7 @@ do_next () {
GIT_AUTHOR_NAME="$GIT_AUTHOR_NAME" \
GIT_AUTHOR_EMAIL="$GIT_AUTHOR_EMAIL" \
GIT_AUTHOR_DATE="$GIT_AUTHOR_DATE" \
- $USE_OUTPUT git commit --no-verify -F "$MSG" $EDIT_COMMIT || failed=t
+ $USE_OUTPUT git commit --no-verify $MSG_OPT "$MSG_FILE" $EDIT_COMMIT || failed=t
fi
if test $failed = t
then
@@ -587,6 +592,7 @@ first and then run 'git rebase --continue' again."
--abbrev=7 --reverse --left-right --cherry-pick \
$UPSTREAM...$HEAD | \
sed -n "s/^>/pick /p" > "$TODO"
+ test -s "$TODO" || echo noop >> "$TODO"
cat >> "$TODO" << EOF
# Rebase $SHORTUPSTREAM..$SHORTHEAD onto $SHORTONTO
diff --git a/git-send-email.perl b/git-send-email.perl
index d2fd89907..bdbfac662 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -39,75 +39,40 @@ package main;
sub usage {
print <<EOT;
git send-email [options] <file | directory>...
-Options:
- --from Specify the "From:" line of the email to be sent.
- --to Specify the primary "To:" line of the email.
-
- --cc Specify an initial "Cc:" list for the entire series
- of emails.
-
- --cc-cmd Specify a command to execute per file which adds
- per file specific cc address entries
-
- --bcc Specify a list of email addresses that should be Bcc:
- on all the emails.
-
- --compose Use \$GIT_EDITOR, core.editor, \$EDITOR, or \$VISUAL to edit
- an introductory message for the patch series.
-
- --subject Specify the initial "Subject:" line.
- Only necessary if --compose is also set. If --compose
- is not set, this will be prompted for.
-
- --in-reply-to Specify the first "In-Reply-To:" header line.
- Only used if --compose is also set. If --compose is not
- set, this will be prompted for.
-
- --chain-reply-to If set, the replies will all be to the previous
- email sent, rather than to the first email sent.
- Defaults to on.
-
- --signed-off-cc Automatically add email addresses that appear in
- Signed-off-by: or Cc: lines to the cc: list. Defaults to on.
-
- --identity The configuration identity, a subsection to prioritise over
- the default section.
-
- --smtp-server If set, specifies the outgoing SMTP server to use.
- Defaults to localhost. Port number can be specified here with
- hostname:port format or by using --smtp-server-port option.
-
- --smtp-server-port Specify a port on the outgoing SMTP server to connect to.
-
- --smtp-user The username for SMTP-AUTH.
-
- --smtp-pass The password for SMTP-AUTH.
-
- --smtp-encryption Specify 'tls' for STARTTLS encryption, or 'ssl' for SSL.
- Any other value disables the feature.
-
- --smtp-ssl Synonym for '--smtp-encryption=ssl'. Deprecated.
-
- --suppress-cc Suppress the specified category of auto-CC. The category
- can be one of 'author' for the patch author, 'self' to
- avoid copying yourself, 'sob' for Signed-off-by lines,
- 'cccmd' for the output of the cccmd, or 'all' to suppress
- all of these.
-
- --suppress-from Suppress sending emails to yourself. Defaults to off.
-
- --thread Specify that the "In-Reply-To:" header should be set on all
- emails. Defaults to on.
-
- --quiet Make git-send-email less verbose. One line per email
- should be all that is output.
-
- --dry-run Do everything except actually send the emails.
-
- --envelope-sender Specify the envelope sender used to send the emails.
-
- --no-validate Don't perform any sanity checks on patches.
+ Composing:
+ --from <str> * Email From:
+ --to <str> * Email To:
+ --cc <str> * Email Cc:
+ --bcc <str> * Email Bcc:
+ --subject <str> * Email "Subject:"
+ --in-reply-to <str> * Email "In-Reply-To:"
+ --compose * Open an editor for introduction.
+
+ Sending:
+ --envelope-sender <str> * Email envelope sender.
+ --smtp-server <str:int> * Outgoing SMTP server to use. The port
+ is optional. Default 'localhost'.
+ --smtp-server-port <int> * Outgoing SMTP server port.
+ --smtp-user <str> * Username for SMTP-AUTH.
+ --smtp-pass <str> * Password for SMTP-AUTH; not necessary.
+ --smtp-encryption <str> * tls or ssl; anything else disables.
+ --smtp-ssl * Deprecated. Use '--smtp-encryption ssl'.
+
+ Automating:
+ --identity <str> * Use the sendemail.<id> options.
+ --cc-cmd <str> * Email Cc: via `<str> \$patch_path`
+ --suppress-cc <str> * author, self, sob, cccmd, all.
+ --[no-]signed-off-by-cc * Send to Cc: and Signed-off-by:
+ addresses. Default on.
+ --[no-]suppress-from * Send to self. Default off.
+ --[no-]chain-reply-to * Chain In-Reply-To: fields. Default on.
+ --[no-]thread * Use In-Reply-To: field. Default on.
+
+ Administering:
+ --quiet * Output one line of info per email.
+ --dry-run * Don't actually send the emails.
+ --[no-]validate * Perform patch sanity checks. Default on.
EOT
exit(1);
@@ -186,17 +151,19 @@ if ($@) {
my ($quiet, $dry_run) = (0, 0);
# Variables with corresponding config settings
-my ($thread, $chain_reply_to, $suppress_from, $signed_off_cc, $cc_cmd);
+my ($thread, $chain_reply_to, $suppress_from, $signed_off_by_cc, $cc_cmd);
my ($smtp_server, $smtp_server_port, $smtp_authuser, $smtp_encryption);
my ($identity, $aliasfiletype, @alias_files, @smtp_host_parts);
-my ($no_validate);
+my ($validate);
my (@suppress_cc);
my %config_bool_settings = (
"thread" => [\$thread, 1],
"chainreplyto" => [\$chain_reply_to, 1],
"suppressfrom" => [\$suppress_from, undef],
- "signedoffcc" => [\$signed_off_cc, undef],
+ "signedoffbycc" => [\$signed_off_by_cc, undef],
+ "signedoffcc" => [\$signed_off_by_cc, undef], # Deprecated
+ "validate" => [\$validate, 1],
);
my %config_settings = (
@@ -259,11 +226,11 @@ my $rc = GetOptions("sender|from=s" => \$sender,
"cc-cmd=s" => \$cc_cmd,
"suppress-from!" => \$suppress_from,
"suppress-cc=s" => \@suppress_cc,
- "signed-off-cc|signed-off-by-cc!" => \$signed_off_cc,
+ "signed-off-cc|signed-off-by-cc!" => \$signed_off_by_cc,
"dry-run" => \$dry_run,
"envelope-sender=s" => \$envelope_sender,
"thread!" => \$thread,
- "no-validate" => \$no_validate,
+ "validate!" => \$validate,
);
unless ($rc) {
@@ -335,7 +302,7 @@ if ($suppress_cc{'all'}) {
# If explicit old-style ones are specified, they trump --suppress-cc.
$suppress_cc{'self'} = $suppress_from if defined $suppress_from;
-$suppress_cc{'sob'} = !$signed_off_cc if defined $signed_off_cc;
+$suppress_cc{'sob'} = !$signed_off_by_cc if defined $signed_off_by_cc;
# Debugging, print out the suppressions.
if (0) {
@@ -416,7 +383,7 @@ for my $f (@ARGV) {
}
}
-if (!$no_validate) {
+if ($validate) {
foreach my $f (@files) {
unless (-p $f) {
my $error = validate_patch($f);
diff --git a/git-stash.sh b/git-stash.sh
index 42f626f9d..b9ace9970 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -145,16 +145,8 @@ show_stash () {
flags=--stat
fi
- if test $# = 0
- then
- set x "$ref_stash@{0}"
- shift
- fi
-
- s=$(git rev-parse --revs-only --no-flags "$@")
-
- w_commit=$(git rev-parse --verify "$s") &&
- b_commit=$(git rev-parse --verify "$s^") &&
+ w_commit=$(git rev-parse --verify --default $ref_stash "$@") &&
+ b_commit=$(git rev-parse --verify "$w_commit^") &&
git diff $flags $b_commit $w_commit
}
@@ -170,19 +162,13 @@ apply_stash () {
shift
esac
- if test $# = 0
- then
- set x "$ref_stash@{0}"
- shift
- fi
-
# current index state
c_tree=$(git write-tree) ||
die 'Cannot apply a stash in the middle of a merge'
# stash records the work tree, and is a merge between the
# base commit (first parent) and the index tree (second parent).
- s=$(git rev-parse --revs-only --no-flags "$@") &&
+ s=$(git rev-parse --verify --default $ref_stash "$@") &&
w_tree=$(git rev-parse --verify "$s:") &&
b_tree=$(git rev-parse --verify "$s^1:") &&
i_tree=$(git rev-parse --verify "$s^2:") ||
@@ -242,7 +228,7 @@ drop_stash () {
shift
fi
# Verify supplied argument looks like a stash entry
- s=$(git rev-parse --revs-only --no-flags "$@") &&
+ s=$(git rev-parse --verify "$@") &&
git rev-parse --verify "$s:" > /dev/null 2>&1 &&
git rev-parse --verify "$s^1:" > /dev/null 2>&1 &&
git rev-parse --verify "$s^2:" > /dev/null 2>&1 ||
diff --git a/git-svn.perl b/git-svn.perl
index 7609a8374..ef6d773df 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -66,7 +66,7 @@ my ($_stdin, $_help, $_edit,
$_version, $_fetch_all, $_no_rebase,
$_merge, $_strategy, $_dry_run, $_local,
$_prefix, $_no_checkout, $_url, $_verbose,
- $_git_format, $_commit_url);
+ $_git_format, $_commit_url, $_tag);
$Git::SVN::_follow_parent = 1;
my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
'config-dir=s' => \$Git::SVN::Ra::config_dir,
@@ -131,6 +131,15 @@ my %cmd = (
'revision|r=i' => \$_revision,
'no-rebase' => \$_no_rebase,
%cmt_opts, %fc_opts } ],
+ branch => [ \&cmd_branch,
+ 'Create a branch in the SVN repository',
+ { 'message|m=s' => \$_message,
+ 'dry-run|n' => \$_dry_run,
+ 'tag|t' => \$_tag } ],
+ tag => [ sub { $_tag = 1; cmd_branch(@_) },
+ 'Create a tag in the SVN repository',
+ { 'message|m=s' => \$_message,
+ 'dry-run|n' => \$_dry_run } ],
'set-tree' => [ \&cmd_set_tree,
"Set an SVN repository to a git tree-ish",
{ 'stdin|' => \$_stdin, %cmt_opts, %fc_opts, } ],
@@ -537,6 +546,42 @@ sub cmd_dcommit {
unlink $gs->{index};
}
+sub cmd_branch {
+ my ($branch_name, $head) = @_;
+
+ unless (defined $branch_name && length $branch_name) {
+ die(($_tag ? "tag" : "branch") . " name required\n");
+ }
+ $head ||= 'HEAD';
+
+ my ($src, $rev, undef, $gs) = working_head_info($head);
+
+ my $remote = Git::SVN::read_all_remotes()->{svn};
+ my $glob = $remote->{ $_tag ? 'tags' : 'branches' };
+ my ($lft, $rgt) = @{ $glob->{path} }{qw/left right/};
+ my $dst = join '/', $remote->{url}, $lft, $branch_name, ($rgt || ());
+
+ my $ctx = SVN::Client->new(
+ auth => Git::SVN::Ra::_auth_providers(),
+ log_msg => sub {
+ ${ $_[0] } = defined $_message
+ ? $_message
+ : 'Create ' . ($_tag ? 'tag ' : 'branch ' )
+ . $branch_name;
+ },
+ );
+
+ eval {
+ $ctx->ls($dst, 'HEAD', 0);
+ } and die "branch ${branch_name} already exists\n";
+
+ print "Copying ${src} at r${rev} to ${dst}...\n";
+ $ctx->copy($src, $rev, $dst)
+ unless $_dry_run;
+
+ $gs->fetch_all;
+}
+
sub cmd_find_rev {
my $revision_or_hash = shift or die "SVN or git revision required ",
"as a command-line argument\n";
diff --git a/git.c b/git.c
index f4b0cf611..89feb0b6d 100644
--- a/git.c
+++ b/git.c
@@ -389,10 +389,9 @@ static void handle_internal_command(int argc, const char **argv)
static void execv_dashed_external(const char **argv)
{
- struct strbuf cmd;
+ struct strbuf cmd = STRBUF_INIT;
const char *tmp;
- strbuf_init(&cmd, 0);
strbuf_addf(&cmd, "git-%s", argv[0]);
/*
diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css
index 07f5b5378..a01eac814 100644
--- a/gitweb/gitweb.css
+++ b/gitweb/gitweb.css
@@ -435,6 +435,10 @@ div.search {
right: 12px
}
+p.projsearch {
+ text-align: center;
+}
+
td.linenr {
text-align: right;
}
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 83f810ad4..11168006c 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -282,6 +282,44 @@ our %feature = (
'forks' => {
'override' => 0,
'default' => [0]},
+
+ # Insert custom links to the action bar of all project pages.
+ # This enables you mainly to link to third-party scripts integrating
+ # into gitweb; e.g. git-browser for graphical history representation
+ # or custom web-based repository administration interface.
+
+ # The 'default' value consists of a list of triplets in the form
+ # (label, link, position) where position is the label after which
+ # to inster the link and link is a format string where %n expands
+ # to the project name, %f to the project path within the filesystem,
+ # %h to the current hash (h gitweb parameter) and %b to the current
+ # hash base (hb gitweb parameter).
+
+ # To enable system wide have in $GITWEB_CONFIG e.g.
+ # $feature{'actions'}{'default'} = [('graphiclog',
+ # '/git-browser/by-commit.html?r=%n', 'summary')];
+ # Project specific override is not supported.
+ 'actions' => {
+ 'override' => 0,
+ 'default' => []},
+
+ # Allow gitweb scan project content tags described in ctags/
+ # of project repository, and display the popular Web 2.0-ish
+ # "tag cloud" near the project list. Note that this is something
+ # COMPLETELY different from the normal Git tags.
+
+ # gitweb by itself can show existing tags, but it does not handle
+ # tagging itself; you need an external application for that.
+ # For an example script, check Girocco's cgi/tagproj.cgi.
+ # You may want to install the HTML::TagCloud Perl module to get
+ # a pretty tag cloud instead of just a list of tags.
+
+ # To enable system wide have in $GITWEB_CONFIG
+ # $feature{'ctags'}{'default'} = ['path_to_tag_script'];
+ # Project specific override is not supported.
+ 'ctags' => {
+ 'override' => 0,
+ 'default' => [0]},
);
sub gitweb_check_feature {
@@ -1762,6 +1800,67 @@ sub git_get_project_description {
return $descr;
}
+sub git_get_project_ctags {
+ my $path = shift;
+ my $ctags = {};
+
+ $git_dir = "$projectroot/$path";
+ foreach (<$git_dir/ctags/*>) {
+ open CT, $_ or next;
+ my $val = <CT>;
+ chomp $val;
+ close CT;
+ my $ctag = $_; $ctag =~ s#.*/##;
+ $ctags->{$ctag} = $val;
+ }
+ $ctags;
+}
+
+sub git_populate_project_tagcloud {
+ my $ctags = shift;
+
+ # First, merge different-cased tags; tags vote on casing
+ my %ctags_lc;
+ foreach (keys %$ctags) {
+ $ctags_lc{lc $_}->{count} += $ctags->{$_};
+ if (not $ctags_lc{lc $_}->{topcount}
+ or $ctags_lc{lc $_}->{topcount} < $ctags->{$_}) {
+ $ctags_lc{lc $_}->{topcount} = $ctags->{$_};
+ $ctags_lc{lc $_}->{topname} = $_;
+ }
+ }
+
+ my $cloud;
+ if (eval { require HTML::TagCloud; 1; }) {
+ $cloud = HTML::TagCloud->new;
+ foreach (sort keys %ctags_lc) {
+ # Pad the title with spaces so that the cloud looks
+ # less crammed.
+ my $title = $ctags_lc{$_}->{topname};
+ $title =~ s/ /&nbsp;/g;
+ $title =~ s/^/&nbsp;/g;
+ $title =~ s/$/&nbsp;/g;
+ $cloud->add($title, $home_link."?by_tag=".$_, $ctags_lc{$_}->{count});
+ }
+ } else {
+ $cloud = \%ctags_lc;
+ }
+ $cloud;
+}
+
+sub git_show_project_tagcloud {
+ my ($cloud, $count) = @_;
+ print STDERR ref($cloud)."..\n";
+ if (ref $cloud eq 'HTML::TagCloud') {
+ return $cloud->html_and_css($count);
+ } else {
+ my @tags = sort { $cloud->{$a}->{count} <=> $cloud->{$b}->{count} } keys %$cloud;
+ return '<p align="center">' . join (', ', map {
+ "<a href=\"$home_link?by_tag=$_\">$cloud->{$_}->{topname}</a>"
+ } splice(@tags, 0, $count)) . '</p>';
+ }
+}
+
sub git_get_project_url_list {
my $path = shift;
@@ -1810,9 +1909,7 @@ sub git_get_projects_list {
my $subdir = substr($File::Find::name, $pfxlen + 1);
# we check related file in $projectroot
- if ($check_forks and $subdir =~ m#/.#) {
- $File::Find::prune = 1;
- } elsif (check_export_ok("$projectroot/$filter/$subdir")) {
+ if (check_export_ok("$projectroot/$filter/$subdir")) {
push @list, { path => ($filter ? "$filter/" : '') . $subdir };
$File::Find::prune = 1;
}
@@ -2764,13 +2861,26 @@ sub git_print_page_nav {
}
}
}
+
$arg{'tree'}{'hash'} = $treehead if defined $treehead;
$arg{'tree'}{'hash_base'} = $treebase if defined $treebase;
+ my @actions = gitweb_check_feature('actions');
+ while (@actions) {
+ my ($label, $link, $pos) = (shift(@actions), shift(@actions), shift(@actions));
+ @navs = map { $_ eq $pos ? ($_, $label) : $_ } @navs;
+ # munch munch
+ $link =~ s#%n#$project#g;
+ $link =~ s#%f#$git_dir#g;
+ $treehead ? $link =~ s#%h#$treehead#g : $link =~ s#%h##g;
+ $treebase ? $link =~ s#%b#$treebase#g : $link =~ s#%b##g;
+ $arg{$label}{'_href'} = $link;
+ }
+
print "<div class=\"page_nav\">\n" .
(join " | ",
map { $_ eq $current ?
- $_ : $cgi->a({-href => href(%{$arg{$_}})}, "$_")
+ $_ : $cgi->a({-href => ($arg{$_}{_href} ? $arg{$_}{_href} : href(%{$arg{$_}}))}, "$_")
} @navs);
print "<br/>\n$extra<br/>\n" .
"</div>\n";
@@ -3580,6 +3690,7 @@ sub fill_project_list_info {
my ($projlist, $check_forks) = @_;
my @projects;
+ my $show_ctags = gitweb_check_feature('ctags');
PROJECT:
foreach my $pr (@$projlist) {
my (@activity) = git_get_last_activity($pr->{'path'});
@@ -3606,25 +3717,20 @@ sub fill_project_list_info {
$pr->{'forks'} = 0;
}
}
+ $show_ctags and $pr->{'ctags'} = git_get_project_ctags($pr->{'path'});
push @projects, $pr;
}
return @projects;
}
-# print 'sort by' <th> element, either sorting by $key if $name eq $order
-# (changing $list), or generating 'sort by $name' replay link otherwise
+# print 'sort by' <th> element, generating 'sort by $name' replay link
+# if that order is not selected
sub print_sort_th {
- my ($str_sort, $name, $order, $key, $header, $list) = @_;
- $key ||= $name;
+ my ($name, $order, $header) = @_;
$header ||= ucfirst($name);
if ($order eq $name) {
- if ($str_sort) {
- @$list = sort {$a->{$key} cmp $b->{$key}} @$list;
- } else {
- @$list = sort {$a->{$key} <=> $b->{$key}} @$list;
- }
print "<th>$header</th>\n";
} else {
print "<th>" .
@@ -3634,15 +3740,8 @@ sub print_sort_th {
}
}
-sub print_sort_th_str {
- print_sort_th(1, @_);
-}
-
-sub print_sort_th_num {
- print_sort_th(0, @_);
-}
-
sub git_project_list_body {
+ # actually uses global variable $project
my ($projlist, $order, $from, $to, $extra, $no_header) = @_;
my ($check_forks) = gitweb_check_feature('forks');
@@ -3652,26 +3751,60 @@ sub git_project_list_body {
$from = 0 unless defined $from;
$to = $#projects if (!defined $to || $#projects < $to);
+ my %order_info = (
+ project => { key => 'path', type => 'str' },
+ descr => { key => 'descr_long', type => 'str' },
+ owner => { key => 'owner', type => 'str' },
+ age => { key => 'age', type => 'num' }
+ );
+ my $oi = $order_info{$order};
+ if ($oi->{'type'} eq 'str') {
+ @projects = sort {$a->{$oi->{'key'}} cmp $b->{$oi->{'key'}}} @projects;
+ } else {
+ @projects = sort {$a->{$oi->{'key'}} <=> $b->{$oi->{'key'}}} @projects;
+ }
+
+ my $show_ctags = gitweb_check_feature('ctags');
+ if ($show_ctags) {
+ my %ctags;
+ foreach my $p (@projects) {
+ foreach my $ct (keys %{$p->{'ctags'}}) {
+ $ctags{$ct} += $p->{'ctags'}->{$ct};
+ }
+ }
+ my $cloud = git_populate_project_tagcloud(\%ctags);
+ print git_show_project_tagcloud($cloud, 64);
+ }
+
print "<table class=\"project_list\">\n";
unless ($no_header) {
print "<tr>\n";
if ($check_forks) {
print "<th></th>\n";
}
- print_sort_th_str('project', $order, 'path',
- 'Project', \@projects);
- print_sort_th_str('descr', $order, 'descr_long',
- 'Description', \@projects);
- print_sort_th_str('owner', $order, 'owner',
- 'Owner', \@projects);
- print_sort_th_num('age', $order, 'age',
- 'Last Change', \@projects);
+ print_sort_th('project', $order, 'Project');
+ print_sort_th('descr', $order, 'Description');
+ print_sort_th('owner', $order, 'Owner');
+ print_sort_th('age', $order, 'Last Change');
print "<th></th>\n" . # for links
"</tr>\n";
}
my $alternate = 1;
+ my $tagfilter = $cgi->param('by_tag');
for (my $i = $from; $i <= $to; $i++) {
my $pr = $projects[$i];
+
+ next if $tagfilter and $show_ctags and not grep { lc $_ eq lc $tagfilter } keys %{$pr->{'ctags'}};
+ next if $searchtext and not $pr->{'path'} =~ /$searchtext/
+ and not $pr->{'descr_long'} =~ /$searchtext/;
+ # Weed out forks or non-matching entries of search
+ if ($check_forks) {
+ my $forkbase = $project; $forkbase ||= ''; $forkbase =~ s#\.git$#/#;
+ $forkbase="^$forkbase" if $forkbase;
+ next if not $searchtext and not $tagfilter and $show_ctags
+ and $pr->{'path'} =~ m#$forkbase.*/.*#; # regexp-safe
+ }
+
if ($alternate) {
print "<tr class=\"dark\">\n";
} else {
@@ -4006,6 +4139,11 @@ sub git_project_list {
close $fd;
print "</div>\n";
}
+ print $cgi->startform(-method => "get") .
+ "<p class=\"projsearch\">Search:\n" .
+ $cgi->textfield(-name => "s", -value => $searchtext) . "\n" .
+ "</p>" .
+ $cgi->end_form() . "\n";
git_project_list_body(\@list, $order);
git_footer_html();
}
@@ -4093,6 +4231,20 @@ sub git_summary {
print "<tr class=\"metadata_url\"><td>$url_tag</td><td>$git_url</td></tr>\n";
$url_tag = "";
}
+
+ # Tag cloud
+ my $show_ctags = (gitweb_check_feature('ctags'))[0];
+ if ($show_ctags) {
+ my $ctags = git_get_project_ctags($project);
+ my $cloud = git_populate_project_tagcloud($ctags);
+ print "<tr id=\"metadata_ctags\"><td>Content tags:<br />";
+ print "</td>\n<td>" unless %$ctags;
+ print "<form action=\"$show_ctags\" method=\"post\"><input type=\"hidden\" name=\"p\" value=\"$project\" />Add: <input type=\"text\" name=\"t\" size=\"8\" /></form>";
+ print "</td>\n<td>" if %$ctags;
+ print git_show_project_tagcloud($cloud, 48);
+ print "</td></tr>";
+ }
+
print "</table>\n";
if (-s "$projectroot/$project/README.html") {
@@ -4131,10 +4283,10 @@ sub git_summary {
if (@forklist) {
git_print_header_div('forks');
- git_project_list_body(\@forklist, undef, 0, 15,
+ git_project_list_body(\@forklist, 'age', 0, 15,
$#forklist <= 15 ? undef :
$cgi->a({-href => href(action=>"forks")}, "..."),
- 'noheader');
+ 'no_header');
}
git_footer_html();
diff --git a/graph.c b/graph.c
index 5f821706c..162a516ee 100644
--- a/graph.c
+++ b/graph.c
@@ -1010,14 +1010,12 @@ int graph_is_commit_finished(struct git_graph const *graph)
void graph_show_commit(struct git_graph *graph)
{
- struct strbuf msgbuf;
+ struct strbuf msgbuf = STRBUF_INIT;
int shown_commit_line = 0;
if (!graph)
return;
- strbuf_init(&msgbuf, 0);
-
while (!shown_commit_line) {
shown_commit_line = graph_next_line(graph, &msgbuf);
fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
@@ -1031,12 +1029,11 @@ void graph_show_commit(struct git_graph *graph)
void graph_show_oneline(struct git_graph *graph)
{
- struct strbuf msgbuf;
+ struct strbuf msgbuf = STRBUF_INIT;
if (!graph)
return;
- strbuf_init(&msgbuf, 0);
graph_next_line(graph, &msgbuf);
fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
strbuf_release(&msgbuf);
@@ -1044,12 +1041,11 @@ void graph_show_oneline(struct git_graph *graph)
void graph_show_padding(struct git_graph *graph)
{
- struct strbuf msgbuf;
+ struct strbuf msgbuf = STRBUF_INIT;
if (!graph)
return;
- strbuf_init(&msgbuf, 0);
graph_padding_line(graph, &msgbuf);
fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
strbuf_release(&msgbuf);
@@ -1057,7 +1053,7 @@ void graph_show_padding(struct git_graph *graph)
int graph_show_remainder(struct git_graph *graph)
{
- struct strbuf msgbuf;
+ struct strbuf msgbuf = STRBUF_INIT;
int shown = 0;
if (!graph)
@@ -1066,7 +1062,6 @@ int graph_show_remainder(struct git_graph *graph)
if (graph_is_commit_finished(graph))
return 0;
- strbuf_init(&msgbuf, 0);
for (;;) {
graph_next_line(graph, &msgbuf);
fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
diff --git a/grep.c b/grep.c
index 706351197..e2c190a7f 100644
--- a/grep.c
+++ b/grep.c
@@ -239,6 +239,8 @@ static int word_char(char ch)
static void show_line(struct grep_opt *opt, const char *bol, const char *eol,
const char *name, unsigned lno, char sign)
{
+ if (opt->null_following_name)
+ sign = '\0';
if (opt->pathname)
printf("%s%c", name, sign);
if (opt->linenum)
@@ -246,6 +248,11 @@ static void show_line(struct grep_opt *opt, const char *bol, const char *eol,
printf("%.*s\n", (int)(eol-bol), bol);
}
+static void show_name(struct grep_opt *opt, const char *name)
+{
+ printf("%s%c", name, opt->null_following_name ? '\0' : '\n');
+}
+
static int fixmatch(const char *pattern, char *line, regmatch_t *match)
{
char *hit = strstr(line, pattern);
@@ -489,7 +496,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
return 1;
}
if (opt->name_only) {
- printf("%s\n", name);
+ show_name(opt, name);
return 1;
}
/* Hit at this line. If we haven't shown the
@@ -555,7 +562,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
return 0;
if (opt->unmatch_name_only) {
/* We did not see any hit, so we want to show this */
- printf("%s\n", name);
+ show_name(opt, name);
return 1;
}
@@ -565,7 +572,8 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
* make it another option? For now suppress them.
*/
if (opt->count && count)
- printf("%s:%u\n", name, count);
+ printf("%s%c%u\n", name,
+ opt->null_following_name ? '\0' : ':', count);
return !!last_hit;
}
diff --git a/grep.h b/grep.h
index 59b3f871e..45a222d90 100644
--- a/grep.h
+++ b/grep.h
@@ -74,6 +74,7 @@ struct grep_opt {
unsigned extended:1;
unsigned relative:1;
unsigned pathname:1;
+ unsigned null_following_name:1;
int regflags;
unsigned pre_context;
unsigned post_context;
diff --git a/hash-object.c b/hash-object.c
index a4d127cf7..20937ff94 100644
--- a/hash-object.c
+++ b/hash-object.c
@@ -34,10 +34,8 @@ static void hash_object(const char *path, const char *type, int write_object,
static void hash_stdin_paths(const char *type, int write_objects)
{
- struct strbuf buf, nbuf;
+ struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;
- strbuf_init(&buf, 0);
- strbuf_init(&nbuf, 0);
while (strbuf_getline(&buf, stdin, '\n') != EOF) {
if (buf.buf[0] == '"') {
strbuf_reset(&nbuf);
diff --git a/imap-send.c b/imap-send.c
index af7e08c09..3703dbd1a 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -1266,10 +1266,9 @@ static int imap_store_msg(struct store *gctx, struct msg_data *data, int *uid)
static int read_message(FILE *f, struct msg_data *msg)
{
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
memset(msg, 0, sizeof(*msg));
- strbuf_init(&buf, 0);
do {
if (strbuf_fread(&buf, CHUNKSIZE, f) <= 0)
diff --git a/index-pack.c b/index-pack.c
index 2e4c0885f..aec11cb94 100644
--- a/index-pack.c
+++ b/index-pack.c
@@ -365,8 +365,11 @@ static void *get_data_from_pack(struct object_entry *obj)
data = src;
do {
ssize_t n = pread(pack_fd, data + rdy, len - rdy, from + rdy);
- if (n <= 0)
+ if (n < 0)
die("cannot pread pack file: %s", strerror(errno));
+ if (!n)
+ die("premature end of pack file, %lu bytes missing",
+ len - rdy);
rdy += n;
} while (rdy < len);
data = xmalloc(obj->size);
@@ -704,6 +707,7 @@ static struct object_entry *append_obj_to_pack(struct sha1file *f,
obj[1].idx.offset = obj[0].idx.offset + n;
obj[1].idx.offset += write_compressed(f, buf, size);
obj[0].idx.crc32 = crc32_end(f);
+ sha1flush(f);
hashcpy(obj->idx.sha1, sha1);
return obj;
}
@@ -786,7 +790,6 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
err = close(output_fd);
if (err)
die("error while closing pack file: %s", strerror(errno));
- chmod(curr_pack_name, 0444);
}
if (keep_msg) {
@@ -820,8 +823,9 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
if (move_temp_to_file(curr_pack_name, final_pack_name))
die("cannot store pack file");
}
+ if (from_stdin)
+ chmod(final_pack_name, 0444);
- chmod(curr_index_name, 0444);
if (final_index_name != curr_index_name) {
if (!final_index_name) {
snprintf(name, sizeof(name), "%s/pack/pack-%s.idx",
@@ -831,6 +835,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
if (move_temp_to_file(curr_index_name, final_index_name))
die("cannot store index file");
}
+ chmod(final_index_name, 0444);
if (!from_stdin) {
printf("%s\n", sha1_to_hex(sha1));
diff --git a/log-tree.c b/log-tree.c
index 2c1f3e673..cec3c0613 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -252,7 +252,7 @@ void log_write_email_headers(struct rev_info *opt, const char *name,
void show_log(struct rev_info *opt)
{
- struct strbuf msgbuf;
+ struct strbuf msgbuf = STRBUF_INIT;
struct log_info *log = opt->loginfo;
struct commit *commit = log->commit, *parent = log->parent;
int abbrev = opt->diffopt.abbrev;
@@ -381,7 +381,6 @@ void show_log(struct rev_info *opt)
/*
* And then the pretty-printed message itself
*/
- strbuf_init(&msgbuf, 0);
if (need_8bit_cte >= 0)
need_8bit_cte = has_non_ascii(opt->add_signoff);
pretty_print_commit(opt->commit_format, commit, &msgbuf,
diff --git a/merge-recursive.c b/merge-recursive.c
index 6bc3eac85..7472d3ecc 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -498,8 +498,7 @@ static void update_file_flags(struct merge_options *o,
if (type != OBJ_BLOB)
die("blob expected for %s '%s'", sha1_to_hex(sha), path);
if (S_ISREG(mode)) {
- struct strbuf strbuf;
- strbuf_init(&strbuf, 0);
+ struct strbuf strbuf = STRBUF_INIT;
if (convert_to_working_tree(path, buf, size, &strbuf)) {
free(buf);
size = strbuf.len;
@@ -1333,7 +1332,7 @@ static int merge_recursive_config(const char *var, const char *value, void *cb)
o->merge_rename_limit = git_config_int(var, value);
return 0;
}
- return git_default_config(var, value, cb);
+ return git_xmerge_config(var, value, cb);
}
void init_merge_options(struct merge_options *o)
diff --git a/merge-tree.c b/merge-tree.c
index 02fc10f7e..2d1413efb 100644
--- a/merge-tree.c
+++ b/merge-tree.c
@@ -158,9 +158,8 @@ static int same_entry(struct name_entry *a, struct name_entry *b)
static struct merge_list *create_entry(unsigned stage, unsigned mode, const unsigned char *sha1, const char *path)
{
- struct merge_list *res = xmalloc(sizeof(*res));
+ struct merge_list *res = xcalloc(1, sizeof(*res));
- memset(res, 0, sizeof(*res));
res->stage = stage;
res->path = path;
res->mode = mode;
diff --git a/mktag.c b/mktag.c
index 0b34341f7..ba3d495e0 100644
--- a/mktag.c
+++ b/mktag.c
@@ -153,7 +153,7 @@ static int verify_tag(char *buffer, unsigned long size)
int main(int argc, char **argv)
{
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
unsigned char result_sha1[20];
if (argc != 1)
@@ -161,7 +161,6 @@ int main(int argc, char **argv)
setup_git_directory();
- strbuf_init(&buf, 0);
if (strbuf_read(&buf, 0, 4096) < 0) {
die("could not read from stdin");
}
diff --git a/mktree.c b/mktree.c
index e0da110a9..514fd9b15 100644
--- a/mktree.c
+++ b/mktree.c
@@ -65,8 +65,8 @@ static const char mktree_usage[] = "git-mktree [-z]";
int main(int ac, char **av)
{
- struct strbuf sb;
- struct strbuf p_uq;
+ struct strbuf sb = STRBUF_INIT;
+ struct strbuf p_uq = STRBUF_INIT;
unsigned char sha1[20];
int line_termination = '\n';
@@ -82,8 +82,6 @@ int main(int ac, char **av)
av++;
}
- strbuf_init(&sb, 0);
- strbuf_init(&p_uq, 0);
while (strbuf_getline(&sb, stdin, line_termination) != EOF) {
char *ptr, *ntr;
unsigned mode;
diff --git a/pretty.c b/pretty.c
index 8beafa08d..1e7994333 100644
--- a/pretty.c
+++ b/pretty.c
@@ -234,7 +234,7 @@ static char *get_header(const struct commit *commit, const char *key)
static char *replace_encoding_header(char *buf, const char *encoding)
{
- struct strbuf tmp;
+ struct strbuf tmp = STRBUF_INIT;
size_t start, len;
char *cp = buf;
@@ -250,7 +250,6 @@ static char *replace_encoding_header(char *buf, const char *encoding)
return buf; /* should not happen but be defensive */
len = cp + 1 - (buf + start);
- strbuf_init(&tmp, 0);
strbuf_attach(&tmp, buf, strlen(buf), strlen(buf) + 1);
if (is_encoding_utf8(encoding)) {
/* we have re-coded to UTF-8; drop the header */
diff --git a/read-cache.c b/read-cache.c
index 901064bf1..c229fd4d0 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -13,6 +13,7 @@
#include "diff.h"
#include "diffcore.h"
#include "revision.h"
+#include "blob.h"
/* Index extensions.
*
@@ -511,6 +512,14 @@ static struct cache_entry *create_alias_ce(struct cache_entry *ce, struct cache_
return new;
}
+static void record_intent_to_add(struct cache_entry *ce)
+{
+ unsigned char sha1[20];
+ if (write_sha1_file("", 0, blob_type, sha1))
+ die("cannot create an empty blob in the object database");
+ hashcpy(ce->sha1, sha1);
+}
+
int add_to_index(struct index_state *istate, const char *path, struct stat *st, int flags)
{
int size, namelen, was_same;
@@ -519,6 +528,9 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY;
int verbose = flags & (ADD_CACHE_VERBOSE | ADD_CACHE_PRETEND);
int pretend = flags & ADD_CACHE_PRETEND;
+ int intent_only = flags & ADD_CACHE_INTENT;
+ int add_option = (ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE|
+ (intent_only ? ADD_CACHE_NEW_ONLY : 0));
if (!S_ISREG(st_mode) && !S_ISLNK(st_mode) && !S_ISDIR(st_mode))
return error("%s: can only add regular files, symbolic links or git-directories", path);
@@ -532,7 +544,8 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
ce = xcalloc(1, size);
memcpy(ce->name, path, namelen);
ce->ce_flags = namelen;
- fill_stat_cache_info(ce, st);
+ if (!intent_only)
+ fill_stat_cache_info(ce, st);
if (trust_executable_bit && has_symlinks)
ce->ce_mode = create_ce_mode(st_mode);
@@ -555,8 +568,12 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
alias->ce_flags |= CE_ADDED;
return 0;
}
- if (index_path(ce->sha1, path, st, 1))
- return error("unable to index file %s", path);
+ if (!intent_only) {
+ if (index_path(ce->sha1, path, st, 1))
+ return error("unable to index file %s", path);
+ } else
+ record_intent_to_add(ce);
+
if (ignore_case && alias && different_name(ce, alias))
ce = create_alias_ce(ce, alias);
ce->ce_flags |= CE_ADDED;
@@ -569,7 +586,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
if (pretend)
;
- else if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
+ else if (add_index_entry(istate, ce, add_option))
return error("unable to add %s to index",path);
if (verbose && !was_same)
printf("add '%s'\n", path);
@@ -591,8 +608,10 @@ struct cache_entry *make_cache_entry(unsigned int mode,
int size, len;
struct cache_entry *ce;
- if (!verify_path(path))
+ if (!verify_path(path)) {
+ error("Invalid path '%s'", path);
return NULL;
+ }
len = strlen(path);
size = cache_entry_size(len);
@@ -848,13 +867,15 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
int ok_to_add = option & ADD_CACHE_OK_TO_ADD;
int ok_to_replace = option & ADD_CACHE_OK_TO_REPLACE;
int skip_df_check = option & ADD_CACHE_SKIP_DFCHECK;
+ int new_only = option & ADD_CACHE_NEW_ONLY;
cache_tree_invalidate_path(istate->cache_tree, ce->name);
pos = index_name_pos(istate, ce->name, ce->ce_flags);
/* existing match? Just replace it. */
if (pos >= 0) {
- replace_index_entry(istate, pos, ce);
+ if (!new_only)
+ replace_index_entry(istate, pos, ce);
return 0;
}
pos = -pos-1;
@@ -874,7 +895,7 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
if (!ok_to_add)
return -1;
if (!verify_path(ce->name))
- return -1;
+ return error("Invalid path '%s'", ce->name);
if (!skip_df_check &&
check_file_directory_conflict(istate, ce, pos, ok_to_replace)) {
@@ -1446,9 +1467,8 @@ int write_index(const struct index_state *istate, int newfd)
/* Write extension data here */
if (istate->cache_tree) {
- struct strbuf sb;
+ struct strbuf sb = STRBUF_INIT;
- strbuf_init(&sb, 0);
cache_tree_write(&sb, istate->cache_tree);
err = write_index_ext_header(&c, newfd, CACHE_EXT_TREE, sb.len) < 0
|| ce_write(&c, newfd, sb.buf, sb.len) < 0;
diff --git a/remote.c b/remote.c
index c45d96e98..8a04066d6 100644
--- a/remote.c
+++ b/remote.c
@@ -245,7 +245,7 @@ static void read_branches_file(struct remote *remote)
{
const char *slash = strchr(remote->name, '/');
char *frag;
- struct strbuf branch;
+ struct strbuf branch = STRBUF_INIT;
int n = slash ? slash - remote->name : 1000;
FILE *f = fopen(git_path("branches/%.*s", n, remote->name), "r");
char *s, *p;
@@ -283,7 +283,6 @@ static void read_branches_file(struct remote *remote)
* #branch specified. The "master" (or specified) branch is
* fetched and stored in the local branch of the same name.
*/
- strbuf_init(&branch, 0);
frag = strchr(p, '#');
if (frag) {
*(frag++) = '\0';
@@ -342,13 +341,14 @@ static int handle_config(const char *key, const char *value, void *cb)
if (prefixcmp(key, "remote."))
return 0;
name = key + 7;
+ if (*name == '/') {
+ warning("Config remote shorthand cannot begin with '/': %s",
+ name);
+ return 0;
+ }
subkey = strrchr(name, '.');
if (!subkey)
return error("Config with no key for remote %s", name);
- if (*subkey == '/') {
- warning("Config remote shorthand cannot begin with '/': %s", name);
- return 0;
- }
remote = make_remote(name, subkey - name);
if (!strcmp(subkey, ".mirror"))
remote->mirror = git_config_bool(key, value);
@@ -751,8 +751,7 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec)
struct ref *alloc_ref(unsigned namelen)
{
- struct ref *ret = xmalloc(sizeof(struct ref) + namelen);
- memset(ret, 0, sizeof(struct ref) + namelen);
+ struct ref *ret = xcalloc(1, sizeof(struct ref) + namelen);
return ret;
}
diff --git a/rerere.c b/rerere.c
index 121f91141..5bb5316cd 100644
--- a/rerere.c
+++ b/rerere.c
@@ -79,7 +79,7 @@ static int handle_file(const char *path,
enum {
RR_CONTEXT = 0, RR_SIDE_1, RR_SIDE_2, RR_ORIGINAL,
} hunk = RR_CONTEXT;
- struct strbuf one, two;
+ struct strbuf one = STRBUF_INIT, two = STRBUF_INIT;
FILE *f = fopen(path, "r");
FILE *out = NULL;
@@ -97,8 +97,6 @@ static int handle_file(const char *path,
if (sha1)
git_SHA1_Init(&ctx);
- strbuf_init(&one, 0);
- strbuf_init(&two, 0);
while (fgets(buf, sizeof(buf), f)) {
if (!prefixcmp(buf, "<<<<<<< ")) {
if (hunk != RR_CONTEXT)
diff --git a/sha1_file.c b/sha1_file.c
index 751598786..70bb453be 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1571,11 +1571,9 @@ static void *cache_or_unpack_entry(struct packed_git *p, off_t base_offset,
struct delta_base_cache_entry *ent = delta_base_cache + hash;
ret = ent->data;
- if (ret && ent->p == p && ent->base_offset == base_offset)
- goto found_cache_entry;
- return unpack_entry(p, base_offset, type, base_size);
+ if (!ret || ent->p != p || ent->base_offset != base_offset)
+ return unpack_entry(p, base_offset, type, base_size);
-found_cache_entry:
if (!keep_cache) {
ent->data = NULL;
ent->lru.next->prev = ent->lru.prev;
@@ -2335,6 +2333,7 @@ int force_object_loose(const unsigned char *sha1, time_t mtime)
enum object_type type;
char hdr[32];
int hdrlen;
+ int ret;
if (has_loose_object(sha1))
return 0;
@@ -2342,7 +2341,10 @@ int force_object_loose(const unsigned char *sha1, time_t mtime)
if (!buf)
return error("cannot read sha1_file for %s", sha1_to_hex(sha1));
hdrlen = sprintf(hdr, "%s %lu", typename(type), len) + 1;
- return write_loose_object(sha1, hdr, hdrlen, buf, len, mtime);
+ ret = write_loose_object(sha1, hdr, hdrlen, buf, len, mtime);
+ free(buf);
+
+ return ret;
}
int has_pack_index(const unsigned char *sha1)
@@ -2388,8 +2390,7 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size,
* Convert blobs to git internal format
*/
if ((type == OBJ_BLOB) && path) {
- struct strbuf nbuf;
- strbuf_init(&nbuf, 0);
+ struct strbuf nbuf = STRBUF_INIT;
if (convert_to_git(path, buf, size, &nbuf,
write_object ? safe_crlf : 0)) {
buf = strbuf_detach(&nbuf, &size);
@@ -2413,8 +2414,7 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
size_t size = xsize_t(st->st_size);
if (!S_ISREG(st->st_mode)) {
- struct strbuf sbuf;
- strbuf_init(&sbuf, 0);
+ struct strbuf sbuf = STRBUF_INIT;
if (strbuf_read(&sbuf, fd, 4096) >= 0)
ret = index_mem(sha1, sbuf.buf, sbuf.len, write_object,
type, path);
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index 620da5b32..5ac0a273a 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -167,4 +167,36 @@ test_expect_success 'init with --template (blank)' '
! test -f template-blank/.git/info/exclude
'
+test_expect_success 'init --bare/--shared overrides system/global config' '
+ (
+ HOME="`pwd`" &&
+ export HOME &&
+ test_config="$HOME"/.gitconfig &&
+ unset GIT_CONFIG_NOGLOBAL &&
+ git config -f "$test_config" core.bare false &&
+ git config -f "$test_config" core.sharedRepository 0640 &&
+ mkdir init-bare-shared-override &&
+ cd init-bare-shared-override &&
+ git init --bare --shared=0666
+ ) &&
+ check_config init-bare-shared-override true unset &&
+ test x0666 = \
+ x`git config -f init-bare-shared-override/config core.sharedRepository`
+'
+
+test_expect_success 'init honors global core.sharedRepository' '
+ (
+ HOME="`pwd`" &&
+ export HOME &&
+ test_config="$HOME"/.gitconfig &&
+ unset GIT_CONFIG_NOGLOBAL &&
+ git config -f "$test_config" core.sharedRepository 0666 &&
+ mkdir shared-honor-global &&
+ cd shared-honor-global &&
+ git init
+ ) &&
+ test x0666 = \
+ x`git config -f shared-honor-global/.git/config core.sharedRepository`
+'
+
test_done
diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh
index dc85e8b60..2275caa31 100755
--- a/t/t1301-shared-repo.sh
+++ b/t/t1301-shared-repo.sh
@@ -7,6 +7,9 @@ test_description='Test shared repository initialization'
. ./test-lib.sh
+# Remove a default ACL from the test dir if possible.
+setfacl -k . 2>/dev/null
+
# User must have read permissions to the repo -> failure on --shared=0400
test_expect_success 'shared = 0400 (faulty permission u-w)' '
mkdir sub && (
diff --git a/t/t2203-add-intent.sh b/t/t2203-add-intent.sh
new file mode 100755
index 000000000..d4de35ea0
--- /dev/null
+++ b/t/t2203-add-intent.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+test_description='Intent to add'
+
+. ./test-lib.sh
+
+test_expect_success 'intent to add' '
+ echo hello >file &&
+ echo hello >elif &&
+ git add -N file &&
+ git add elif
+'
+
+test_expect_success 'check result of "add -N"' '
+ git ls-files -s file >actual &&
+ empty=$(git hash-object --stdin </dev/null) &&
+ echo "100644 $empty 0 file" >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'intent to add is just an ordinary empty blob' '
+ git add -u &&
+ git ls-files -s file >actual &&
+ git ls-files -s elif | sed -e "s/elif/file/" >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'intent to add does not clobber existing paths' '
+ git add -N file elif &&
+ empty=$(git hash-object --stdin </dev/null) &&
+ git ls-files -s >actual &&
+ ! grep "$empty" actual
+'
+
+test_done
+
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index e0ded197e..7d10a27f1 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -419,4 +419,15 @@ test_expect_success 'rebase with a file named HEAD in worktree' '
'
+test_expect_success 'do "noop" when there is nothing to cherry-pick' '
+
+ git checkout -b branch4 HEAD &&
+ GIT_EDITOR=: git commit --amend \
+ --author="Somebody else <somebody@else.com>"
+ test $(git rev-parse branch3) != $(git rev-parse branch4) &&
+ git rebase -i branch3 &&
+ test $(git rev-parse branch3) = $(git rev-parse branch4)
+
+'
+
test_done
diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh
index 558c80edb..66aca99fd 100755
--- a/t/t3600-rm.sh
+++ b/t/t3600-rm.sh
@@ -219,14 +219,23 @@ test_expect_success 'Remove nonexistent file returns nonzero exit status' '
test_expect_success 'Call "rm" from outside the work tree' '
mkdir repo &&
- cd repo &&
- git init &&
- echo something > somefile &&
- git add somefile &&
- git commit -m "add a file" &&
- (cd .. &&
- git --git-dir=repo/.git --work-tree=repo rm somefile) &&
- test_must_fail git ls-files --error-unmatch somefile
+ (cd repo &&
+ git init &&
+ echo something > somefile &&
+ git add somefile &&
+ git commit -m "add a file" &&
+ (cd .. &&
+ git --git-dir=repo/.git --work-tree=repo rm somefile) &&
+ test_must_fail git ls-files --error-unmatch somefile)
+'
+
+test_expect_success 'refresh index before checking if it is up-to-date' '
+
+ git reset --hard &&
+ test-chmtime -86400 frotz/nitfol &&
+ git rm frotz/nitfol &&
+ test ! -f frotz/nitfol
+
'
test_done
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 1a6b52234..fe6080da5 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -258,6 +258,7 @@ diff --patch-with-stat -r initial..side
diff --patch-with-raw -r initial..side
diff --name-status dir2 dir
diff --no-index --name-status dir2 dir
+diff master master^ side
EOF
test_done
diff --git a/t/t4013/diff.diff_master_master^_side b/t/t4013/diff.diff_master_master^_side
new file mode 100644
index 000000000..50ec9cadd
--- /dev/null
+++ b/t/t4013/diff.diff_master_master^_side
@@ -0,0 +1,29 @@
+$ git diff master master^ side
+diff --cc dir/sub
+index cead32e,7289e35..992913c
+--- a/dir/sub
++++ b/dir/sub
+@@@ -1,6 -1,4 +1,8 @@@
+ A
+ B
+ +C
+ +D
+ +E
+ +F
++ 1
++ 2
+diff --cc file0
+index b414108,f4615da..10a8a9f
+--- a/file0
++++ b/file0
+@@@ -1,6 -1,6 +1,9 @@@
+ 1
+ 2
+ 3
+ +4
+ +5
+ +6
++ A
++ B
++ C
+$
diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh
index 520e095c5..be541348c 100755
--- a/t/t4018-diff-funcname.sh
+++ b/t/t4018-diff-funcname.sh
@@ -32,7 +32,7 @@ EOF
sed 's/beer\\/beer,\\/' < Beer.java > Beer-correct.java
-builtin_patterns="bibtex html java pascal php python ruby tex"
+builtin_patterns="bibtex html java objc pascal php python ruby tex"
for p in $builtin_patterns
do
test_expect_success "builtin $p pattern compiles" '
@@ -65,7 +65,14 @@ test_expect_success 'custom pattern' '
test_expect_success 'last regexp must not be negated' '
git config diff.java.funcname "!static" &&
- test_must_fail git diff --no-index Beer.java Beer-correct.java
+ git diff --no-index Beer.java Beer-correct.java 2>&1 |
+ grep "fatal: Last expression must not be negated:"
+'
+
+test_expect_success 'pattern which matches to end of line' '
+ git config diff.java.funcname "Beer$" &&
+ git diff --no-index Beer.java Beer-correct.java |
+ grep "^@@.*@@ Beer"
'
test_expect_success 'alternation in pattern' '
diff --git a/t/t4128-apply-root.sh b/t/t4128-apply-root.sh
index 2dd0c75f9..8f6aea48d 100755
--- a/t/t4128-apply-root.sh
+++ b/t/t4128-apply-root.sh
@@ -40,4 +40,56 @@ test_expect_success 'apply --directory -p (2) ' '
'
+cat > patch << EOF
+diff --git a/newfile b/newfile
+new file mode 100644
+index 0000000..d95f3ad
+--- /dev/null
++++ b/newfile
+@@ -0,0 +1 @@
++content
+EOF
+
+test_expect_success 'apply --directory (new file)' '
+ git reset --hard initial &&
+ git apply --directory=some/sub/dir/ --index patch &&
+ test content = $(git show :some/sub/dir/newfile) &&
+ test content = $(cat some/sub/dir/newfile)
+'
+
+cat > patch << EOF
+diff --git a/delfile b/delfile
+deleted file mode 100644
+index d95f3ad..0000000
+--- a/delfile
++++ /dev/null
+@@ -1 +0,0 @@
+-content
+EOF
+
+test_expect_success 'apply --directory (delete file)' '
+ git reset --hard initial &&
+ echo content >some/sub/dir/delfile &&
+ git add some/sub/dir/delfile &&
+ git apply --directory=some/sub/dir/ --index patch &&
+ ! (git ls-files | grep delfile)
+'
+
+cat > patch << 'EOF'
+diff --git "a/qu\157tefile" "b/qu\157tefile"
+new file mode 100644
+index 0000000..d95f3ad
+--- /dev/null
++++ "b/qu\157tefile"
+@@ -0,0 +1 @@
++content
+EOF
+
+test_expect_success 'apply --directory (quoted filename)' '
+ git reset --hard initial &&
+ git apply --directory=some/sub/dir/ --index patch &&
+ test content = $(git show :some/sub/dir/quotefile) &&
+ test content = $(cat some/sub/dir/quotefile)
+'
+
test_done
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 9516f541e..3a36a95b9 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -511,4 +511,37 @@ test_expect_success 'in-index merge' '
test_debug 'gitk --all'
+test_expect_success 'refresh the index before merging' '
+ git reset --hard c1 &&
+ sleep 1 &&
+ touch file &&
+ git merge c3
+'
+
+cat >expected <<EOF
+Merge branch 'c5' (early part)
+EOF
+
+test_expect_success 'merge early part of c2' '
+ git reset --hard c3 &&
+ echo c4 > c4.c &&
+ git add c4.c &&
+ git commit -m c4 &&
+ git tag c4 &&
+ echo c5 > c5.c &&
+ git add c5.c &&
+ git commit -m c5 &&
+ git tag c5 &&
+ git reset --hard c3 &&
+ echo c6 > c6.c &&
+ git add c6.c &&
+ git commit -m c6 &&
+ git tag c6 &&
+ git merge c5~1 &&
+ git show -s --pretty=format:%s HEAD > actual &&
+ test_cmp actual expected
+'
+
+test_debug 'gitk --all'
+
test_done
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index d098a01ba..561ae7d0a 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -109,7 +109,7 @@ test_expect_success 'allow long lines with --no-validate' '
--from="Example <nobody@example.com>" \
--to=nobody@example.com \
--smtp-server="$(pwd)/fake.sendmail" \
- --no-validate \
+ --novalidate \
$patches longline.patch \
2>errors
'
diff --git a/t/t9128-git-svn-cmd-branch.sh b/t/t9128-git-svn-cmd-branch.sh
new file mode 100755
index 000000000..47c4d4d93
--- /dev/null
+++ b/t/t9128-git-svn-cmd-branch.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+#
+# Copyright (c) 2008 Deskin Miller
+#
+
+test_description='git svn partial-rebuild tests'
+. ./lib-git-svn.sh
+
+test_expect_success 'initialize svnrepo' '
+ mkdir import &&
+ (
+ cd import &&
+ mkdir trunk branches tags &&
+ cd trunk &&
+ echo foo > foo &&
+ cd .. &&
+ svn import -m "import for git-svn" . "$svnrepo" >/dev/null &&
+ cd .. &&
+ rm -rf import &&
+ svn co "$svnrepo"/trunk trunk &&
+ cd trunk &&
+ echo bar >> foo &&
+ svn ci -m "updated trunk" &&
+ cd .. &&
+ rm -rf trunk
+ )
+'
+
+test_expect_success 'import into git' '
+ git svn init --stdlayout "$svnrepo" &&
+ git svn fetch &&
+ git checkout remotes/trunk
+'
+
+test_expect_success 'git svn branch tests' '
+ git svn branch a &&
+ base=$(git rev-parse HEAD:) &&
+ test $base = $(git rev-parse remotes/a:) &&
+ git svn branch -m "created branch b blah" b &&
+ test $base = $(git rev-parse remotes/b:) &&
+ test_must_fail git branch -m "no branchname" &&
+ git svn branch -n c &&
+ test_must_fail git rev-parse remotes/c &&
+ test_must_fail git svn branch a &&
+ git svn branch -t tag1 &&
+ test $base = $(git rev-parse remotes/tags/tag1:) &&
+ git svn branch --tag tag2 &&
+ test $base = $(git rev-parse remotes/tags/tag2:) &&
+ git svn tag tag3 &&
+ test $base = $(git rev-parse remotes/tags/tag3:) &&
+ git svn tag -m "created tag4 foo" tag4 &&
+ test $base = $(git rev-parse remotes/tags/tag4:) &&
+ test_must_fail git svn tag -m "no tagname" &&
+ git svn tag -n tag5 &&
+ test_must_fail git rev-parse remotes/tags/tag5 &&
+ test_must_fail git svn tag tag1
+'
+
+test_done
diff --git a/t/test-lib.sh b/t/test-lib.sh
index e2b106cb6..8936173ee 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -112,8 +112,9 @@ if test -n "$color"; then
*) test -n "$quiet" && return;;
esac
shift
- echo "* $*"
+ printf "* %s" "$*"
tput sgr0
+ echo
)
}
else
diff --git a/walker.c b/walker.c
index 0e68ee6d2..6b4cf70c6 100644
--- a/walker.c
+++ b/walker.c
@@ -215,9 +215,8 @@ static int mark_complete(const char *path, const unsigned char *sha1, int flag,
int walker_targets_stdin(char ***target, const char ***write_ref)
{
int targets = 0, targets_alloc = 0;
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
*target = NULL; *write_ref = NULL;
- strbuf_init(&buf, 0);
while (1) {
char *rf_one = NULL;
char *tg_one;
diff --git a/ws.c b/ws.c
index 7a7ff130a..b1efcd9d7 100644
--- a/ws.c
+++ b/ws.c
@@ -99,8 +99,7 @@ unsigned whitespace_rule(const char *pathname)
/* The returned string should be freed by the caller. */
char *whitespace_error_string(unsigned ws)
{
- struct strbuf err;
- strbuf_init(&err, 0);
+ struct strbuf err = STRBUF_INIT;
if (ws & WS_TRAILING_SPACE)
strbuf_addstr(&err, "trailing whitespace");
if (ws & WS_SPACE_BEFORE_TAB) {
diff --git a/wt-status.c b/wt-status.c
index 7cf890f24..d2eac36ae 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -103,10 +103,8 @@ static void wt_status_print_filepair(struct wt_status *s,
{
const char *c = color(t);
const char *one, *two;
- struct strbuf onebuf, twobuf;
+ struct strbuf onebuf = STRBUF_INIT, twobuf = STRBUF_INIT;
- strbuf_init(&onebuf, 0);
- strbuf_init(&twobuf, 0);
one = quote_path(p->one->path, -1, &onebuf, s->prefix);
two = quote_path(p->two->path, -1, &twobuf, s->prefix);
@@ -190,9 +188,8 @@ static void wt_status_print_changed_cb(struct diff_queue_struct *q,
static void wt_status_print_initial(struct wt_status *s)
{
int i;
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
- strbuf_init(&buf, 0);
if (active_nr) {
s->commitable = 1;
wt_status_print_cached_header(s);
@@ -268,9 +265,8 @@ static void wt_status_print_untracked(struct wt_status *s)
struct dir_struct dir;
int i;
int shown_header = 0;
- struct strbuf buf;
+ struct strbuf buf = STRBUF_INIT;
- strbuf_init(&buf, 0);
memset(&dir, 0, sizeof(dir));
if (!s->untracked) {
diff --git a/xdiff-interface.c b/xdiff-interface.c
index 8bab82ed7..49e06af71 100644
--- a/xdiff-interface.c
+++ b/xdiff-interface.c
@@ -191,12 +191,32 @@ struct ff_regs {
static long ff_regexp(const char *line, long len,
char *buffer, long buffer_size, void *priv)
{
- char *line_buffer = xstrndup(line, len); /* make NUL terminated */
+ char *line_buffer;
struct ff_regs *regs = priv;
regmatch_t pmatch[2];
int i;
int result = -1;
+ /* Exclude terminating newline (and cr) from matching */
+ if (len > 0 && line[len-1] == '\n') {
+ if (len > 1 && line[len-2] == '\r')
+ len -= 2;
+ else
+ len--;
+ }
+
+ line_buffer = xstrndup(line, len); /* make NUL terminated */
+
+ /* Exclude terminating newline (and cr) from matching */
+ if (len > 0 && line[len-1] == '\n') {
+ if (len > 1 && line[len-2] == '\r')
+ len -= 2;
+ else
+ len--;
+ }
+
+ line_buffer = xstrndup(line, len); /* make NUL terminated */
+
for (i = 0; i < regs->nr; i++) {
struct ff_reg *reg = regs->array + i;
if (!regexec(&reg->re, line_buffer, 2, pmatch, 0)) {