Code

Merge branch 'ns/rebase-noverify'
authorJunio C Hamano <gitster@pobox.com>
Sun, 19 Oct 2008 23:05:58 +0000 (16:05 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sun, 19 Oct 2008 23:05:58 +0000 (16:05 -0700)
* ns/rebase-noverify:
  rebase: Document --no-verify option to bypass pre-rebase hook
  rebase --no-verify

111 files changed:
Documentation/RelNotes-1.6.0.3.txt
Documentation/RelNotes-1.6.1.txt
Documentation/config.txt
Documentation/diff-options.txt
Documentation/git-check-attr.txt
Documentation/git-checkout.txt
Documentation/git-commit.txt
Documentation/git-grep.txt
Documentation/git-prune.txt
Documentation/git-push.txt
Documentation/git-send-email.txt
Documentation/git-svn.txt
Documentation/gitattributes.txt
Documentation/gittutorial-2.txt
Documentation/howto/rebase-and-edit.txt [deleted file]
Makefile
archive-tar.c
archive.c
builtin-add.c
builtin-apply.c
builtin-blame.c
builtin-branch.c
builtin-cat-file.c
builtin-checkout-index.c
builtin-checkout.c
builtin-clean.c
builtin-clone.c
builtin-commit.c
builtin-diff.c
builtin-fetch--tool.c
builtin-fmt-merge-msg.c
builtin-grep.c
builtin-help.c
builtin-init-db.c
builtin-log.c
builtin-merge-base.c
builtin-merge-file.c
builtin-merge.c
builtin-pack-objects.c
builtin-prune.c
builtin-push.c
builtin-remote.c
builtin-rev-list.c
builtin-rev-parse.c
builtin-rm.c
builtin-show-branch.c
builtin-stripspace.c
builtin-tag.c
builtin-unpack-objects.c
builtin-update-index.c
cache.h
combine-diff.c
compat/cygwin.c [new file with mode: 0644]
compat/cygwin.h [new file with mode: 0644]
compat/mingw.c
compat/win32.h [new file with mode: 0644]
config.c
contrib/completion/git-completion.bash
contrib/examples/git-remote.perl
contrib/hooks/pre-auto-gc-battery
contrib/stats/packinfo.pl
convert.c
csum-file.c
csum-file.h
date.c
diff.c
editor.c
environment.c
exec_cmd.c
fsck.c
git-compat-util.h
git-rebase--interactive.sh
git-send-email.perl
git-stash.sh
git-svn.perl
git.c
gitweb/gitweb.css
gitweb/gitweb.perl
graph.c
grep.c
grep.h
hash-object.c
imap-send.c
index-pack.c
log-tree.c
merge-recursive.c
merge-tree.c
mktag.c
mktree.c
pretty.c
read-cache.c
remote.c
rerere.c
sha1_file.c
t/t0001-init.sh
t/t1301-shared-repo.sh
t/t2203-add-intent.sh [new file with mode: 0755]
t/t3404-rebase-interactive.sh
t/t3600-rm.sh
t/t4013-diff-various.sh
t/t4013/diff.diff_master_master^_side [new file with mode: 0644]
t/t4018-diff-funcname.sh
t/t4128-apply-root.sh
t/t7600-merge.sh
t/t9001-send-email.sh
t/t9128-git-svn-cmd-branch.sh [new file with mode: 0755]
t/test-lib.sh
walker.c
ws.c
wt-status.c
xdiff-interface.c

index edd5e45c958b72f52a64471d598c60117d4df4ac..c0f037d6dbe4cfa98ea97a9b28d115e34ccfde75 100644 (file)
@@ -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
index 906932cfa1a51c6cd0c7098eabd067b6698b7fa4..afd1150eaa4fc17600dd948f8d7dc4ec266aa162 100644 (file)
@@ -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
index bbe38ccaa2697f88936a8eff63a99b5c89435ac8..da18a5458e82e3d3d72e7ef1832cdb6461324ea4 100644 (file)
@@ -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
index 7788d4fa4a1209cbed564a20f882f0946ba400cf..c62b45cdbade990878b8e8e9371d41d4e3c43bfe 100644 (file)
@@ -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
index 2b821f2a1d70fa108ce279135fd5028453a04fd9..4b3c2b0b06e9821124759d0cc6240d0a1953d2fa 100644 (file)
@@ -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
 --------
index 82e154de4970c1c2cb35335591cfe457e80a89c1..168333a588e0828d2d14687774fd41cc57f43721 100644 (file)
@@ -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.
index eb05b0f49b0c513581150415d1a4e679d7bfbea6..41809eecab9750746d2df4a0e148f09796e90224 100644 (file)
@@ -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::
index fa4d133c1bccc088d3c8da65bce4e15cafd394aa..553da6cbb1777a94cb3d6b48dc77c445e18ca2b0 100644 (file)
@@ -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
index 54f1dab38de9e01d8452753ac6028875b91d5f6b..da6055d4b8cf78aff16fa553e684b0b3ed57138e 100644 (file)
@@ -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.
 
index 45c96435fa66ab4b1b57b6a860a2fc264321cfe4..6150b1b959e17655a2875d39ec3b70449684a0eb 100644 (file)
@@ -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::
index 3c3e1b0e77abe171ac7531b8098ea2af7d6809dd..82f505686e998d36b87bfe2c1a29031449fbdbc6 100644 (file)
@@ -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
index 82d03b4ced9cb7e34feca325d0ac7b41923de976..84c8f3cde0b781ef1579b38a17430dc405115190 100644 (file)
@@ -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
index 2ae771f2fb213a478cf8ed5273829c97ad1392a9..26945593cb1739bb6a6e1e2acc2cd78caab3a102 100644 (file)
@@ -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.
index 660904686c656fd00078aa272d0b9a5a198e1833..bab0f34b452bfab7174d216700b46220e3a4d2c3 100644 (file)
@@ -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 (file)
index 554909f..0000000
+++ /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
index 15ca6599a7b665d5d4888c00b0fecd7bbde28879..308dc70b5de118083a14bcb2665372a40ae6522c 100644 (file)
--- 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
index 13029619e5ec34bac4ba61a6fc08800ab36f4a1b..ba890ebdecd8672aeb32757605c8a2976fa21161 100644 (file)
@@ -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);
index 44ab008039854b7c585adf53bee195b81f4e18c7..849eed553e9d6455c021664135a01b322eef9a31 100644 (file)
--- 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)
index 7c874e31154a4c3f96b3403db1bdcb0b36fdec3e..ea4e77169a782ef38ed1c0524952a7220cbf739d 100644 (file)
@@ -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));
index 342f2fe5e6476db7cb7b4647aea45a42d7ac7642..cfd8fceb9033cf5c4c7924d96437b94a9c4fe226 100644 (file)
@@ -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;
index df537593d052f0b4d705eb1d0d19ed296f76a39d..48cc0c175d52446266658d785de0311daaaf4776 100644 (file)
@@ -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;
index b1a2ad7a6b3b150cda8d031a87352a4daedc40ea..8d634ff571ce34ce21a5519628d6f66a7e52aa93 100644 (file)
@@ -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;
index 3fba6b9e743545868368a0e554466fca3814316a..30d00a66649f749c8cf6e657734045382bc29e13 100644 (file)
@@ -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)
index 55b7aafe06680fa51729ddb7fa97f9cd319a470e..4ba27024c53ca1b67e9b6d6f4a62aa7548b7b96d 100644 (file)
@@ -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] == '"') {
index 3762f71aaeae623b37d38c5c03b7a0d10973efc4..57b94d282931187a0cb6394d4df707237038a7eb 100644 (file)
@@ -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))
index 48bf29f40a5e06fd588b34c468535e04abcf206b..f78c2fb108bc667079290f9b2fa82f47da5eb34c 100644 (file)
@@ -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);
index 49d2eb9c2ba574f2c1484717f0755208e7ed8147..1ddc14b9c70b3318ab5e1cad779c8af029e56ce3 100644 (file)
@@ -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");
 
index b920257524850ea04bc940411d342e9a622e7094..2c33af276671ff0ba4bffee437a03e7fc2a7fae2 100644 (file)
@@ -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");
index 35da366f46009eab8eab693f7f56403d91d5d677..9c8c295732bf12990b8324bf75968fd68dd41d59 100644 (file)
@@ -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;
index 7460ab7fce2a4e6a7e014f448819140e2204ccb7..469b07e240953aa21fd67eb2563e094a7f0f3d42 100644 (file)
@@ -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));
        }
index df02ba7afdd615492361a1897a9dedd6ab233c96..df18f4070f3877ed907476f2179590001ec972b7 100644 (file)
@@ -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;
 }
index 3a51662a35878ae6b5965c90abb747b5b27c5493..624f86e287cf6304d122850f8258444c5f916702 100644 (file)
@@ -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;
index 64207cbfe909d17ea9698d3ff680203eee9f5c01..f076efa9211ddcffdc81ffd7c0c56fdb197a11b0 100644 (file)
@@ -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
index 8140c1299afe368266de1153f3bb891f000fe5f5..d30c3fe2ca542b061ab8b7a7696cdd5416e17147 100644 (file)
@@ -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
index fc5e4da822c470fdb2fb4738874a56e0103a2013..794821f6bca6500cbb040403c1350932ae7126fb 100644 (file)
@@ -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,
index b08da516e491e7089b1bb178e9a4b05c2ab36539..03fc1c211453f1ed09ee2c6b71d438b0bfbf474f 100644 (file)
@@ -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);
 }
index 45c98538cdbf35352f7a3b5adf40fca9d7512ea5..9d4e874809f495ad685a7218584041fa001696e5 100644 (file)
@@ -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)
index 5c65a5869900ad1a1014fb3aad88c874a5410bf7..5e2b7f12c35ab1bfebda66f7ee9180c68e7f23c4 100644 (file)
@@ -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,
index 1158e42cba81e2bdb8640cd6c5a3835453d17e7f..59c30d1caa37416041177ff4aaf01b67f4e8add4 100644 (file)
@@ -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++;
index 1663f8bdb1e27713bab6cf7a16ca15cfcfc1abef..7b4ec80e62997fe70f53c92380cd4d66e80d62a0 100644 (file)
@@ -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()
index cc6666f75e7db8a546d4a1589335589190e414fe..122fdcfbdc13a11388a091e5ec33d077648fab0a 100644 (file)
@@ -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,
 };
 
index 90a4e35828697f349a38ba3486c40813db32cee0..6b3325dfa9e0aa52d806d1c28692a05cf549abe4 100644 (file)
@@ -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);
index facaff288dba2789f0637c4554bd130440e2a3da..06cdeb7ebe7468911a7bee670bf5ec539185ba54 100644 (file)
@@ -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);
index 9aa049ec170b0125fddde29adda3c720c8a7b8ee..81d5a6ffc9ff1c149bfb68f976a9e66c307cae1d 100644 (file)
@@ -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)
index 50ae6d54011fad89387f0d56ce7a4591d07874f3..e06640cf8d3418cbbe177b8fdcdccd19e0f3379f 100644 (file)
@@ -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;
index 233eed499d0b8790781326ff0455bdc7f09fe4d4..306b850c720ecef7030bd7139f7c7d2758125ac4 100644 (file)
@@ -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);
index c0b21301ba4c126a49ed38b6983756b99a25aae0..d6e3896c006796ccca12c00de45e36583387f05b 100644 (file)
@@ -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");
 
index f2853d08c77368b37b40c7ea51f5a124208d385f..b13fa34d8c59a9226599ba10b4d679f41ad230b0 100644 (file)
@@ -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.");
index d2796b6309d3b13a6c401b502aafd53d684328d8..9f4bdd3296d19b75211ca0f2434d227eafac44b6 100644 (file)
@@ -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);
index 417f9724abdce3c49df316505eff1019126a5058..65d5775107f9013526cc5b288a80a00b449e8814 100644 (file)
@@ -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 9f4e5c0d459dcf73c86ef977469ba4885cc8f4c2..991544cf0bd7e84c5db5bd6486e5922a53ec136f 100644 (file)
--- 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);
index de83c6972e9dffbd634e5cc09b5e455ec22c6c48..5aa1104d3480f8057dd71c49bcf300eccabe2f9d 100644 (file)
@@ -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 (file)
index 0000000..423ff20
--- /dev/null
@@ -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 (file)
index 0000000..a3229f5
--- /dev/null
@@ -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)
index fc45d240f579ab3e1e0f867859f24132c593410e..09858f6c593d9a8301c857c81e09bfa24b955eac 100644 (file)
@@ -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 (file)
index 0000000..c26384e
--- /dev/null
@@ -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;
+       }
+}
index 18d305c890d3f4ba00962cfa4033ff9ed68cf95b..b8d289d21789b5017579d90b7894db8ebee4c47a 100644 (file)
--- 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);
 
index 15073d4c9fbccb06e9b17dff4a8d134e805aed6d..d192927c20a1b4bca97a6bea91cc10b0b67bdd29 100755 (executable)
@@ -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
index 36bd54c985080f8dd5558a3e7a4e19ede9fbab93..b17952a785d9e45dea8a71c211f76f0271e659da 100755 (executable)
@@ -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) {
index b0a8caae9e7822fd4ea5c6e9b202373b2947e6af..1f914c94aa748f57bd6c70fdd18dfb681c684556 100644 (file)
@@ -28,6 +28,9 @@ elif grep -q 'on-line' /proc/acpi/ac_adapter/AC/state 2>/dev/null
 then
        exit 0
 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 |
index f4a7b62cd9f1a397118b95792c04c2f70f910f9e..be188c0f11dbea8320737b4fdf426a2f5acd1a00 100755 (executable)
@@ -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+(.*)$/) {
index 78efed800d4d64898d438d9590b01be008cfcd36..1816e977b7b13782003fc78a9de9b47cd3554a32 100644 (file)
--- 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;
index 717d29fc03ba0bf375efa58be8dc0f676d9ac5c4..2ddb12a0b70da87afe6fa8a33dce08c6c8ae7f71 100644 (file)
@@ -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;
index 9e13342eb357d6427a208fc6777ea170eb55acb8..294add2a91496355b42ce02ecfe9c453d21b291a 100644 (file)
@@ -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 35a52576c53e5e1406d40ed4402b8834a29b9f0e..950b88fdcf74f550a582684f1702ffb58c62c7f9 100644 (file)
--- 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;
@@ -462,6 +471,13 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
                return n;
        }
 
+       /*
+        * 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",
@@ -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 02e948c9dd6244a0003c2c6bc81f55e46cf0ad2b..1c6be897b2c95fc481c02834e4fe022b6bd405ae 100644 (file)
--- 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);
index eebc3e95fe0c7e61f7c29fa5412ea9d4a5900f92..4d469d076bcd58df3af16d98adc9120e34765944 100644 (file)
--- 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);
index 0c6d11f6a0c6fa5dbab2f36c4b4ad4de5aba4ac9..0693cd9a42adf4914bb219ecf24fc6d5da7aafd3 100644 (file)
@@ -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)
index ce6741eb682b59ad638c7bee6ca31e2fcd53f281..cdd35f91954bdc751455e1083a0612a21eeadc67 100644 (file)
@@ -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 797e3178ae279f444d2efa7e3758652ad0898dd7..0cf5f012bdfa876fae4e15ed9cb94ed304314bf6 100644 (file)
--- 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);
index 2ac832f3b4ad1566c7e744505205c13f7b05347f..e20b1e858cc715d1840da11c6198a1d6e6bec2a4 100644 (file)
@@ -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>
index b0d757db5dbb97d91014b22e34938ca0764dd4ef..86290f63b25f921de5c78b087e111e6b872676fb 100755 (executable)
@@ -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
index d2fd89907688a044ffe0d2520744e00a9b33c942..bdbfac66256ffc29e26f5c83531c77a18a263808 100755 (executable)
@@ -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);
index 42f626f9d555f26f3e50441c0ab27de5cac19bf4..b9ace9970492aaf48472904d978d809d90ca33db 100755 (executable)
@@ -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 ||
index 7609a837419012d94109cf8b4de1b9bbdb969c83..ef6d773df1143b32f0bc421b59421f7e0eab60bd 100755 (executable)
@@ -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 f4b0cf611b8a281d51970fa088c7271f0aacf21c..89feb0b6dc9c34902aa7c3c4ac526c646c0e0d84 100644 (file)
--- 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]);
 
        /*
index 07f5b5378805a520e22b0f1b598aed7af4235538..a01eac814e51edd2115474f4d48a8d7fafa8c0e6 100644 (file)
@@ -435,6 +435,10 @@ div.search {
        right: 12px
 }
 
+p.projsearch {
+       text-align: center;
+}
+
 td.linenr {
        text-align: right;
 }
index 83f810ad46cd2dfcea37308791ba64870ebfbd3c..11168006cffe9bd2f6c8c27bd1d034c41667e39a 100755 (executable)
@@ -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 5f821706c63778e8b6b53a10894edfc2fb21a8b0..162a516ee15cca1f8ab118dd41b803a5d76e42ff 100644 (file)
--- 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 706351197fc26efa10c4666d38433f8fbdf1d6b5..e2c190a7f66f9e9311f91d9a41b7dc3f295f00fb 100644 (file)
--- 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 59b3f871ea63619f8d3caae74c41b4da1e9a2b9f..45a222d904b5898758c3c84f6ef1e0119c81f6b2 100644 (file)
--- 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;
index a4d127cf78013ca43339c5493b7f7ef90b2145a8..20937ff94c1ce6ab7984d7b6b1903307e303eb60 100644 (file)
@@ -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);
index af7e08c0943ada9a650f80fd5b5fc1df23c04b88..3703dbd1af65c30806a98f0d2d3dc14b8b0e9798 100644 (file)
@@ -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)
index 2e4c0885f2c6f6907481dfefe7e0761c3957d8a6..aec11cb94066bc2d0fc75cad2b9f675c9d9bdb53 100644 (file)
@@ -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));
index 2c1f3e673ae7c9441cb171244d3fb91a8dd9fb1b..cec3c061360e9d33068fdb6c2555b69cc11f6771 100644 (file)
@@ -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,
index 6bc3eac85c46700b1ed7ab93bce6ecf859fa13f9..7472d3ecc9b8412a697a64c1307259a104e0abf9 100644 (file)
@@ -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)
index 02fc10f7e622ba1c53065e7cf4563ff10af0c41f..2d1413efbbc33c51fd4820933dcb54164e12d706 100644 (file)
@@ -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 0b34341f711a903d4a12fe96dc6ef63e55fb2f5b..ba3d495e0715d83ffab3103e4d340a3b9ac4f4e7 100644 (file)
--- 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");
        }
index e0da110a98d3a7376dc78df71fabc10fc5664296..514fd9b15a6680389bf2c1274d29c55d2c1034f7 100644 (file)
--- 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;
index 8beafa08d3927e943a94279f5d776d6a45c673c5..1e799433395afa935b5ac1454c299ae873873893 100644 (file)
--- 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 */
index 901064bf1ae72aacb583ff735058eec953475ae3..c229fd4d0da68b204e81e1e8127f8529abe06336 100644 (file)
@@ -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;
index c45d96e98fffe3411284144b6d836cf499d42ba4..8a04066d6142823183033aaff8754febe31ad1b0 100644 (file)
--- 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;
 }
 
index 121f9114140708efd36bd4bd1b375f5ad0c558bc..5bb5316cdae16154fd4aaffe996710c0bcfc0b94 100644 (file)
--- 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)
index 751598786822950766668b4d1c97198b183586f7..70bb453be25d4e5ba05ee5f2565630a8994842f2 100644 (file)
@@ -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);
index 620da5b32041b1ad69bfdcb6d139f2705386a5ff..5ac0a273a94c033fbb7c48cb9a22e44c389e0f7d 100755 (executable)
@@ -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
index dc85e8b60a5c10e57047d1692e383f177e2c478d..2275caa317c8b7237c6f118251dc2d34cf10e218 100755 (executable)
@@ -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 (executable)
index 0000000..d4de35e
--- /dev/null
@@ -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
+
index e0ded197ecabce712ac1eeaa4c959c714f0e9d34..7d10a27f1dcb8058f0e3c6180c3d45705fe3b21d 100755 (executable)
@@ -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
index 558c80edbfa5c0c90566a0be94723e2783d6df9b..66aca99fd32c6b98f5e6e34a3cf7b096b3e236cf 100755 (executable)
@@ -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
index 1a6b52234d8df70e5ddcb28c0ddde582d8310d43..fe6080da576c45cec800376e81915c51f11f7106 100755 (executable)
@@ -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 (file)
index 0000000..50ec9ca
--- /dev/null
@@ -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
+$
index 520e095c597a61f0f263a274a53ae0aa2781da85..be541348c6f8d469428e2fcc7abaf6d25168c08f 100755 (executable)
@@ -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' '
index 2dd0c75f964b690977e40a3a8235cc324dc6826e..8f6aea48d84621ae3b7304636452c724a4bbe5b6 100755 (executable)
@@ -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
index 9516f541e9c47f83fed2fc8d3baa065a9bb206de..3a36a95b9ac42b35e680109df4daf87fc219fb53 100755 (executable)
@@ -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
index d098a01ba30fa08ae696085164e7b77453f8715a..561ae7d0a6ddf9531a8770e54beb43a38fe2aab1 100755 (executable)
@@ -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 (executable)
index 0000000..47c4d4d
--- /dev/null
@@ -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
index e2b106cb6a2337f873a7225670392b376f74c6e7..8936173ee204c589fb299837586b4866722b2388 100644 (file)
@@ -112,8 +112,9 @@ if test -n "$color"; then
                        *) test -n "$quiet" && return;;
                esac
                shift
-               echo "* $*"
+               printf "* %s" "$*"
                tput sgr0
+               echo
                )
        }
 else
index 0e68ee6d2e2fb1b866ecec00c5f6446af366a62e..6b4cf70c6af1289501f72cbde78cd04da57293f3 100644 (file)
--- 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 7a7ff130a34942506e6068105ac5946c9404bf18..b1efcd9d753a29d295702b36fb1beba58fb16995 100644 (file)
--- 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) {
index 7cf890f2433bf622fe8c18faa0b0c89be60ef1db..d2eac36aeaafab2800b4f0802c7db9656c44cdeb 100644 (file)
@@ -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) {
index 8bab82ed7fd1fcfea4dd13f6d020476758a18031..49e06af710ceee5538eb10f0c6cf9c30f31748b4 100644 (file)
@@ -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)) {