Merge branch 'maint'
authorJunio C Hamano <junkio@cox.net>
Wed, 28 Feb 2007 22:18:57 +0000 (14:18 -0800)
committerJunio C Hamano <junkio@cox.net>
Wed, 28 Feb 2007 22:18:57 +0000 (14:18 -0800)
* maint:
  Start preparing Release Notes for 1.5.0.3
  Documentation: git-remote add [-t <branch>] [-m <branch>] [-f] name url
  Include config.mak in doc/Makefile
  git.el: Set the default commit coding system from the repository config.
  git-archimport: support empty summaries, put summary on a single line.
  http-push.c::lock_remote(): validate all remote refs.
  git-cvsexportcommit: don't cleanup .msg if not yet committed to cvs.

149 files changed:
.gitignore
.mailmap
Documentation/RelNotes-1.5.1.txt [new file with mode: 0644]
Documentation/cmd-list.perl
Documentation/config.txt
Documentation/core-intro.txt
Documentation/core-tutorial.txt
Documentation/diff-options.txt
Documentation/diffcore.txt
Documentation/git-cvsexportcommit.txt
Documentation/git-diff-files.txt
Documentation/git-diff-stages.txt [deleted file]
Documentation/git-diff.txt
Documentation/git-name-rev.txt
Documentation/git-remote.txt
Documentation/git-resolve.txt [deleted file]
Documentation/git-rev-list.txt
Documentation/git-svn.txt
Documentation/git.txt
Documentation/howto/revert-branch-rebase.txt
Documentation/user-manual.txt
GIT-VERSION-GEN
Makefile
RelNotes
archive-tar.c
archive-zip.c
blob.c
builtin-apply.c
builtin-archive.c
builtin-blame.c
builtin-branch.c
builtin-cat-file.c
builtin-checkout-index.c
builtin-commit-tree.c
builtin-config.c
builtin-describe.c
builtin-diff-files.c
builtin-diff-index.c
builtin-diff-stages.c [deleted file]
builtin-diff.c
builtin-fmt-merge-msg.c
builtin-for-each-ref.c
builtin-fsck.c
builtin-grep.c
builtin-init-db.c
builtin-log.c
builtin-ls-files.c
builtin-ls-tree.c
builtin-mailinfo.c
builtin-merge-base.c [moved from merge-base.c with 79% similarity]
builtin-name-rev.c
builtin-pack-objects.c
builtin-pack-refs.c
builtin-prune.c
builtin-push.c
builtin-read-tree.c
builtin-reflog.c
builtin-rerere.c
builtin-rev-parse.c
builtin-shortlog.c
builtin-show-branch.c
builtin-show-ref.c
builtin-tar-tree.c
builtin-unpack-objects.c
builtin-update-index.c
builtin-write-tree.c
builtin.h
cache.h
combine-diff.c
commit.c
commit.h
config.c
configure.ac
connect.c
contrib/completion/git-completion.bash
contrib/examples/git-resolve.sh [moved from git-resolve.sh with 100% similarity]
convert-objects.c
convert.c [new file with mode: 0644]
daemon.c
diff-lib.c
diff.c
diff.h
entry.c
environment.c
exec_cmd.c
fast-import.c
fetch-pack.c
git-commit.sh
git-compat-util.h
git-cvsexportcommit.perl
git-cvsserver.perl
git-fetch.sh
git-remote.perl
git-send-email.perl
git-svn.perl
git.c
hash-object.c
help.c
http-fetch.c
http-push.c
imap-send.c
index-pack.c
merge-file.c
merge-recursive.c
merge-tree.c
mktag.c
mktree.c
object.c
object.h
pack-check.c
peek-remote.c
perl/Git.pm
read-cache.c
receive-pack.c
refs.c
revision.c
revision.h
send-pack.c
setup.c
sha1_file.c
shell.c
t/lib-git-svn.sh
t/t0020-crlf.sh [new file with mode: 0755]
t/t1200-tutorial.sh
t/t4016-diff-quote.sh
t/t4119-apply-config.sh [new file with mode: 0755]
t/t4200-rerere.sh
t/t9100-git-svn-basic.sh
t/t9101-git-svn-props.sh
t/t9103-git-svn-graft-branches.sh [deleted file]
t/t9104-git-svn-follow-parent.sh
t/t9105-git-svn-commit-diff.sh
t/t9107-git-svn-migrate.sh [new file with mode: 0755]
t/t9108-git-svn-glob.sh [new file with mode: 0755]
t/t9110-git-svn-use-svm-props.sh [new file with mode: 0755]
t/t9110/svm.dump [new file with mode: 0644]
t/t9111-git-svn-use-svnsync-props.sh [new file with mode: 0755]
t/t9111/svnsync.dump [new file with mode: 0644]
t/test-lib.sh
tag.c
templates/hooks--update
test-chmtime.c [new file with mode: 0644]
tree-diff.c
tree.c
unpack-file.c
upload-pack.c
wt-status.c
xdiff/xdiff.h
xdiff/xutils.c

index d99372a..eb8a1f8 100644 (file)
@@ -33,7 +33,6 @@ git-daemon
 git-diff
 git-diff-files
 git-diff-index
-git-diff-stages
 git-diff-tree
 git-describe
 git-fast-import
@@ -101,7 +100,6 @@ git-repo-config
 git-request-pull
 git-rerere
 git-reset
-git-resolve
 git-rev-list
 git-rev-parse
 git-revert
@@ -141,6 +139,7 @@ git-whatchanged
 git-write-tree
 git-core-*/?*
 gitweb/gitweb.cgi
+test-chmtime
 test-date
 test-delta
 test-dump-cache-tree
index c7a3a75..3a624ea 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -27,6 +27,7 @@ Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
 Ramsay Allan Jones <ramsay@ramsay1.demon.co.uk>
 René Scharfe <rene.scharfe@lsrfire.ath.cx>
 Robert Fitzsimons <robfitz@273k.net>
+Sam Vilain <sam@vilain.net>
 Santi Béjar <sbejar@gmail.com>
 Sean Estabrooks <seanlkml@sympatico.ca>
 Shawn O. Pearce <spearce@spearce.org>
diff --git a/Documentation/RelNotes-1.5.1.txt b/Documentation/RelNotes-1.5.1.txt
new file mode 100644 (file)
index 0000000..4d37186
--- /dev/null
@@ -0,0 +1,44 @@
+GIT v1.5.1 Release Notes
+========================
+
+Updates since v1.5.0
+--------------------
+
+* Deprecated commands and options.
+
+  - git-diff-stages and git-resolve have been removed.
+
+* New commands and options.
+
+  - "git log" and friends take --reverse.  This makes output
+    that typically goes reverse order in chronological order.
+    "git shortlog" usually lists commits in chronological order,
+    but with "--reverse", they are shown in reverse
+    chronological order.
+
+  - "git diff" learned --ignore-space-at-eol.  This is a weaker
+    form of --ignore-space-change.
+
+  - "git name-rev" learned --refs=<pattern>, to limit the tags
+    used for naming the given revisions only to the ones
+    matching the given pattern.
+
+* Updated behaviour of existing commands.
+
+  - "git diff" outputs a trailing HT when pathnames have embedded
+    SP on +++/--- header lines, in order to help "GNU patch" to
+    parse its output.  "git apply" was already updated to accept
+    this modified output format since ce74618d (Sep 22, 2006).
+
+* Hooks
+
+  - The sample update hook to show how to send out notification
+    e-mail was updated to show only new commits that appeared in
+    the repository.  Earlier, it showed new commits that appeared
+    on the branch.
+
+--
+exec >/var/tmp/1
+O=v1.5.0-49-g69bc0e2
+echo O=`git describe master`
+git shortlog --no-merges $O..master ^maint
index 75f4791..a2d6268 100755 (executable)
@@ -90,7 +90,6 @@ git-describe                            mainporcelain
 git-diff-files                          plumbinginterrogators
 git-diff-index                          plumbinginterrogators
 git-diff                                mainporcelain
-git-diff-stages                         plumbinginterrogators
 git-diff-tree                           plumbinginterrogators
 git-fast-import                                ancillarymanipulators
 git-fetch                               mainporcelain
@@ -150,7 +149,6 @@ git-remote                              ancillarymanipulators
 git-request-pull                        foreignscminterface
 git-rerere                              ancillaryinterrogators
 git-reset                               mainporcelain
-git-resolve                             mainporcelain
 git-revert                              mainporcelain
 git-rev-list                            plumbinginterrogators
 git-rev-parse                           ancillaryinterrogators
index 9fec769..d2b4a05 100644 (file)
@@ -5,7 +5,8 @@ The git configuration file contains a number of variables that affect
 the git command's behavior. `.git/config` file for each repository
 is used to store the information for that repository, and
 `$HOME/.gitconfig` is used to store per user information to give
-fallback values for `.git/config` file.
+fallback values for `.git/config` file. The file `/etc/gitconfig`
+can be used to store system-wide defaults.
 
 They can be used by both the git plumbing
 and the porcelains. The variables are divided into sections, where
@@ -470,6 +471,10 @@ remote.<name>.push::
        The default set of "refspec" for gitlink:git-push[1]. See
        gitlink:git-push[1].
 
+remote.<name>.skipDefaultUpdate::
+       If true, this remote will be skipped by default when updating
+       using the remote subcommand of gitlink:git-remote[1].
+
 remote.<name>.receivepack::
        The default program to execute on the remote side when pushing.  See
        option \--exec of gitlink:git-push[1].
@@ -478,6 +483,14 @@ remote.<name>.uploadpack::
        The default program to execute on the remote side when fetching.  See
        option \--exec of gitlink:git-fetch-pack[1].
 
+remote.<name>.tagopt::
+       Setting this value to --no-tags disables automatic tag following when fetching
+       from remote <name>
+
+remotes.<group>::
+       The list of remotes which are fetched by "git remote update
+       <group>".  See gitlink:git-remote[1].
+
 repack.usedeltabaseoffset::
        Allow gitlink:git-repack[1] to create packs that uses
        delta-base offset.  Defaults to false.
index 6bee448..eea44d9 100644 (file)
@@ -588,4 +588,5 @@ stages to temporary files and calls a "merge" script on it:
 
        git-merge-index git-merge-one-file hello.c
 
-and that is what higher level `git resolve` is implemented with.
+and that is what higher level `git merge -s resolve` is implemented
+with.
index 9c28bea..97cdb90 100644 (file)
@@ -977,7 +977,7 @@ see more complex cases.
 Now, let's pretend you are the one who did all the work in
 `mybranch`, and the fruit of your hard work has finally been merged
 to the `master` branch. Let's go back to `mybranch`, and run
-resolve to get the "upstream changes" back to your branch.
+`git merge` to get the "upstream changes" back to your branch.
 
 ------------
 $ git checkout mybranch
@@ -996,7 +996,7 @@ Fast forward
 ----------------
 
 Because your branch did not contain anything more than what are
-already merged into the `master` branch, the resolve operation did
+already merged into the `master` branch, the merge operation did
 not actually do a merge. Instead, it just updated the top of
 the tree of your branch to that of the `master` branch. This is
 often called 'fast forward' merge.
@@ -1099,11 +1099,11 @@ programs, which are 'commit walkers'; they outlived their
 usefulness when git Native and SSH transports were introduced,
 and not used by `git pull` or `git push` scripts.
 
-Once you fetch from the remote repository, you `resolve` that
+Once you fetch from the remote repository, you `merge` that
 with your current branch.
 
 However -- it's such a common thing to `fetch` and then
-immediately `resolve`, that it's called `git pull`, and you can
+immediately `merge`, that it's called `git pull`, and you can
 simply do
 
 ----------------
index 019a39f..d8696b7 100644 (file)
 -a::
        Shorthand for "--text".
 
+--ignore-space-at-eol::
+       Ignore changes in white spaces at EOL.
+
 --ignore-space-change::
        Ignore changes in amount of white space.  This ignores white
        space at line end, and consider all other sequences of one or
index cb4e562..34cd306 100644 (file)
@@ -6,8 +6,8 @@ June 2005
 Introduction
 ------------
 
-The diff commands git-diff-index, git-diff-files, git-diff-tree, and
-git-diff-stages can be told to manipulate differences they find in
+The diff commands git-diff-index, git-diff-files, and git-diff-tree
+can be told to manipulate differences they find in
 unconventional ways before showing diff(1) output.  The manipulation
 is collectively called "diffcore transformation".  This short note
 describes what they are and how to use them to produce diff outputs
@@ -30,9 +30,6 @@ files:
 
  - git-diff-tree compares contents of two "tree" objects;
 
- - git-diff-stages compares contents of blobs at two stages in an
-   unmerged index file.
-
 In all of these cases, the commands themselves compare
 corresponding paths in the two sets of files.  The result of
 comparison is passed from these commands to what is internally
index 27d531b..555b823 100644 (file)
@@ -8,7 +8,7 @@ git-cvsexportcommit - Export a single commit to a CVS checkout
 
 SYNOPSIS
 --------
-'git-cvsexportcommit' [-h] [-v] [-c] [-P] [-p] [-a] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID
+'git-cvsexportcommit' [-h] [-v] [-c] [-P] [-p] [-a] [-d cvsroot] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID
 
 
 DESCRIPTION
@@ -43,6 +43,11 @@ OPTIONS
        Add authorship information. Adds Author line, and Committer (if
        different from Author) to the message.
 
+-d::
+       Set an alternative CVSROOT to use.  This corresponds to the CVS
+       -d parameter.  Usually users will not want to set this, except
+       if using CVS in an asymmetric fashion.
+
 -f::
        Force the merge even if the files are not up to date.
 
index 7248b35..b78c4c6 100644 (file)
@@ -8,7 +8,7 @@ git-diff-files - Compares files in the working tree and the index
 
 SYNOPSIS
 --------
-'git-diff-files' [-q] [-0|-1|-2|-3|-c|--cc] [<common diff options>] [<path>...]
+'git-diff-files' [-q] [-0|-1|-2|-3|-c|--cc|-n|--no-index] [<common diff options>] [<path>...]
 
 DESCRIPTION
 -----------
@@ -36,6 +36,9 @@ omit diff output for unmerged entries and just show "Unmerged".
        diff, similar to the way 'diff-tree' shows a merge
        commit with these flags.
 
+\-n,\--no-index::
+       Compare the two given files / directories.
+
 -q::
        Remain silent even on nonexistent files
 
diff --git a/Documentation/git-diff-stages.txt b/Documentation/git-diff-stages.txt
deleted file mode 100644 (file)
index b8f45b8..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-git-diff-stages(1)
-==================
-
-NAME
-----
-git-diff-stages - Compares two merge stages in the index
-
-
-SYNOPSIS
---------
-'git-diff-stages' [<common diff options>] <stage1> <stage2> [<path>...]
-
-DESCRIPTION
------------
-DEPRECATED and will be removed in 1.5.1.
-
-Compares the content and mode of the blobs in two stages in an
-unmerged index file.
-
-OPTIONS
--------
-include::diff-options.txt[]
-
-<stage1>,<stage2>::
-       The stage number to be compared.
-
-Output format
--------------
-include::diff-format.txt[]
-
-
-Author
-------
-Written by Junio C Hamano <junkio@cox.net>
-
-Documentation
---------------
-Documentation by Junio C Hamano.
-
-GIT
----
-Part of the gitlink:git[7] suite
index 6a098df..12a531d 100644 (file)
@@ -23,6 +23,10 @@ tree and the index file, or the index file and the working tree.
        further add to the index but you still haven't.  You can
        stage these changes by using gitlink:git-add[1].
 
+       If exactly two paths are given, and at least one is untracked,
+       compare the two files / directories. This behavior can be
+       forced by --no-index.
+
 'git-diff' [--options] --cached [<commit>] [--] [<path>...]::
 
        This form is to view the changes you staged for the next
index 37fbf66..5b5c4c8 100644 (file)
@@ -8,7 +8,8 @@ git-name-rev - Find symbolic names for given revs
 
 SYNOPSIS
 --------
-'git-name-rev' [--tags] ( --all | --stdin | <committish>... )
+'git-name-rev' [--tags] [--refs=<pattern>]
+              ( --all | --stdin | <committish>... )
 
 DESCRIPTION
 -----------
@@ -22,6 +23,9 @@ OPTIONS
 --tags::
        Do not use branch names, but only tags to name the commits
 
+--refs=<pattern>::
+       Only use refs whose names match a given shell pattern.
+
 --all::
        List all commits reachable from all refs
 
index f96b304..a9fb6a9 100644 (file)
@@ -13,6 +13,7 @@ SYNOPSIS
 'git-remote' add [-t <branch>] [-m <branch>] [-f] <name> <url>
 'git-remote' show <name>
 'git-remote' prune <name>
+'git-remote' update [group]
 
 DESCRIPTION
 -----------
@@ -53,7 +54,17 @@ Gives some information about the remote <name>.
 
 Deletes all stale tracking branches under <name>.
 These stale branches have already been removed from the remote repository
-referenced by <name>, but are still locally available in "remotes/<name>".
+referenced by <name>, but are still locally available in
+"remotes/<name>".
+
+'update'::
+
+Fetch updates for a named set of remotes in the repository as defined by
+remotes.<group>.  If a named group is not specified on the command line,
+the configuration parameter remotes.default will get used; if
+remotes.default is not defined, all remotes which do not the
+configuration parameter remote.<name>.skipDefaultUpdate set to true will
+be updated.  (See gitlink:git-config[1]).
 
 
 DISCUSSION
diff --git a/Documentation/git-resolve.txt b/Documentation/git-resolve.txt
deleted file mode 100644 (file)
index 7fde665..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-git-resolve(1)
-==============
-
-NAME
-----
-git-resolve - Merge two commits
-
-
-SYNOPSIS
---------
-'git-resolve' <current> <merged> <message>
-
-DESCRIPTION
------------
-DEPRECATED and will be removed in 1.5.1.  Use `git-merge` instead.
-
-Given two commits and a merge message, merge the <merged> commit
-into <current> commit, with the commit log message <message>.
-
-When <current> is a descendant of <merged>, or <current> is an
-ancestor of <merged>, no new commit is created and the <message>
-is ignored.  The former is informally called "already up to
-date", and the latter is often called "fast forward".
-
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org> and
-Dan Holmsand <holmsand@gmail.com>.
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
-GIT
----
-Part of the gitlink:git[7] suite
-
index c742117..4f145ea 100644 (file)
@@ -27,6 +27,7 @@ SYNOPSIS
             [ \--pretty | \--header ]
             [ \--bisect ]
             [ \--merge ]
+            [ \--reverse ]
             [ \--walk-reflogs ]
             <commit>... [ \-- <paths>... ]
 
@@ -266,6 +267,10 @@ By default, the commits are shown in reverse chronological order.
        parent comes before all of its children, but otherwise things
        are still ordered in the commit timestamp order.
 
+--reverse::
+
+       Output the commits in reverse order.
+
 Object Traversal
 ~~~~~~~~~~~~~~~~
 
index 6ce6a39..cf094ca 100644 (file)
@@ -13,14 +13,13 @@ DESCRIPTION
 -----------
 git-svn is a simple conduit for changesets between Subversion and git.
 It is not to be confused with gitlink:git-svnimport[1], which is
-read-only and geared towards tracking multiple branches.
+read-only.
 
 git-svn was originally designed for an individual developer who wants a
 bidirectional flow of changesets between a single branch in Subversion
 and an arbitrary number of branches in git.  Since its inception,
 git-svn has gained the ability to track multiple branches in a manner
-similar to git-svnimport; but it cannot (yet) automatically detect new
-branches and tags like git-svnimport does.
+similar to git-svnimport.
 
 git-svn is especially useful when it comes to tracking repositories
 not organized in the way Subversion developers recommend (trunk,
@@ -31,26 +30,80 @@ COMMANDS
 --
 
 'init'::
-       Creates an empty git repository with additional metadata
-       directories for git-svn.  The Subversion URL must be specified
-       as a command-line argument.  Optionally, the target directory
-       to operate on can be specified as a second argument.  Normally
-       this command initializes the current directory.
+       Initializes an empty git repository with additional
+       metadata directories for git-svn.  The Subversion URL
+       may be specified as a command-line argument, or as full
+       URL arguments to -T/-t/-b.  Optionally, the target
+       directory to operate on can be specified as a second
+       argument.  Normally this command initializes the current
+       directory.
 
-'fetch'::
+-T<trunk_subdir>::
+--trunk=<trunk_subdir>::
+-t<tags_subdir>::
+--tags=<tags_subdir>::
+-b<branches_subdir>::
+--branches=<branches_subdir>::
+       These are optional command-line options for init.  Each of
+       these flags can point to a relative repository path
+       (--tags=project/tags') or a full url
+       (--tags=https://foo.org/project/tags)
 
-Fetch unfetched revisions from the Subversion URL we are
-tracking.  refs/remotes/git-svn will be updated to the
-latest revision.
+--no-metadata::
+       Set the 'noMetadata' option in the [svn-remote] config.
+--use-svm-props::
+       Set the 'useSvmProps' option in the [svn-remote] config.
+--use-svnsync-props::
+       Set the 'useSvnsyncProps' option in the [svn-remote] config.
+--rewrite-root=<URL>::
+       Set the 'rewriteRoot' option in the [svn-remote] config.
+--username=<USER>::
+       For transports that SVN handles authentication for (http,
+       https, and plain svn), specify the username.  For other
+       transports (eg svn+ssh://), you must include the username in
+       the URL, eg svn+ssh://foo@svn.bar.com/project
 
-Note: You should never attempt to modify the remotes/git-svn
-branch outside of git-svn.  Instead, create a branch from
-remotes/git-svn and work on that branch.  Use the 'dcommit'
-command (see below) to write git commits back to
-remotes/git-svn.
+--prefix=<prefix>
+       This allows one to specify a prefix which is prepended
+       to the names of remotes if trunk/branches/tags are
+       specified.  The prefix does not automatically include a
+       trailing slash, so be sure you include one in the
+       argument if that is what you want.  This is useful if
+       you wish to track multiple projects that share a common
+       repository.
+
+'fetch'::
 
-See '<<fetch-args,Additional Fetch Arguments>>' if you are interested in
-manually joining branches on commit.
+       Fetch unfetched revisions from the Subversion remote we are
+       tracking.  The name of the [svn-remote "..."] section in the
+       .git/config file may be specified as an optional command-line
+       argument.
+
+'clone'::
+       Runs 'init' and 'fetch'.  It will automatically create a
+       directory based on the basename of the URL passed to it;
+       or if a second argument is passed; it will create a directory
+       and work within that.  It accepts all arguments that the
+       'init' and 'fetch' commands accept; with the exception of
+       '--fetch-all'.   After a repository is cloned, the 'fetch'
+       command will be able to update revisions without affecting
+       the working tree; and the 'rebase' command will be able
+       to update the working tree with the latest changes.
+
+'rebase'::
+       This fetches revisions from the SVN parent of the current HEAD
+       and rebases the current (uncommitted to SVN) work against it.
+
+       This works similarly to 'svn update' or 'git-pull' except that
+       it preserves linear history with 'git-rebase' instead of
+       'git-merge' for ease of dcommit-ing with git-svn.
+
+       This accepts all options that 'git-svn fetch' and 'git-rebase'
+       accepts.  However '--fetch-all' only fetches from the current
+       [svn-remote], and not all [svn-remote] definitions.
+
+       Like 'git-rebase'; this requires that the working tree be clean
+       and have no uncommitted changes.
 
 'dcommit'::
        Commit each diff from a specified head directly to the SVN
@@ -96,16 +149,6 @@ manually joining branches on commit.
        commit.  All merging is assumed to have taken place
        independently of git-svn functions.
 
-'rebuild'::
-       Not a part of daily usage, but this is a useful command if
-       you've just cloned a repository (using gitlink:git-clone[1]) that was
-       tracked with git-svn.  Unfortunately, git-clone does not clone
-       git-svn metadata and the svn working tree that git-svn uses for
-       its operations.  This rebuilds the metadata so git-svn can
-       resume fetch operations.  A Subversion URL may be optionally
-       specified at the command-line if the directory/repository you're
-       tracking has moved or changed protocols.
-
 'show-ignore'::
        Recursively finds and lists the svn:ignore property on
        directories.  The output is suitable for appending to
@@ -122,53 +165,13 @@ manually joining branches on commit.
        repository (that has been init-ed with git-svn).
        The -r<revision> option is required for this.
 
-'graft-branches'::
-       This command attempts to detect merges/branches from already
-       imported history.  Techniques used currently include regexes,
-       file copies, and tree-matches).  This command generates (or
-       modifies) the $GIT_DIR/info/grafts file.  This command is
-       considered experimental, and inherently flawed because
-       merge-tracking in SVN is inherently flawed and inconsistent
-       across different repositories.
-
-'multi-init'::
-       This command supports git-svnimport-like command-line syntax for
-       importing repositories that are laid out as recommended by the
-       SVN folks.  This is a bit more tolerant than the git-svnimport
-       command-line syntax and doesn't require the user to figure out
-       where the repository URL ends and where the repository path
-       begins.
-
--T<trunk_subdir>::
---trunk=<trunk_subdir>::
--t<tags_subdir>::
---tags=<tags_subdir>::
--b<branches_subdir>::
---branches=<branches_subdir>::
-       These are the command-line options for multi-init.  Each of
-       these flags can point to a relative repository path
-       (--tags=project/tags') or a full url
-       (--tags=https://foo.org/project/tags)
-
---prefix=<prefix>
-       This allows one to specify a prefix which is prepended to the
-       names of remotes.  The prefix does not automatically include a
-       trailing slash, so be sure you include one in the argument if
-       that is what you want.  This is useful if you wish to track
-       multiple projects that share a common repository.
-
-'multi-fetch'::
-       This runs fetch on all known SVN branches we're tracking.  This
-       will NOT discover new branches (unlike git-svnimport), so
-       multi-init will need to be re-run (it's idempotent).
-
 --
 
 OPTIONS
 -------
 --
 
---shared::
+--shared[={false|true|umask|group|all|world|everybody}]::
 --template=<template_directory>::
        Only used with the 'init' command.
        These are passed directly to gitlink:git-init[1].
@@ -176,14 +179,15 @@ OPTIONS
 -r <ARG>::
 --revision <ARG>::
 
-Only used with the 'fetch' command.
+Used with the 'fetch' command.
 
-Takes any valid -r<argument> svn would accept and passes it
-directly to svn. -r<ARG1>:<ARG2> ranges and "{" DATE "}" syntax
-is also supported.  This is passed directly to svn, see svn
-documentation for more details.
+This allows revision ranges for partial/cauterized history
+to be supported.  $NUMBER, $NUMBER1:$NUMBER2 (numeric ranges),
+$NUMBER:HEAD, and BASE:$NUMBER are all supported.
 
-This can allow you to make partial mirrors when running fetch.
+This can allow you to make partial mirrors when running fetch;
+but is generally not recommended because history will be skipped
+and lost.
 
 -::
 --stdin::
@@ -270,7 +274,7 @@ config key: svn.repackflags
 -s<strategy>::
 --strategy=<strategy>::
 
-These are only used with the 'dcommit' command.
+These are only used with the 'dcommit' and 'rebase' commands.
 
 Passed directly to git-rebase when using 'dcommit' if a
 'git-reset' cannot be used (see dcommit).
@@ -289,75 +293,79 @@ ADVANCED OPTIONS
 ----------------
 --
 
--b<refname>::
---branch <refname>::
-Used with 'fetch', 'dcommit' or 'set-tree'.
-
-This can be used to join arbitrary git branches to remotes/git-svn
-on new commits where the tree object is equivalent.
-
-When used with different GIT_SVN_ID values, tags and branches in
-SVN can be tracked this way, as can some merges where the heads
-end up having completely equivalent content.  This can even be
-used to track branches across multiple SVN _repositories_.
-
-This option may be specified multiple times, once for each
-branch.
-
-config key: svn.branch
-
 -i<GIT_SVN_ID>::
 --id <GIT_SVN_ID>::
 
-This sets GIT_SVN_ID (instead of using the environment).  See the
-section on
-'<<tracking-multiple-repos,Tracking Multiple Repositories or Branches>>'
-for more information on using GIT_SVN_ID.
+This sets GIT_SVN_ID (instead of using the environment).  This
+allows the user to override the default refname to fetch from
+when tracking a single URL.  The 'log' and 'dcommit' commands
+no longer require this switch as an argument.
+
+-R<remote name>::
+--svn-remote <remote name>::
+       Specify the [svn-remote "<remote name>"] section to use,
+       this allows SVN multiple repositories to be tracked.
+       Default: "svn"
 
 --follow-parent::
        This is especially helpful when we're tracking a directory
        that has been moved around within the repository, or if we
        started tracking a branch and never tracked the trunk it was
-       descended from.
+       descended from. This feature is enabled by default, use
+       --no-follow-parent to disable it.
 
 config key: svn.followparent
 
---no-metadata::
-       This gets rid of the git-svn-id: lines at the end of every commit.
-
-       With this, you lose the ability to use the rebuild command.  If
-       you ever lose your .git/svn/git-svn/.rev_db file, you won't be
-       able to fetch again, either.  This is fine for one-shot imports.
-
-       The 'git-svn log' command will not work on repositories using this,
-       either.
-
-config key: svn.nometadata
-
 --
-
-COMPATIBILITY OPTIONS
----------------------
+CONFIG FILE-ONLY OPTIONS
+------------------------
 --
 
---upgrade::
-Only used with the 'rebuild' command.
-
-Run this if you used an old version of git-svn that used
-"git-svn-HEAD" instead of "remotes/git-svn" as the branch
-for tracking the remote.
-
---ignore-nodate::
-Only used with the 'fetch' command.
-
-By default git-svn will crash if it tries to import a revision
-from SVN which has '(no date)' listed as the date of the revision.
-This is repository corruption on SVN's part, plain and simple.
-But sometimes you really need those revisions anyway.
+svn.noMetadata::
+svn-remote.<name>.noMetadata::
+       This gets rid of the git-svn-id: lines at the end of every commit.
 
-If supplied git-svn will convert '(no date)' entries to the UNIX
-epoch (midnight on Jan. 1, 1970).  Yes, that's probably very wrong.
-SVN was very wrong.
+       If you lose your .git/svn/git-svn/.rev_db file, git-svn will not
+       be able to rebuild it and you won't be able to fetch again,
+       either.  This is fine for one-shot imports.
+
+       The 'git-svn log' command will not work on repositories using
+       this, either.  Using this conflicts with the 'useSvmProps'
+       option for (hopefully) obvious reasons.
+
+svn.useSvmProps::
+svn-remote.<name>.useSvmProps::
+       This allows git-svn to re-map repository URLs and UUIDs from
+       mirrors created using SVN::Mirror (or svk) for metadata.
+
+       If an SVN revision has a property, "svm:headrev", it is likely
+       that the revision was created by SVN::Mirror (also used by SVK).
+       The property contains a repository UUID and a revision.  We want
+       to make it look like we are mirroring the original URL, so
+       introduce a helper function that returns the original identity
+       URL and UUID, and use it when generating metadata in commit
+       messages.
+
+svn.useSvnsyncProps::
+svn-remote.<name>.useSvnsyncprops::
+       Similar to the useSvmProps option; this is for users
+       of the svnsync(1) command distributed with SVN 1.4.x and
+       later.
+
+svn-remote.<name>.rewriteRoot::
+       This allows users to create repositories from alternate
+       URLs.  For example, an administrator could run git-svn on the
+       server locally (accessing via file://) but wish to distribute
+       the repository with a public http:// or svn:// URL in the
+       metadata so users of it will see the public URL.
+
+Since the noMetadata, rewriteRoot, useSvnsyncProps and useSvmProps
+options all affect the metadata generated and used by git-svn; they
+*must* be set in the configuration file before any history is imported
+and these settings should never be changed once they are set.
+
+Additionally, only one of these four options can be used per-svn-remote
+section because they affect the 'git-svn-id:' metadata line.
 
 --
 
@@ -367,43 +375,37 @@ Basic Examples
 Tracking and contributing to a the trunk of a Subversion-managed project:
 
 ------------------------------------------------------------------------
-# Initialize a repo (like git init):
-       git-svn init http://svn.foo.org/project/trunk
-# Fetch remote revisions:
-       git-svn fetch
-# Create your own branch to hack on:
-       git checkout -b my-branch remotes/git-svn
-# Do some work, and then commit your new changes to SVN, as well as
-# automatically updating your working HEAD:
+# Clone a repo (like git clone):
+       git-svn clone http://svn.foo.org/project/trunk
+# Enter the newly cloned directory:
+       cd trunk
+# You should be on master branch, double-check with git-branch
+       git branch
+# Do some work and commit locally to git:
+       git commit ...
+# Something is committed to SVN, rebase your local changes against the
+# latest changes in SVN:
+       git-svn rebase
+# Now commit your changes (that were committed previously using git) to SVN,
+# as well as automatically updating your working HEAD:
        git-svn dcommit
-# Something is committed to SVN, rebase the latest into your branch:
-       git-svn fetch && git rebase remotes/git-svn
 # Append svn:ignore settings to the default git exclude file:
        git-svn show-ignore >> .git/info/exclude
 ------------------------------------------------------------------------
 
 Tracking and contributing to an entire Subversion-managed project
 (complete with a trunk, tags and branches):
-See also:
-'<<tracking-multiple-repos,Tracking Multiple Repositories or Branches>>'
 
 ------------------------------------------------------------------------
-# Initialize a repo (like git init):
-       git-svn multi-init http://svn.foo.org/project \
-               -T trunk -b branches -t tags
-# Fetch remote revisions:
-       git-svn multi-fetch
-# Create your own branch of trunk to hack on:
-       git checkout -b my-trunk remotes/trunk
-# Do some work, and then commit your new changes to SVN, as well as
-# automatically updating your working HEAD:
-       git-svn dcommit -i trunk
-# Something has been committed to trunk, rebase the latest into your branch:
-       git-svn multi-fetch && git rebase remotes/trunk
-# Append svn:ignore settings of trunk to the default git exclude file:
-       git-svn show-ignore -i trunk >> .git/info/exclude
-# Check for new branches and tags (no arguments are needed):
-       git-svn multi-init
+# Clone a repo (like git clone):
+       git-svn clone http://svn.foo.org/project -T trunk -b branches -t tags
+# View all branches and tags you have cloned:
+       git branch -r
+# Reset your master to trunk (or any other branch, replacing 'trunk'
+# with the appropriate name):
+       git reset --hard remotes/trunk
+# You may only dcommit to one branch/tag/trunk at a time.  The usage
+# of dcommit/rebase/show-ignore should be teh same as above.
 ------------------------------------------------------------------------
 
 REBASE VS. PULL/MERGE
@@ -416,7 +418,7 @@ pulled or merged from.  This is because the author favored
 
 If you use 'git-svn set-tree A..B' to commit several diffs and you do
 not have the latest remotes/git-svn merged into my-branch, you should
-use 'git rebase' to update your work branch instead of 'git pull' or
+use 'git-svn rebase' to update your work branch instead of 'git pull' or
 'git merge'.  'pull/merge' can cause non-linear history to be flattened
 when committing into SVN, which can lead to merge commits reversing
 previous commits in SVN.
@@ -426,67 +428,49 @@ DESIGN PHILOSOPHY
 Merge tracking in Subversion is lacking and doing branched development
 with Subversion is cumbersome as a result.  git-svn does not do
 automated merge/branch tracking by default and leaves it entirely up to
-the user on the git side.
-
-[[tracking-multiple-repos]]
-TRACKING MULTIPLE REPOSITORIES OR BRANCHES
-------------------------------------------
-Because git-svn does not care about relationships between different
-branches or directories in a Subversion repository, git-svn has a simple
-hack to allow it to track an arbitrary number of related _or_ unrelated
-SVN repositories via one git repository.  Simply use the --id/-i flag or
-set the GIT_SVN_ID environment variable to a name other other than
-"git-svn" (the default) and git-svn will ignore the contents of the
-$GIT_DIR/svn/git-svn directory and instead do all of its work in
-$GIT_DIR/svn/$GIT_SVN_ID for that invocation.  The interface branch will
-be remotes/$GIT_SVN_ID, instead of remotes/git-svn.  Any
-remotes/$GIT_SVN_ID branch should never be modified by the user outside
-of git-svn commands.
-
-[[fetch-args]]
-ADDITIONAL FETCH ARGUMENTS
---------------------------
-This is for advanced users, most users should ignore this section.
-
-Unfetched SVN revisions may be imported as children of existing commits
-by specifying additional arguments to 'fetch'.  Additional parents may
-optionally be specified in the form of sha1 hex sums at the
-command-line.  Unfetched SVN revisions may also be tied to particular
-git commits with the following syntax:
-
-------------------------------------------------
-       svn_revision_number=git_commit_sha1
-------------------------------------------------
-
-This allows you to tie unfetched SVN revision 375 to your current HEAD:
-
-------------------------------------------------
-       git-svn fetch 375=$(git-rev-parse HEAD)
-------------------------------------------------
-
-If you're tracking a directory that has moved, or otherwise been
-branched or tagged off of another directory in the repository and you
-care about the full history of the project, then you can use
-the --follow-parent option.
-
-------------------------------------------------
-       git-svn fetch --follow-parent
-------------------------------------------------
+the user on the git side.  git-svn does however follow copy
+history of the directory that it is tracking, however (much like
+how 'svn log' works).
 
 BUGS
 ----
 
-We ignore all SVN properties except svn:executable.  Too difficult to
-map them since we rely heavily on git write-tree being _exactly_ the
-same on both the SVN and git working trees and I prefer not to clutter
-working trees with metadata files.
+We ignore all SVN properties except svn:executable.  Any unhandled
+properties are logged to $GIT_DIR/svn/<refname>/unhandled.log
 
 Renamed and copied directories are not detected by git and hence not
 tracked when committing to SVN.  I do not plan on adding support for
 this as it's quite difficult and time-consuming to get working for all
-the possible corner cases (git doesn't do it, either).  Renamed and
-copied files are fully supported if they're similar enough for git to
-detect them.
+the possible corner cases (git doesn't do it, either).  Committing
+renamed and copied files are fully supported if they're similar enough
+for git to detect them.
+
+CONFIGURATION
+-------------
+
+git-svn stores [svn-remote] configuration information in the
+repository .git/config file.  It is similar the core git
+[remote] sections except 'fetch' keys do not accept glob
+arguments; but they are instead handled by the 'branches'
+and 'tags' keys.  Since some SVN repositories are oddly
+configured with multiple projects glob expansions such those
+listed below are allowed:
+
+------------------------------------------------------------------------
+[svn-remote "project-a"]
+       url = http://server.org/svn
+       branches = branches/*/project-a:refs/remotes/project-a/branches/*
+       tags = tags/*/project-a:refs/remotes/project-a/tags/*
+       trunk = trunk/project-a:refs/remotes/project-a/trunk
+------------------------------------------------------------------------
+
+Keep in mind that the '*' (asterisk) wildcard of the local ref
+(left of the ':') *must* be the farthest right path component;
+however the remote wildcard may be anywhere as long as it's own
+independent path componet (surrounded by '/' or EOL).   This
+type of configuration is not automatically created by 'init' and
+should be manually entered with a text-editor or using
+gitlink:git-config[1]
 
 SEE ALSO
 --------
index c0fa0d4..9a74747 100644 (file)
@@ -35,6 +35,16 @@ ifdef::stalenotes[]
 You are reading the documentation for the latest version of git.
 Documentation for older releases are available here:
 
+* link:v1.5.0.2/git.html[documentation for release 1.5.0.2]
+
+* link:v1.5.0.2/RelNotes-1.5.0.2.txt[release notes for 1.5.0.2]
+
+* link:v1.5.0.1/RelNotes-1.5.0.1.txt[release notes for 1.5.0.1]
+
+* link:v1.5.0/git.html[documentation for release 1.5.0]
+
+* link:v1.5.0/RelNotes-1.5.0.txt[release notes for 1.5.0]
+
 * link:v1.4.4.4/git.html[documentation for release 1.4.4.4]
 
 * link:v1.3.3/git.html[documentation for release 1.3.3]
index d10476b..d88ec23 100644 (file)
@@ -85,7 +85,7 @@ Fortunately I did not have to; what I have in the current branch
 
 ------------------------------------------------
 $ git checkout master
-$ git resolve master revert-c99 fast ;# this should be a fast forward
+$ git merge revert-c99 ;# this should be a fast forward
 Updating from 10d781b9caa4f71495c7b34963bef137216f86a8 to e3a693c...
  cache.h        |    8 ++++----
  commit.c       |    2 +-
@@ -95,13 +95,6 @@ Updating from 10d781b9caa4f71495c7b34963bef137216f86a8 to e3a693c...
  5 files changed, 8 insertions(+), 8 deletions(-)
 ------------------------------------------------
 
-The 'fast' in the above 'git resolve' is not a magic.  I knew this
-'resolve' would result in a fast forward merge, and if not, there is
-something very wrong (so I would do 'git reset' on the 'master' branch
-and examine the situation).  When a fast forward merge is done, the
-message parameter to 'git resolve' is discarded, because no new commit
-is created.  You could have said 'junk' or 'nothing' there as well.
-
 There is no need to redo the test at this point.  We fast forwarded
 and we know 'master' matches 'revert-c99' exactly.  In fact:
 
index 7b6dc22..34e9651 100644 (file)
@@ -2752,7 +2752,7 @@ stages to temporary files and calls a "merge" script on it:
 $ git-merge-index git-merge-one-file hello.c
 -------------------------------------------------
 
-and that is what higher level `git resolve` is implemented with.
+and that is what higher level `git merge -s resolve` is implemented with.
 
 How git stores objects efficiently: pack files
 ----------------------------------------------
index 32a9422..6abde8d 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.5.0.2.GIT
+DEF_VER=v1.5.0.GIT
 
 LF='
 '
index 64d29f7..8a42be9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -128,6 +128,7 @@ prefix = $(HOME)
 bindir = $(prefix)/bin
 gitexecdir = $(bindir)
 template_dir = $(prefix)/share/git-core/templates/
+ETC_GITCONFIG = $(prefix)/etc/gitconfig
 # DESTDIR=
 
 # default configuration for gitweb
@@ -176,7 +177,7 @@ SCRIPT_SH = \
        git-merge-one-file.sh git-parse-remote.sh \
        git-pull.sh git-rebase.sh \
        git-repack.sh git-request-pull.sh git-reset.sh \
-       git-resolve.sh git-revert.sh git-sh-setup.sh \
+       git-revert.sh git-sh-setup.sh \
        git-tag.sh git-verify-tag.sh \
        git-applymbox.sh git-applypatch.sh git-am.sh \
        git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
@@ -266,7 +267,8 @@ LIB_OBJS = \
        revision.o pager.o tree-walk.o xdiff-interface.o \
        write_or_die.o trace.o list-objects.o grep.o \
        alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
-       color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o
+       color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \
+       convert.o
 
 BUILTIN_OBJS = \
        builtin-add.o \
@@ -284,7 +286,6 @@ BUILTIN_OBJS = \
        builtin-diff.o \
        builtin-diff-files.o \
        builtin-diff-index.o \
-       builtin-diff-stages.o \
        builtin-diff-tree.o \
        builtin-fmt-merge-msg.o \
        builtin-for-each-ref.o \
@@ -296,6 +297,7 @@ BUILTIN_OBJS = \
        builtin-ls-tree.o \
        builtin-mailinfo.o \
        builtin-mailsplit.o \
+       builtin-merge-base.o \
        builtin-merge-file.o \
        builtin-mv.o \
        builtin-name-rev.o \
@@ -597,6 +599,7 @@ endif
 # Shell quote (do not use $(call) to accommodate ancient setups);
 
 SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER))
+ETC_GITCONFIG_SQ = $(subst ','\'',$(ETC_GITCONFIG))
 
 DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
 bindir_SQ = $(subst ','\'',$(bindir))
@@ -609,7 +612,8 @@ PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
 
 LIBS = $(GITLIBS) $(EXTLIBS)
 
-BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' $(COMPAT_CFLAGS)
+BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \
+       -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"' $(COMPAT_CFLAGS)
 LIB_OBJS += $(COMPAT_OBJS)
 
 ALL_CFLAGS += $(BASIC_CFLAGS)
@@ -825,7 +829,7 @@ GIT-CFLAGS: .FORCE-GIT-CFLAGS
 
 export NO_SVN_TESTS
 
-test: all
+test: all test-chmtime$X
        $(MAKE) -C t/ all
 
 test-date$X: test-date.c date.o ctype.o
@@ -840,6 +844,9 @@ test-dump-cache-tree$X: dump-cache-tree.o $(GITLIBS)
 test-sha1$X: test-sha1.o $(GITLIBS)
        $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
 
+test-chmtime$X: test-chmtime.c
+       $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $<
+
 check-sha1:: test-sha1$X
        ./test-sha1.sh
 
index 6a658bf..d5e055d 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes-1.5.0.3.txt
\ No newline at end of file
+Documentation/RelNotes-1.5.1.txt
\ No newline at end of file
index 7d52a06..d9c30d3 100644 (file)
@@ -262,7 +262,7 @@ static int write_tar_entry(const unsigned char *sha1,
        static struct strbuf path;
        int filenamelen = strlen(filename);
        void *buffer;
-       char type[20];
+       enum object_type type;
        unsigned long size;
 
        if (!path.alloc) {
@@ -283,7 +283,7 @@ static int write_tar_entry(const unsigned char *sha1,
                buffer = NULL;
                size = 0;
        } else {
-               buffer = read_sha1_file(sha1, type, &size);
+               buffer = read_sha1_file(sha1, &type, &size);
                if (!buffer)
                        die("cannot read %s", sha1_to_hex(sha1));
        }
index f31b8ed..7c49848 100644 (file)
@@ -167,7 +167,7 @@ static int write_zip_entry(const unsigned char *sha1,
        int pathlen;
        unsigned char *out;
        char *path;
-       char type[20];
+       enum object_type type;
        void *buffer = NULL;
        void *deflated = NULL;
 
@@ -195,7 +195,7 @@ static int write_zip_entry(const unsigned char *sha1,
                if (S_ISREG(mode) && zlib_compression_level != 0)
                        method = 8;
                result = 0;
-               buffer = read_sha1_file(sha1, type, &size);
+               buffer = read_sha1_file(sha1, &type, &size);
                if (!buffer)
                        die("cannot read %s", sha1_to_hex(sha1));
                crc = crc32(crc, buffer, size);
diff --git a/blob.c b/blob.c
index 9776bea..0a9ea41 100644 (file)
--- a/blob.c
+++ b/blob.c
@@ -30,18 +30,18 @@ int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size)
 
 int parse_blob(struct blob *item)
 {
-        char type[20];
+        enum object_type type;
         void *buffer;
         unsigned long size;
        int ret;
 
         if (item->object.parsed)
                 return 0;
-        buffer = read_sha1_file(item->object.sha1, type, &size);
+        buffer = read_sha1_file(item->object.sha1, &type, &size);
         if (!buffer)
                 return error("Could not read %s",
                              sha1_to_hex(item->object.sha1));
-        if (strcmp(type, blob_type))
+        if (type != OBJ_BLOB)
                 return error("Object %s not a blob",
                              sha1_to_hex(item->object.sha1));
        ret = parse_blob_buffer(item, buffer, size);
index bec95d6..38f6475 100644 (file)
@@ -28,6 +28,7 @@ static int newfd = -1;
 
 static int unidiff_zero;
 static int p_value = 1;
+static int p_value_known;
 static int check_index;
 static int write_index;
 static int cached;
@@ -144,6 +145,7 @@ struct patch {
        unsigned long deflate_origlen;
        int lines_added, lines_deleted;
        int score;
+       unsigned int is_toplevel_relative:1;
        unsigned int inaccurate_eof:1;
        unsigned int is_binary:1;
        unsigned int is_copy:1;
@@ -238,7 +240,7 @@ static int name_terminate(const char *name, int namelen, int c, int terminate)
        return 1;
 }
 
-static char * find_name(const char *line, char *def, int p_value, int terminate)
+static char *find_name(const char *line, char *def, int p_value, int terminate)
 {
        int len;
        const char *start = line;
@@ -311,11 +313,54 @@ static char * find_name(const char *line, char *def, int p_value, int terminate)
        return name;
 }
 
+static int count_slashes(const char *cp)
+{
+       int cnt = 0;
+       char ch;
+
+       while ((ch = *cp++))
+               if (ch == '/')
+                       cnt++;
+       return cnt;
+}
+
+/*
+ * Given the string after "--- " or "+++ ", guess the appropriate
+ * p_value for the given patch.
+ */
+static int guess_p_value(const char *nameline)
+{
+       char *name, *cp;
+       int val = -1;
+
+       if (is_dev_null(nameline))
+               return -1;
+       name = find_name(nameline, NULL, 0, TERM_SPACE | TERM_TAB);
+       if (!name)
+               return -1;
+       cp = strchr(name, '/');
+       if (!cp)
+               val = 0;
+       else if (prefix) {
+               /*
+                * Does it begin with "a/$our-prefix" and such?  Then this is
+                * very likely to apply to our directory.
+                */
+               if (!strncmp(name, prefix, prefix_length))
+                       val = count_slashes(prefix);
+               else {
+                       cp++;
+                       if (!strncmp(cp, prefix, prefix_length))
+                               val = count_slashes(prefix) + 1;
+               }
+       }
+       free(name);
+       return val;
+}
+
 /*
  * Get the name etc info from the --/+++ lines of a traditional patch header
  *
- * NOTE! This hardcodes "-p1" behaviour in filename detection.
- *
  * FIXME! The end-of-filename heuristics are kind of screwy. For existing
  * files, we can happily check the index for a match, but for creating a
  * new file we should try to match whatever "patch" does. I have no idea.
@@ -326,6 +371,16 @@ static void parse_traditional_patch(const char *first, const char *second, struc
 
        first += 4;     /* skip "--- " */
        second += 4;    /* skip "+++ " */
+       if (!p_value_known) {
+               int p, q;
+               p = guess_p_value(first);
+               q = guess_p_value(second);
+               if (p < 0) p = q;
+               if (0 <= p && p == q) {
+                       p_value = p;
+                       p_value_known = 1;
+               }
+       }
        if (is_dev_null(first)) {
                patch->is_new = 1;
                patch->is_delete = 0;
@@ -787,6 +842,7 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
 {
        unsigned long offset, len;
 
+       patch->is_toplevel_relative = 0;
        patch->is_rename = patch->is_copy = 0;
        patch->is_new = patch->is_delete = -1;
        patch->old_mode = patch->new_mode = 0;
@@ -831,6 +887,7 @@ static int find_header(char *line, unsigned long size, int *hdrsize, struct patc
                                        die("git diff header lacks filename information (line %d)", linenr);
                                patch->old_name = patch->new_name = patch->def_name;
                        }
+                       patch->is_toplevel_relative = 1;
                        *hdrsize = git_hdr_len;
                        return offset;
                }
@@ -1129,11 +1186,11 @@ static struct fragment *parse_binary_hunk(char **buf_p,
 
        *status_p = 0;
 
-       if (!strncmp(buffer, "delta ", 6)) {
+       if (!prefixcmp(buffer, "delta ")) {
                patch_method = BINARY_DELTA_DEFLATED;
                origlen = strtoul(buffer + 6, NULL, 10);
        }
-       else if (!strncmp(buffer, "literal ", 8)) {
+       else if (!prefixcmp(buffer, "literal ")) {
                patch_method = BINARY_LITERAL_DEFLATED;
                origlen = strtoul(buffer + 8, NULL, 10);
        }
@@ -1393,28 +1450,39 @@ static void show_stats(struct patch *patch)
        free(qname);
 }
 
-static int read_old_data(struct stat *st, const char *path, void *buf, unsigned long size)
+static int read_old_data(struct stat *st, const char *path, char **buf_p, unsigned long *alloc_p, unsigned long *size_p)
 {
        int fd;
        unsigned long got;
+       unsigned long nsize;
+       char *nbuf;
+       unsigned long size = *size_p;
+       char *buf = *buf_p;
 
        switch (st->st_mode & S_IFMT) {
        case S_IFLNK:
-               return readlink(path, buf, size);
+               return readlink(path, buf, size) != size;
        case S_IFREG:
                fd = open(path, O_RDONLY);
                if (fd < 0)
                        return error("unable to open %s", path);
                got = 0;
                for (;;) {
-                       int ret = xread(fd, (char *) buf + got, size - got);
+                       int ret = xread(fd, buf + got, size - got);
                        if (ret <= 0)
                                break;
                        got += ret;
                }
                close(fd);
-               return got;
-
+               nsize = got;
+               nbuf = buf;
+               if (convert_to_git(path, &nbuf, &nsize)) {
+                       free(buf);
+                       *buf_p = nbuf;
+                       *alloc_p = nsize;
+                       *size_p = nsize;
+               }
+               return got != size;
        default:
                return -1;
        }
@@ -1656,6 +1724,8 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
                        /* Ignore it, we already handled it */
                        break;
                default:
+                       if (apply_verbosely)
+                               error("invalid start of line: '%c'", first);
                        return -1;
                }
                patch += len;
@@ -1753,6 +1823,9 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
                }
        }
 
+       if (offset && apply_verbosely)
+               error("while searching for:\n%.*s", oldsize, oldlines);
+
        free(old);
        free(new);
        return offset;
@@ -1839,11 +1912,11 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
 
        if (has_sha1_file(sha1)) {
                /* We already have the postimage */
-               char type[10];
+               enum object_type type;
                unsigned long size;
 
                free(desc->buffer);
-               desc->buffer = read_sha1_file(sha1, type, &size);
+               desc->buffer = read_sha1_file(sha1, &type, &size);
                if (!desc->buffer)
                        return error("the necessary postimage %s for "
                                     "'%s' cannot be read",
@@ -1899,8 +1972,8 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
        buf = NULL;
        if (cached) {
                if (ce) {
-                       char type[20];
-                       buf = read_sha1_file(ce->sha1, type, &size);
+                       enum object_type type;
+                       buf = read_sha1_file(ce->sha1, &type, &size);
                        if (!buf)
                                return error("read of %s failed",
                                             patch->old_name);
@@ -1911,7 +1984,7 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *
                size = st->st_size;
                alloc = size + 8192;
                buf = xmalloc(alloc);
-               if (read_old_data(st, patch->old_name, buf, alloc) != size)
+               if (read_old_data(st, patch->old_name, &buf, &alloc, &size))
                        return error("read of %s failed", patch->old_name);
        }
 
@@ -2233,7 +2306,7 @@ static void patch_stats(struct patch *patch)
        }
 }
 
-static void remove_file(struct patch *patch)
+static void remove_file(struct patch *patch, int rmdir_empty)
 {
        if (write_index) {
                if (remove_file_from_cache(patch->old_name) < 0)
@@ -2241,7 +2314,7 @@ static void remove_file(struct patch *patch)
                cache_tree_invalidate_path(active_cache_tree, patch->old_name);
        }
        if (!cached) {
-               if (!unlink(patch->old_name)) {
+               if (!unlink(patch->old_name) && rmdir_empty) {
                        char *name = xstrdup(patch->old_name);
                        char *end = strrchr(name, '/');
                        while (end) {
@@ -2283,12 +2356,22 @@ 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;
+       char *nbuf;
+       unsigned long nsize;
 
        if (S_ISLNK(mode))
                /* Although buf:size is counted string, it also is NUL
                 * terminated.
                 */
                return symlink(buf, path);
+       nsize = size;
+       nbuf = (char *) buf;
+       if (convert_to_working_tree(path, &nbuf, &nsize)) {
+               free((char *) buf);
+               buf = nbuf;
+               size = nsize;
+       }
+
        fd = open(path, O_CREAT | O_EXCL | O_WRONLY, (mode & 0100) ? 0777 : 0666);
        if (fd < 0)
                return -1;
@@ -2374,7 +2457,7 @@ static void write_out_one_result(struct patch *patch, int phase)
 {
        if (patch->is_delete > 0) {
                if (phase == 0)
-                       remove_file(patch);
+                       remove_file(patch, 1);
                return;
        }
        if (patch->is_new > 0 || patch->is_copy) {
@@ -2387,7 +2470,7 @@ static void write_out_one_result(struct patch *patch, int phase)
         * thing: remove the old, write the new
         */
        if (phase == 0)
-               remove_file(patch);
+               remove_file(patch, 0);
        if (phase == 1)
                create_file(patch);
 }
@@ -2509,6 +2592,32 @@ static int use_patch(struct patch *p)
        return 1;
 }
 
+static void prefix_one(char **name)
+{
+       char *old_name = *name;
+       if (!old_name)
+               return;
+       *name = xstrdup(prefix_filename(prefix, prefix_length, *name));
+       free(old_name);
+}
+
+static void prefix_patches(struct patch *p)
+{
+       if (!prefix || p->is_toplevel_relative)
+               return;
+       for ( ; p; p = p->next) {
+               if (p->new_name == p->old_name) {
+                       char *prefixed = p->new_name;
+                       prefix_one(&prefixed);
+                       p->new_name = p->old_name = prefixed;
+               }
+               else {
+                       prefix_one(&p->new_name);
+                       prefix_one(&p->old_name);
+               }
+       }
+}
+
 static int apply_patch(int fd, const char *filename, int inaccurate_eof)
 {
        unsigned long offset, size;
@@ -2531,11 +2640,14 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
                        break;
                if (apply_in_reverse)
                        reverse_patches(patch);
+               if (prefix)
+                       prefix_patches(patch);
                if (use_patch(patch)) {
                        patch_stats(patch);
                        *listp = patch;
                        listp = &patch->next;
-               } else {
+               }
+               else {
                        /* perhaps free it a bit better? */
                        free(patch);
                        skipped_patch++;
@@ -2596,9 +2708,16 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
        int read_stdin = 1;
        int inaccurate_eof = 0;
        int errs = 0;
+       int is_not_gitdir = 0;
 
        const char *whitespace_option = NULL;
 
+       prefix = setup_git_directory_gently(&is_not_gitdir);
+       prefix_length = prefix ? strlen(prefix) : 0;
+       git_config(git_apply_config);
+       if (apply_default_whitespace)
+               parse_whitespace_option(apply_default_whitespace);
+
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
                char *end;
@@ -2609,15 +2728,16 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
                        read_stdin = 0;
                        continue;
                }
-               if (!strncmp(arg, "--exclude=", 10)) {
+               if (!prefixcmp(arg, "--exclude=")) {
                        struct excludes *x = xmalloc(sizeof(*x));
                        x->path = arg + 10;
                        x->next = excludes;
                        excludes = x;
                        continue;
                }
-               if (!strncmp(arg, "-p", 2)) {
+               if (!prefixcmp(arg, "-p")) {
                        p_value = atoi(arg + 2);
+                       p_value_known = 1;
                        continue;
                }
                if (!strcmp(arg, "--no-add")) {
@@ -2649,10 +2769,14 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
                        continue;
                }
                if (!strcmp(arg, "--index")) {
+                       if (is_not_gitdir)
+                               die("--index outside a repository");
                        check_index = 1;
                        continue;
                }
                if (!strcmp(arg, "--cached")) {
+                       if (is_not_gitdir)
+                               die("--cached outside a repository");
                        check_index = 1;
                        cached = 1;
                        continue;
@@ -2670,13 +2794,13 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
                        line_termination = 0;
                        continue;
                }
-               if (!strncmp(arg, "-C", 2)) {
+               if (!prefixcmp(arg, "-C")) {
                        p_context = strtoul(arg + 2, &end, 0);
                        if (*end != '\0')
                                die("unrecognized context count '%s'", arg + 2);
                        continue;
                }
-               if (!strncmp(arg, "--whitespace=", 13)) {
+               if (!prefixcmp(arg, "--whitespace=")) {
                        whitespace_option = arg + 13;
                        parse_whitespace_option(arg + 13);
                        continue;
@@ -2693,7 +2817,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
                        apply = apply_with_reject = apply_verbosely = 1;
                        continue;
                }
-               if (!strcmp(arg, "--verbose")) {
+               if (!strcmp(arg, "-v") || !strcmp(arg, "--verbose")) {
                        apply_verbosely = 1;
                        continue;
                }
@@ -2701,14 +2825,6 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
                        inaccurate_eof = 1;
                        continue;
                }
-
-               if (check_index && prefix_length < 0) {
-                       prefix = setup_git_directory();
-                       prefix_length = prefix ? strlen(prefix) : 0;
-                       git_config(git_apply_config);
-                       if (!whitespace_option && apply_default_whitespace)
-                               parse_whitespace_option(apply_default_whitespace);
-               }
                if (0 < prefix_length)
                        arg = prefix_filename(prefix, prefix_length, arg);
 
index f613ac2..8ea6cb1 100644 (file)
@@ -35,7 +35,7 @@ static int run_remote_archiver(const char *remote, int argc,
 
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
-               if (!strncmp("--exec=", arg, 7)) {
+               if (!prefixcmp(arg, "--exec=")) {
                        if (exec_at)
                                die("multiple --exec specified");
                        exec = arg + 7;
@@ -62,7 +62,7 @@ static int run_remote_archiver(const char *remote, int argc,
        if (buf[len-1] == '\n')
                buf[--len] = 0;
        if (strcmp(buf, "ACK")) {
-               if (len > 5 && !strncmp(buf, "NACK ", 5))
+               if (len > 5 && !prefixcmp(buf, "NACK "))
                        die("git-archive: NACK %s", buf + 5);
                die("git-archive: protocol error");
        }
@@ -166,11 +166,11 @@ int parse_archive_args(int argc, const char **argv, struct archiver *ar)
                        verbose = 1;
                        continue;
                }
-               if (!strncmp(arg, "--format=", 9)) {
+               if (!prefixcmp(arg, "--format=")) {
                        format = arg + 9;
                        continue;
                }
-               if (!strncmp(arg, "--prefix=", 9)) {
+               if (!prefixcmp(arg, "--prefix=")) {
                        base = arg + 9;
                        continue;
                }
@@ -218,7 +218,7 @@ static const char *extract_remote_arg(int *ac, const char **av)
                if (!strcmp(arg, "--"))
                        no_more_options = 1;
                if (!no_more_options) {
-                       if (!strncmp(arg, "--remote=", 9)) {
+                       if (!prefixcmp(arg, "--remote=")) {
                                if (remote)
                                        die("Multiple --remote specified");
                                remote = arg + 9;
index 1a752b9..9f7dd4e 100644 (file)
@@ -87,9 +87,9 @@ struct origin {
 static char *fill_origin_blob(struct origin *o, mmfile_t *file)
 {
        if (!o->file.ptr) {
-               char type[10];
+               enum object_type type;
                num_read_blob++;
-               file->ptr = read_sha1_file(o->blob_sha1, type,
+               file->ptr = read_sha1_file(o->blob_sha1, &type,
                                           (unsigned long *)(&(file->size)));
                o->file = *file;
        }
@@ -263,7 +263,6 @@ static struct origin *get_origin(struct scoreboard *sb,
 static int fill_blob_sha1(struct origin *origin)
 {
        unsigned mode;
-       char type[10];
 
        if (!is_null_sha1(origin->blob_sha1))
                return 0;
@@ -271,8 +270,7 @@ static int fill_blob_sha1(struct origin *origin)
                           origin->path,
                           origin->blob_sha1, &mode))
                goto error_out;
-       if (sha1_object_info(origin->blob_sha1, type, NULL) ||
-           strcmp(type, blob_type))
+       if (sha1_object_info(origin->blob_sha1, NULL) != OBJ_BLOB)
                goto error_out;
        return 0;
  error_out:
@@ -1322,10 +1320,10 @@ static void get_commit_info(struct commit *commit,
         * we now need to populate them for output.
         */
        if (!commit->buffer) {
-               char type[20];
+               enum object_type type;
                unsigned long size;
                commit->buffer =
-                       read_sha1_file(commit->object.sha1, type, &size);
+                       read_sha1_file(commit->object.sha1, &type, &size);
        }
        ret->author = author_buf;
        get_ac_line(commit->buffer, "\nauthor ",
@@ -2006,7 +2004,7 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
        buf[fin_size] = 0;
        origin->file.ptr = buf;
        origin->file.size = fin_size;
-       pretend_sha1_file(buf, fin_size, blob_type, origin->blob_sha1);
+       pretend_sha1_file(buf, fin_size, OBJ_BLOB, origin->blob_sha1);
        commit->util = origin;
 
        /*
@@ -2065,9 +2063,10 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
        int i, seen_dashdash, unk, opt;
        long bottom, top, lno;
        int output_option = 0;
+       int show_stats = 0;
        const char *revs_file = NULL;
        const char *final_commit_name = NULL;
-       char type[10];
+       enum object_type type;
        const char *bottomtop = NULL;
        const char *contents_from = NULL;
 
@@ -2086,6 +2085,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                        blank_boundary = 1;
                else if (!strcmp("--root", arg))
                        show_root = 1;
+               else if (!strcmp(arg, "--show-stats"))
+                       show_stats = 1;
                else if (!strcmp("-c", arg))
                        output_option |= OUTPUT_ANNOTATE_COMPAT;
                else if (!strcmp("-t", arg))
@@ -2094,17 +2095,17 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                        output_option |= OUTPUT_LONG_OBJECT_NAME;
                else if (!strcmp("-S", arg) && ++i < argc)
                        revs_file = argv[i];
-               else if (!strncmp("-M", arg, 2)) {
+               else if (!prefixcmp(arg, "-M")) {
                        opt |= PICKAXE_BLAME_MOVE;
                        blame_move_score = parse_score(arg+2);
                }
-               else if (!strncmp("-C", arg, 2)) {
+               else if (!prefixcmp(arg, "-C")) {
                        if (opt & PICKAXE_BLAME_COPY)
                                opt |= PICKAXE_BLAME_COPY_HARDER;
                        opt |= PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE;
                        blame_copy_score = parse_score(arg+2);
                }
-               else if (!strncmp("-L", arg, 2)) {
+               else if (!prefixcmp(arg, "-L")) {
                        if (!arg[2]) {
                                if (++i >= argc)
                                        usage(blame_usage);
@@ -2299,7 +2300,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                if (fill_blob_sha1(o))
                        die("no such path %s in %s", path, final_commit_name);
 
-               sb.final_buf = read_sha1_file(o->blob_sha1, type,
+               sb.final_buf = read_sha1_file(o->blob_sha1, &type,
                                              &sb.final_buf_size);
        }
        num_read_blob++;
@@ -2351,7 +2352,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                ent = e;
        }
 
-       if (DEBUG) {
+       if (show_stats) {
                printf("num read blob: %d\n", num_read_blob);
                printf("num get patch: %d\n", num_get_patch);
                printf("num commits: %d\n", num_commits);
index 2d8d61b..d0179b0 100644 (file)
@@ -59,7 +59,7 @@ int git_branch_config(const char *var, const char *value)
                branch_use_color = git_config_colorbool(var, value);
                return 0;
        }
-       if (!strncmp(var, "color.branch.", 13)) {
+       if (!prefixcmp(var, "color.branch.")) {
                int slot = parse_branch_color_slot(var, 13);
                color_parse(value, var, branch_colors[slot]);
                return 0;
@@ -134,7 +134,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
                 */
 
                if (!force &&
-                   !in_merge_bases(rev, head_rev)) {
+                   !in_merge_bases(rev, &head_rev, 1)) {
                        error("The branch '%s' is not a strict subset of "
                                "your current HEAD.\n"
                                "If you are sure you want to delete it, "
@@ -178,13 +178,13 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
        int len;
 
        /* Detect kind */
-       if (!strncmp(refname, "refs/heads/", 11)) {
+       if (!prefixcmp(refname, "refs/heads/")) {
                kind = REF_LOCAL_BRANCH;
                refname += 11;
-       } else if (!strncmp(refname, "refs/remotes/", 13)) {
+       } else if (!prefixcmp(refname, "refs/remotes/")) {
                kind = REF_REMOTE_BRANCH;
                refname += 13;
-       } else if (!strncmp(refname, "refs/tags/", 10)) {
+       } else if (!prefixcmp(refname, "refs/tags/")) {
                kind = REF_TAG;
                refname += 10;
        }
@@ -446,7 +446,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                        reflog = 1;
                        continue;
                }
-               if (!strncmp(arg, "--abbrev=", 9)) {
+               if (!prefixcmp(arg, "--abbrev=")) {
                        abbrev = atoi(arg+9);
                        continue;
                }
@@ -476,7 +476,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                detached = 1;
        }
        else {
-               if (strncmp(head, "refs/heads/", 11))
+               if (prefixcmp(head, "refs/heads/"))
                        die("HEAD not found below refs/heads!");
                head += 11;
        }
index 6c16bfa..d61d3d5 100644 (file)
@@ -79,7 +79,7 @@ static void pprint_tag(const unsigned char *sha1, const char *buf, unsigned long
 int cmd_cat_file(int argc, const char **argv, const char *prefix)
 {
        unsigned char sha1[20];
-       char type[20];
+       enum object_type type;
        void *buf;
        unsigned long size;
        int opt;
@@ -100,14 +100,16 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
        buf = NULL;
        switch (opt) {
        case 't':
-               if (!sha1_object_info(sha1, type, NULL)) {
-                       printf("%s\n", type);
+               type = sha1_object_info(sha1, NULL);
+               if (type > 0) {
+                       printf("%s\n", typename(type));
                        return 0;
                }
                break;
 
        case 's':
-               if (!sha1_object_info(sha1, type, &size)) {
+               type = sha1_object_info(sha1, &size);
+               if (type > 0) {
                        printf("%lu\n", size);
                        return 0;
                }
@@ -117,17 +119,18 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
                return !has_sha1_file(sha1);
 
        case 'p':
-               if (sha1_object_info(sha1, type, NULL))
+               type = sha1_object_info(sha1, NULL);
+               if (type < 0)
                        die("Not a valid object name %s", argv[2]);
 
                /* custom pretty-print here */
-               if (!strcmp(type, tree_type))
+               if (type == OBJ_TREE)
                        return cmd_ls_tree(2, argv + 1, NULL);
 
-               buf = read_sha1_file(sha1, type, &size);
+               buf = read_sha1_file(sha1, &type, &size);
                if (!buf)
                        die("Cannot read object %s", argv[2]);
-               if (!strcmp(type, tag_type)) {
+               if (type == OBJ_TAG) {
                        pprint_tag(sha1, buf, size);
                        return 0;
                }
index b097c88..afe4b0e 100644 (file)
@@ -223,12 +223,12 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)
                        to_tempfile = 1;
                        continue;
                }
-               if (!strncmp(arg, "--prefix=", 9)) {
+               if (!prefixcmp(arg, "--prefix=")) {
                        state.base_dir = arg+9;
                        state.base_dir_len = strlen(state.base_dir);
                        continue;
                }
-               if (!strncmp(arg, "--stage=", 8)) {
+               if (!prefixcmp(arg, "--stage=")) {
                        if (!strcmp(arg + 8, "all")) {
                                to_tempfile = 1;
                                checkout_stage = CHECKOUT_ALL;
index 2a818a0..4a8d8d8 100644 (file)
@@ -45,15 +45,14 @@ static void add_buffer(char **bufp, unsigned int *sizep, const char *fmt, ...)
        memcpy(buf + size, one_line, len);
 }
 
-static void check_valid(unsigned char *sha1, const char *expect)
+static void check_valid(unsigned char *sha1, enum object_type expect)
 {
-       char type[20];
-
-       if (sha1_object_info(sha1, type, NULL))
+       enum object_type type = sha1_object_info(sha1, NULL);
+       if (type < 0)
                die("%s is not a valid object", sha1_to_hex(sha1));
-       if (expect && strcmp(type, expect))
+       if (type != expect)
                die("%s is not a valid '%s' object", sha1_to_hex(sha1),
-                   expect);
+                   typename(expect));
 }
 
 /*
@@ -101,7 +100,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
        if (get_sha1(argv[1], tree_sha1))
                die("Not a valid object name %s", argv[1]);
 
-       check_valid(tree_sha1, tree_type);
+       check_valid(tree_sha1, OBJ_TREE);
        for (i = 2; i < argc; i += 2) {
                const char *a, *b;
                a = argv[i]; b = argv[i+1];
@@ -112,7 +111,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
                        die("Too many parents (%d max)", MAXPARENT);
                if (get_sha1(b, parent_sha1[parents]))
                        die("Not a valid object name %s", b);
-               check_valid(parent_sha1[parents], commit_type);
+               check_valid(parent_sha1[parents], OBJ_COMMIT);
                if (new_parent(parents))
                        parents++;
        }
index 0f9051d..f1433a4 100644 (file)
@@ -64,7 +64,7 @@ static int get_value(const char* key_, const char* regex_)
        int ret = -1;
        char *tl;
        char *global = NULL, *repo_config = NULL;
-       const char *local;
+       const char *system_wide = NULL, *local;
 
        local = getenv(CONFIG_ENVIRONMENT);
        if (!local) {
@@ -74,6 +74,7 @@ static int get_value(const char* key_, const char* regex_)
                        local = repo_config = xstrdup(git_path("config"));
                if (home)
                        global = xstrdup(mkpath("%s/.gitconfig", home));
+               system_wide = ETC_GITCONFIG;
        }
 
        key = xstrdup(key_);
@@ -103,11 +104,15 @@ static int get_value(const char* key_, const char* regex_)
                }
        }
 
+       if (do_all && system_wide)
+               git_config_from_file(show_config, system_wide);
        if (do_all && global)
                git_config_from_file(show_config, global);
        git_config_from_file(show_config, local);
        if (!do_all && !seen && global)
                git_config_from_file(show_config, global);
+       if (!do_all && !seen && system_wide)
+               git_config_from_file(show_config, system_wide);
 
        free(key);
        if (regexp) {
@@ -147,7 +152,10 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                        } else {
                                die("$HOME not set");
                        }
-               } else if (!strcmp(argv[1], "--rename-section")) {
+               }
+               else if (!strcmp(argv[1], "--system"))
+                       setenv("GIT_CONFIG", ETC_GITCONFIG, 1);
+               else if (!strcmp(argv[1], "--rename-section")) {
                        int ret;
                        if (argc != 4)
                                usage(git_config_set_usage);
@@ -159,7 +167,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                                return 1;
                        }
                        return 0;
-               } else
+               }
+               else
                        break;
                argc--;
                argv++;
index bcc6456..165917e 100644 (file)
@@ -52,7 +52,7 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
         * If --tags, then any tags are used.
         * Otherwise only annotated tags are used.
         */
-       if (!strncmp(path, "refs/tags/", 10)) {
+       if (!prefixcmp(path, "refs/tags/")) {
                if (object->type == OBJ_TAG)
                        prio = 2;
                else
@@ -254,12 +254,12 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
                        all = 1;
                else if (!strcmp(arg, "--tags"))
                        tags = 1;
-               else if (!strncmp(arg, "--abbrev=", 9)) {
+               else if (!prefixcmp(arg, "--abbrev=")) {
                        abbrev = strtoul(arg + 9, NULL, 10);
                        if (abbrev != 0 && (abbrev < MINIMUM_ABBREV || 40 < abbrev))
                                abbrev = DEFAULT_ABBREV;
                }
-               else if (!strncmp(arg, "--candidates=", 13)) {
+               else if (!prefixcmp(arg, "--candidates=")) {
                        max_candidates = strtoul(arg + 13, NULL, 10);
                        if (max_candidates < 1)
                                max_candidates = 1;
index 5d4a5c5..e1199f8 100644 (file)
 #include "builtin.h"
 
 static const char diff_files_usage[] =
-"git-diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]"
+"git-diff-files [-q] [-0/-1/2/3 |-c|--cc|-n|--no-index] [<common diff options>] [<path>...]"
 COMMON_DIFF_OPTIONS_HELP;
 
 int cmd_diff_files(int argc, const char **argv, const char *prefix)
 {
        struct rev_info rev;
-       int silent = 0;
+       int nongit = 0;
 
+       prefix = setup_git_directory_gently(&nongit);
        init_revisions(&rev, prefix);
        git_config(git_default_config); /* no "diff" UI options */
        rev.abbrev = 0;
 
        argc = setup_revisions(argc, argv, &rev, NULL);
-       while (1 < argc && argv[1][0] == '-') {
-               if (!strcmp(argv[1], "--base"))
-                       rev.max_count = 1;
-               else if (!strcmp(argv[1], "--ours"))
-                       rev.max_count = 2;
-               else if (!strcmp(argv[1], "--theirs"))
-                       rev.max_count = 3;
-               else if (!strcmp(argv[1], "-q"))
-                       silent = 1;
-               else
-                       usage(diff_files_usage);
-               argv++; argc--;
-       }
        if (!rev.diffopt.output_format)
                rev.diffopt.output_format = DIFF_FORMAT_RAW;
-
-       /*
-        * Make sure there are NO revision (i.e. pending object) parameter,
-        * rev.max_count is reasonable (0 <= n <= 3),
-        * there is no other revision filtering parameters.
-        */
-       if (rev.pending.nr ||
-           rev.min_age != -1 || rev.max_age != -1)
-               usage(diff_files_usage);
-       return run_diff_files(&rev, silent);
+       return run_diff_files_cmd(&rev, argc, argv);
 }
index 95a3db1..083599d 100644 (file)
@@ -38,5 +38,9 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
        if (rev.pending.nr != 1 ||
            rev.max_count != -1 || rev.min_age != -1 || rev.max_age != -1)
                usage(diff_cache_usage);
+       if (read_cache() < 0) {
+               perror("read_cache");
+               return -1;
+       }
        return run_diff_index(&rev, cached);
 }
diff --git a/builtin-diff-stages.c b/builtin-diff-stages.c
deleted file mode 100644 (file)
index 70bb898..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (c) 2005 Junio C Hamano
- */
-
-#include "cache.h"
-#include "diff.h"
-#include "builtin.h"
-
-static struct diff_options diff_options;
-
-static const char diff_stages_usage[] =
-"git-diff-stages [<common diff options>] <stage1> <stage2> [<path>...]"
-COMMON_DIFF_OPTIONS_HELP;
-
-static void diff_stages(int stage1, int stage2, const char **pathspec)
-{
-       int i = 0;
-       while (i < active_nr) {
-               struct cache_entry *ce, *stages[4] = { NULL, };
-               struct cache_entry *one, *two;
-               const char *name;
-               int len, skip;
-
-               ce = active_cache[i];
-               skip = !ce_path_match(ce, pathspec);
-               len = ce_namelen(ce);
-               name = ce->name;
-               for (;;) {
-                       int stage = ce_stage(ce);
-                       stages[stage] = ce;
-                       if (active_nr <= ++i)
-                               break;
-                       ce = active_cache[i];
-                       if (ce_namelen(ce) != len ||
-                           memcmp(name, ce->name, len))
-                               break;
-               }
-               one = stages[stage1];
-               two = stages[stage2];
-
-               if (skip || (!one && !two))
-                       continue;
-               if (!one)
-                       diff_addremove(&diff_options, '+', ntohl(two->ce_mode),
-                                      two->sha1, name, NULL);
-               else if (!two)
-                       diff_addremove(&diff_options, '-', ntohl(one->ce_mode),
-                                      one->sha1, name, NULL);
-               else if (hashcmp(one->sha1, two->sha1) ||
-                        (one->ce_mode != two->ce_mode) ||
-                        diff_options.find_copies_harder)
-                       diff_change(&diff_options,
-                                   ntohl(one->ce_mode), ntohl(two->ce_mode),
-                                   one->sha1, two->sha1, name, NULL);
-       }
-}
-
-int cmd_diff_stages(int ac, const char **av, const char *prefix)
-{
-       int stage1, stage2;
-       const char **pathspec = NULL;
-
-       git_config(git_default_config); /* no "diff" UI options */
-       read_cache();
-       diff_setup(&diff_options);
-       while (1 < ac && av[1][0] == '-') {
-               const char *arg = av[1];
-               if (!strcmp(arg, "-r"))
-                       ; /* as usual */
-               else {
-                       int diff_opt_cnt;
-                       diff_opt_cnt = diff_opt_parse(&diff_options,
-                                                     av+1, ac-1);
-                       if (diff_opt_cnt < 0)
-                               usage(diff_stages_usage);
-                       else if (diff_opt_cnt) {
-                               av += diff_opt_cnt;
-                               ac -= diff_opt_cnt;
-                               continue;
-                       }
-                       else
-                               usage(diff_stages_usage);
-               }
-               ac--; av++;
-       }
-
-       if (!diff_options.output_format)
-               diff_options.output_format = DIFF_FORMAT_RAW;
-
-       if (ac < 3 ||
-           sscanf(av[1], "%d", &stage1) != 1 ||
-           ! (0 <= stage1 && stage1 <= 3) ||
-           sscanf(av[2], "%d", &stage2) != 1 ||
-           ! (0 <= stage2 && stage2 <= 3))
-               usage(diff_stages_usage);
-
-       av += 3; /* The rest from av[0] are for paths restriction. */
-       pathspec = get_pathspec(prefix, av);
-
-       if (diff_setup_done(&diff_options) < 0)
-               usage(diff_stages_usage);
-
-       diff_stages(stage1, stage2, pathspec);
-       diffcore_std(&diff_options);
-       diff_flush(&diff_options);
-       return 0;
-}
index c387ebb..28b660a 100644 (file)
@@ -25,40 +25,6 @@ struct blobinfo {
 static const char builtin_diff_usage[] =
 "git-diff <options> <rev>{0,2} -- <path>*";
 
-static int builtin_diff_files(struct rev_info *revs,
-                             int argc, const char **argv)
-{
-       int silent = 0;
-       while (1 < argc) {
-               const char *arg = argv[1];
-               if (!strcmp(arg, "--base"))
-                       revs->max_count = 1;
-               else if (!strcmp(arg, "--ours"))
-                       revs->max_count = 2;
-               else if (!strcmp(arg, "--theirs"))
-                       revs->max_count = 3;
-               else if (!strcmp(arg, "-q"))
-                       silent = 1;
-               else
-                       usage(builtin_diff_usage);
-               argv++; argc--;
-       }
-       /*
-        * Make sure there are NO revision (i.e. pending object) parameter,
-        * specified rev.max_count is reasonable (0 <= n <= 3), and
-        * there is no other revision filtering parameter.
-        */
-       if (revs->pending.nr ||
-           revs->min_age != -1 ||
-           revs->max_age != -1 ||
-           3 < revs->max_count)
-               usage(builtin_diff_usage);
-       if (revs->max_count < 0 &&
-           (revs->diffopt.output_format & DIFF_FORMAT_PATCH))
-               revs->combine_merges = revs->dense_combined_merges = 1;
-       return run_diff_files(revs, silent);
-}
-
 static void stuff_change(struct diff_options *opt,
                         unsigned old_mode, unsigned new_mode,
                         const unsigned char *old_sha1,
@@ -151,6 +117,10 @@ static int builtin_diff_index(struct rev_info *revs,
            revs->max_count != -1 || revs->min_age != -1 ||
            revs->max_age != -1)
                usage(builtin_diff_usage);
+       if (read_cache() < 0) {
+               perror("read_cache");
+               return -1;
+       }
        return run_diff_index(revs, cached);
 }
 
@@ -219,6 +189,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
        int ents = 0, blobs = 0, paths = 0;
        const char *path = NULL;
        struct blobinfo blob[2];
+       int nongit = 0;
 
        /*
         * We could get N tree-ish in the rev.pending_objects list.
@@ -240,6 +211,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
         * Other cases are errors.
         */
 
+       prefix = setup_git_directory_gently(&nongit);
        git_config(git_diff_ui_config);
        init_revisions(&rev, prefix);
 
@@ -261,6 +233,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
                                break;
                        else if (!strcmp(arg, "--cached")) {
                                add_head(&rev);
+                               if (!rev.pending.nr)
+                                       die("No HEAD commit to compare with (yet)");
                                break;
                        }
                }
@@ -315,7 +289,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
        if (!ents) {
                switch (blobs) {
                case 0:
-                       return builtin_diff_files(&rev, argc, argv);
+                       return run_diff_files_cmd(&rev, argc, argv);
                        break;
                case 1:
                        if (paths != 1)
index 5be6fb4..5c145d2 100644 (file)
@@ -81,7 +81,7 @@ static int handle_line(char *line)
        if (len < 43 || line[40] != '\t')
                return 1;
 
-       if (!strncmp(line + 41, "not-for-merge", 13))
+       if (!prefixcmp(line + 41, "not-for-merge"))
                return 0;
 
        if (line[41] != '\t')
@@ -119,15 +119,15 @@ static int handle_line(char *line)
        if (pulling_head) {
                origin = xstrdup(src);
                src_data->head_status |= 1;
-       } else if (!strncmp(line, "branch ", 7)) {
+       } else if (!prefixcmp(line, "branch ")) {
                origin = xstrdup(line + 7);
                append_to_list(&src_data->branch, origin, NULL);
                src_data->head_status |= 2;
-       } else if (!strncmp(line, "tag ", 4)) {
+       } else if (!prefixcmp(line, "tag ")) {
                origin = line;
                append_to_list(&src_data->tag, xstrdup(origin + 4), NULL);
                src_data->head_status |= 2;
-       } else if (!strncmp(line, "remote branch ", 14)) {
+       } else if (!prefixcmp(line, "remote branch ")) {
                origin = xstrdup(line + 14);
                append_to_list(&src_data->r_branch, origin, NULL);
                src_data->head_status |= 2;
@@ -282,7 +282,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
        current_branch = resolve_ref("HEAD", head_sha1, 1, NULL);
        if (!current_branch)
                die("No current branch");
-       if (!strncmp(current_branch, "refs/heads/", 11))
+       if (!prefixcmp(current_branch, "refs/heads/"))
                current_branch += 11;
 
        while (fgets(line, sizeof(line), in)) {
index 16c785f..b11ca92 100644 (file)
@@ -173,8 +173,8 @@ static void verify_format(const char *format)
  */
 static void *get_obj(const unsigned char *sha1, struct object **obj, unsigned long *sz, int *eaten)
 {
-       char type[20];
-       void *buf = read_sha1_file(sha1, type, sz);
+       enum object_type type;
+       void *buf = read_sha1_file(sha1, &type, sz);
 
        if (buf)
                *obj = parse_object_buffer(sha1, type, *sz, buf, eaten);
@@ -196,7 +196,7 @@ static void grab_common_values(struct atom_value *val, int deref, struct object
                if (deref)
                        name++;
                if (!strcmp(name, "objecttype"))
-                       v->s = type_names[obj->type];
+                       v->s = typename(obj->type);
                else if (!strcmp(name, "objectsize")) {
                        char *s = xmalloc(40);
                        sprintf(s, "%lu", sz);
@@ -814,7 +814,7 @@ int cmd_for_each_ref(int ac, const char **av, char *prefix)
                        i++;
                        break;
                }
-               if (!strncmp(arg, "--format=", 9)) {
+               if (!prefixcmp(arg, "--format=")) {
                        if (format)
                                die("more than one --format?");
                        format = arg + 9;
@@ -844,7 +844,7 @@ int cmd_for_each_ref(int ac, const char **av, char *prefix)
                        quote_style = QUOTE_TCL;
                        continue;
                }
-               if (!strncmp(arg, "--count=", 8)) {
+               if (!prefixcmp(arg, "--count=")) {
                        if (maxcount)
                                die("more than one --count?");
                        maxcount = atoi(arg + 8);
@@ -852,7 +852,7 @@ int cmd_for_each_ref(int ac, const char **av, char *prefix)
                                die("The number %s did not parse", arg);
                        continue;
                }
-               if (!strncmp(arg, "--sort=", 7)) {
+               if (!prefixcmp(arg, "--sort=")) {
                        struct ref_sort *s = xcalloc(1, sizeof(*s));
                        int len;
 
index 6da3814..6abf498 100644 (file)
@@ -546,7 +546,7 @@ static int fsck_head_link(void)
 
        if (!head_points_at || !(flag & REF_ISSYMREF))
                return error("HEAD is not a symbolic ref");
-       if (strncmp(head_points_at, "refs/heads/", 11))
+       if (prefixcmp(head_points_at, "refs/heads/"))
                return error("HEAD points to something strange (%s)",
                             head_points_at);
        if (is_null_sha1(sha1))
index 2bfbdb7..96b7022 100644 (file)
@@ -84,11 +84,11 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char
 {
        unsigned long size;
        char *data;
-       char type[20];
+       enum object_type type;
        char *to_free = NULL;
        int hit;
 
-       data = read_sha1_file(sha1, type, &size);
+       data = read_sha1_file(sha1, &type, &size);
        if (!data) {
                error("'%s': unable to read %s", name, sha1_to_hex(sha1));
                return 0;
@@ -380,10 +380,10 @@ static int grep_tree(struct grep_opt *opt, const char **paths,
                else if (S_ISREG(entry.mode))
                        hit |= grep_sha1(opt, entry.sha1, path_buf, tn_len);
                else if (S_ISDIR(entry.mode)) {
-                       char type[20];
+                       enum object_type type;
                        struct tree_desc sub;
                        void *data;
-                       data = read_sha1_file(entry.sha1, type, &sub.size);
+                       data = read_sha1_file(entry.sha1, &type, &sub.size);
                        if (!data)
                                die("unable to read tree (%s)",
                                    sha1_to_hex(entry.sha1));
@@ -527,9 +527,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                        opt.word_regexp = 1;
                        continue;
                }
-               if (!strncmp("-A", arg, 2) ||
-                   !strncmp("-B", arg, 2) ||
-                   !strncmp("-C", arg, 2) ||
+               if (!prefixcmp(arg, "-A") ||
+                   !prefixcmp(arg, "-B") ||
+                   !prefixcmp(arg, "-C") ||
                    (arg[0] == '-' && '1' <= arg[1] && arg[1] <= '9')) {
                        unsigned num;
                        const char *scan;
index 12e43d0..4df9fd0 100644 (file)
@@ -283,11 +283,11 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
 
        for (i = 1; i < argc; i++, argv++) {
                const char *arg = argv[1];
-               if (!strncmp(arg, "--template=", 11))
+               if (!prefixcmp(arg, "--template="))
                        template_dir = arg+11;
                else if (!strcmp(arg, "--shared"))
                        shared_repository = PERM_GROUP;
-               else if (!strncmp(arg, "--shared=", 9))
+               else if (!prefixcmp(arg, "--shared="))
                        shared_repository = git_config_perm("arg", arg+9);
                else
                        usage(init_db_usage);
index a5e4b62..1c9f7d0 100644 (file)
@@ -32,7 +32,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
                rev->always_show_header = 0;
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
-               if (!strncmp(arg, "--encoding=", 11)) {
+               if (!prefixcmp(arg, "--encoding=")) {
                        arg += 11;
                        if (strcmp(arg, "none"))
                                git_log_output_encoding = strdup(arg);
@@ -89,8 +89,8 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)
 static int show_object(const unsigned char *sha1, int suppress_header)
 {
        unsigned long size;
-       char type[20];
-       char *buf = read_sha1_file(sha1, type, &size);
+       enum object_type type;
+       char *buf = read_sha1_file(sha1, &type, &size);
        int offset = 0;
 
        if (!buf)
@@ -293,7 +293,7 @@ static int reopen_stdout(struct commit *commit, int nr, int keep_subject)
 
                sol += 2;
                /* strip [PATCH] or [PATCH blabla] */
-               if (!keep_subject && !strncmp(sol, "[PATCH", 6)) {
+               if (!keep_subject && !prefixcmp(sol, "[PATCH")) {
                        char *eos = strchr(sol + 6, ']');
                        if (eos) {
                                while (isspace(*eos))
@@ -448,7 +448,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                else if (!strcmp(argv[i], "-n") ||
                                !strcmp(argv[i], "--numbered"))
                        numbered = 1;
-               else if (!strncmp(argv[i], "--start-number=", 15))
+               else if (!prefixcmp(argv[i], "--start-number="))
                        start_number = strtol(argv[i] + 15, NULL, 10);
                else if (!strcmp(argv[i], "--start-number")) {
                        i++;
@@ -484,13 +484,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                }
                else if (!strcmp(argv[i], "--attach"))
                        rev.mime_boundary = git_version_string;
-               else if (!strncmp(argv[i], "--attach=", 9))
+               else if (!prefixcmp(argv[i], "--attach="))
                        rev.mime_boundary = argv[i] + 9;
                else if (!strcmp(argv[i], "--ignore-if-in-upstream"))
                        ignore_if_in_upstream = 1;
                else if (!strcmp(argv[i], "--thread"))
                        thread = 1;
-               else if (!strncmp(argv[i], "--in-reply-to=", 14))
+               else if (!prefixcmp(argv[i], "--in-reply-to="))
                        in_reply_to = argv[i] + 14;
                else if (!strcmp(argv[i], "--in-reply-to")) {
                        i++;
@@ -498,7 +498,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                                die("Need a Message-Id for --in-reply-to");
                        in_reply_to = argv[i];
                }
-               else if (!strncmp(argv[i], "--suffix=", 9))
+               else if (!prefixcmp(argv[i], "--suffix="))
                        fmt_patch_suffix = argv[i] + 9;
                else
                        argv[j++] = argv[i];
index ac89eb2..4e1d5af 100644 (file)
@@ -406,7 +406,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
                        add_exclude(argv[++i], "", 0, &dir.exclude_list[EXC_CMDL]);
                        continue;
                }
-               if (!strncmp(arg, "--exclude=", 10)) {
+               if (!prefixcmp(arg, "--exclude=")) {
                        exc_given = 1;
                        add_exclude(arg+10, "", 0, &dir.exclude_list[EXC_CMDL]);
                        continue;
@@ -416,12 +416,12 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
                        add_excludes_from_file(&dir, argv[++i]);
                        continue;
                }
-               if (!strncmp(arg, "--exclude-from=", 15)) {
+               if (!prefixcmp(arg, "--exclude-from=")) {
                        exc_given = 1;
                        add_excludes_from_file(&dir, arg+15);
                        continue;
                }
-               if (!strncmp(arg, "--exclude-per-directory=", 24)) {
+               if (!prefixcmp(arg, "--exclude-per-directory=")) {
                        exc_given = 1;
                        dir.exclude_per_dir = arg + 24;
                        continue;
@@ -434,7 +434,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
                        error_unmatch = 1;
                        continue;
                }
-               if (!strncmp(arg, "--abbrev=", 9)) {
+               if (!prefixcmp(arg, "--abbrev=")) {
                        abbrev = strtoul(arg+9, NULL, 10);
                        if (abbrev && abbrev < MINIMUM_ABBREV)
                                abbrev = MINIMUM_ABBREV;
index 201defd..6472610 100644 (file)
@@ -118,7 +118,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
                                chomp_prefix = 0;
                                break;
                        }
-                       if (!strncmp(argv[1]+2, "abbrev=",7)) {
+                       if (!prefixcmp(argv[1]+2, "abbrev=")) {
                                abbrev = strtoul(argv[1]+9, NULL, 10);
                                if (abbrev && abbrev < MINIMUM_ABBREV)
                                        abbrev = MINIMUM_ABBREV;
index cf5ef29..766a37e 100644 (file)
@@ -847,7 +847,7 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)
                        metainfo_charset = def_charset;
                else if (!strcmp(argv[1], "-n"))
                        metainfo_charset = NULL;
-               else if (!strncmp(argv[1], "--encoding=", 11))
+               else if (!prefixcmp(argv[1], "--encoding="))
                        metainfo_charset = argv[1] + 11;
                else
                        usage(mailinfo_usage);
similarity index 79%
rename from merge-base.c
rename to builtin-merge-base.c
index 385f4ba..e35d362 100644 (file)
@@ -1,9 +1,7 @@
 #include "cache.h"
 #include "commit.h"
 
-static int show_all;
-
-static int merge_base(struct commit *rev1, struct commit *rev2)
+static int show_merge_base(struct commit *rev1, struct commit *rev2, int show_all)
 {
        struct commit_list *result = get_merge_bases(rev1, rev2, 0);
 
@@ -23,16 +21,16 @@ static int merge_base(struct commit *rev1, struct commit *rev2)
 static const char merge_base_usage[] =
 "git-merge-base [--all] <commit-id> <commit-id>";
 
-int main(int argc, char **argv)
+int cmd_merge_base(int argc, const char **argv, const char *prefix)
 {
        struct commit *rev1, *rev2;
        unsigned char rev1key[20], rev2key[20];
+       int show_all = 0;
 
-       setup_git_directory();
        git_config(git_default_config);
 
        while (1 < argc && argv[1][0] == '-') {
-               char *arg = argv[1];
+               const char *arg = argv[1];
                if (!strcmp(arg, "-a") || !strcmp(arg, "--all"))
                        show_all = 1;
                else
@@ -49,5 +47,5 @@ int main(int argc, char **argv)
        rev2 = lookup_commit_reference(rev2key);
        if (!rev1 || !rev2)
                return 1;
-       return merge_base(rev1, rev2);
+       return show_merge_base(rev1, rev2, show_all);
 }
index b4f15cc..c022224 100644 (file)
@@ -5,7 +5,7 @@
 #include "refs.h"
 
 static const char name_rev_usage[] =
-       "git-name-rev [--tags] ( --all | --stdin | committish [committish...] )\n";
+       "git-name-rev [--tags | --refs=<pattern>] ( --all | --stdin | committish [committish...] )\n";
 
 typedef struct rev_name {
        const char *tip_name;
@@ -57,13 +57,17 @@ copy_data:
                        parents;
                        parents = parents->next, parent_number++) {
                if (parent_number > 1) {
-                       char *new_name = xmalloc(strlen(tip_name)+8);
+                       int len = strlen(tip_name);
+                       char *new_name = xmalloc(len + 8);
 
+                       if (len > 2 && !strcmp(tip_name + len - 2, "^0"))
+                               len -= 2;
                        if (generation > 0)
-                               sprintf(new_name, "%s~%d^%d", tip_name,
+                               sprintf(new_name, "%.*s~%d^%d", len, tip_name,
                                                generation, parent_number);
                        else
-                               sprintf(new_name, "%s^%d", tip_name, parent_number);
+                               sprintf(new_name, "%.*s^%d", len, tip_name,
+                                               parent_number);
 
                        name_rev(parents->item, new_name,
                                merge_traversals + 1 , 0, 0);
@@ -74,13 +78,21 @@ copy_data:
        }
 }
 
+struct name_ref_data {
+       int tags_only;
+       const char *ref_filter;
+};
+
 static int name_ref(const char *path, const unsigned char *sha1, int flags, void *cb_data)
 {
        struct object *o = parse_object(sha1);
-       int tags_only = *(int*)cb_data;
+       struct name_ref_data *data = cb_data;
        int deref = 0;
 
-       if (tags_only && strncmp(path, "refs/tags/", 10))
+       if (data->tags_only && prefixcmp(path, "refs/tags/"))
+               return 0;
+
+       if (data->ref_filter && fnmatch(data->ref_filter, path, 0))
                return 0;
 
        while (o && o->type == OBJ_TAG) {
@@ -93,9 +105,9 @@ static int name_ref(const char *path, const unsigned char *sha1, int flags, void
        if (o && o->type == OBJ_COMMIT) {
                struct commit *commit = (struct commit *)o;
 
-               if (!strncmp(path, "refs/heads/", 11))
+               if (!prefixcmp(path, "refs/heads/"))
                        path = path + 11;
-               else if (!strncmp(path, "refs/", 5))
+               else if (!prefixcmp(path, "refs/"))
                        path = path + 5;
 
                name_rev(commit, xstrdup(path), 0, 0, deref);
@@ -119,17 +131,22 @@ static const char* get_rev_name(struct object *o)
 
        if (!n->generation)
                return n->tip_name;
-
-       snprintf(buffer, sizeof(buffer), "%s~%d", n->tip_name, n->generation);
-
-       return buffer;
+       else {
+               int len = strlen(n->tip_name);
+               if (len > 2 && !strcmp(n->tip_name + len - 2, "^0"))
+                       len -= 2;
+               snprintf(buffer, sizeof(buffer), "%.*s~%d", len, n->tip_name,
+                               n->generation);
+
+               return buffer;
+       }
 }
 
 int cmd_name_rev(int argc, const char **argv, const char *prefix)
 {
        struct object_array revs = { 0, 0, NULL };
        int as_is = 0, all = 0, transform_stdin = 0;
-       int tags_only = 0;
+       struct name_ref_data data = { 0, NULL };
 
        git_config(git_default_config);
 
@@ -146,7 +163,10 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
                                as_is = 1;
                                continue;
                        } else if (!strcmp(*argv, "--tags")) {
-                               tags_only = 1;
+                               data.tags_only = 1;
+                               continue;
+                       } else  if (!prefixcmp(*argv, "--refs=")) {
+                               data.ref_filter = *argv + 7;
                                continue;
                        } else if (!strcmp(*argv, "--all")) {
                                if (argc > 1)
@@ -185,7 +205,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
                add_object_array((struct object *)commit, *argv, &revs);
        }
 
-       for_each_ref(name_ref, &tags_only);
+       for_each_ref(name_ref, &data);
 
        if (transform_stdin) {
                char buffer[2048];
index 9713882..8cf24f4 100644 (file)
@@ -230,8 +230,8 @@ static unsigned char *find_packed_object_name(struct packed_git *p,
 static void *delta_against(void *buf, unsigned long size, struct object_entry *entry)
 {
        unsigned long othersize, delta_size;
-       char type[10];
-       void *otherbuf = read_sha1_file(entry->delta->sha1, type, &othersize);
+       enum object_type type;
+       void *otherbuf = read_sha1_file(entry->delta->sha1, &type, &othersize);
        void *delta_buf;
 
        if (!otherbuf)
@@ -375,7 +375,7 @@ static unsigned long write_object(struct sha1file *f,
                                  struct object_entry *entry)
 {
        unsigned long size;
-       char type[10];
+       enum object_type type;
        void *buf;
        unsigned char header[10];
        unsigned hdrlen, datalen;
@@ -416,7 +416,7 @@ static unsigned long write_object(struct sha1file *f,
        }
 
        if (!to_reuse) {
-               buf = read_sha1_file(entry->sha1, type, &size);
+               buf = read_sha1_file(entry->sha1, &type, &size);
                if (!buf)
                        die("unable to read %s", sha1_to_hex(entry->sha1));
                if (size != entry->size)
@@ -765,7 +765,7 @@ static struct pbase_tree_cache *pbase_tree_get(const unsigned char *sha1)
        struct pbase_tree_cache *ent, *nent;
        void *data;
        unsigned long size;
-       char type[20];
+       enum object_type type;
        int neigh;
        int my_ix = pbase_tree_cache_ix(sha1);
        int available_ix = -1;
@@ -792,10 +792,10 @@ static struct pbase_tree_cache *pbase_tree_get(const unsigned char *sha1)
        /* Did not find one.  Either we got a bogus request or
         * we need to read and perhaps cache.
         */
-       data = read_sha1_file(sha1, type, &size);
+       data = read_sha1_file(sha1, &type, &size);
        if (!data)
                return NULL;
-       if (strcmp(type, tree_type)) {
+       if (type != OBJ_TREE) {
                free(data);
                return NULL;
        }
@@ -854,19 +854,19 @@ static void add_pbase_object(struct tree_desc *tree,
 
        while (tree_entry(tree,&entry)) {
                unsigned long size;
-               char type[20];
+               enum object_type type;
 
                if (entry.pathlen != cmplen ||
                    memcmp(entry.path, name, cmplen) ||
                    !has_sha1_file(entry.sha1) ||
-                   sha1_object_info(entry.sha1, type, &size))
+                   (type = sha1_object_info(entry.sha1, &size)) < 0)
                        continue;
                if (name[cmplen] != '/') {
                        unsigned hash = name_hash(fullname);
                        add_object_entry(entry.sha1, hash, 1);
                        return;
                }
-               if (!strcmp(type, tree_type)) {
+               if (type == OBJ_TREE) {
                        struct tree_desc sub;
                        struct pbase_tree_cache *tree;
                        const char *down = name+cmplen+1;
@@ -978,8 +978,6 @@ static void add_preferred_base(unsigned char *sha1)
 
 static void check_object(struct object_entry *entry)
 {
-       char type[20];
-
        if (entry->in_pack && !entry->preferred_base) {
                struct packed_git *p = entry->in_pack;
                struct pack_window *w_curs = NULL;
@@ -1062,21 +1060,10 @@ static void check_object(struct object_entry *entry)
                /* Otherwise we would do the usual */
        }
 
-       if (sha1_object_info(entry->sha1, type, &entry->size))
+       entry->type = sha1_object_info(entry->sha1, &entry->size);
+       if (entry->type < 0)
                die("unable to get type of object %s",
                    sha1_to_hex(entry->sha1));
-
-       if (!strcmp(type, commit_type)) {
-               entry->type = OBJ_COMMIT;
-       } else if (!strcmp(type, tree_type)) {
-               entry->type = OBJ_TREE;
-       } else if (!strcmp(type, blob_type)) {
-               entry->type = OBJ_BLOB;
-       } else if (!strcmp(type, tag_type)) {
-               entry->type = OBJ_TAG;
-       } else
-               die("unable to pack object %s of type %s",
-                   sha1_to_hex(entry->sha1), type);
 }
 
 static unsigned int check_delta_limit(struct object_entry *me, unsigned int n)
@@ -1206,7 +1193,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
        struct object_entry *trg_entry = trg->entry;
        struct object_entry *src_entry = src->entry;
        unsigned long trg_size, src_size, delta_size, sizediff, max_size, sz;
-       char type[10];
+       enum object_type type;
        void *delta_buf;
 
        /* Don't bother doing diffs between different types */
@@ -1257,13 +1244,13 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
 
        /* Load data if not already done */
        if (!trg->data) {
-               trg->data = read_sha1_file(trg_entry->sha1, type, &sz);
+               trg->data = read_sha1_file(trg_entry->sha1, &type, &sz);
                if (sz != trg_size)
                        die("object %s inconsistent object length (%lu vs %lu)",
                            sha1_to_hex(trg_entry->sha1), sz, trg_size);
        }
        if (!src->data) {
-               src->data = read_sha1_file(src_entry->sha1, type, &sz);
+               src->data = read_sha1_file(src_entry->sha1, &type, &sz);
                if (sz != src_size)
                        die("object %s inconsistent object length (%lu vs %lu)",
                            sha1_to_hex(src_entry->sha1), sz, src_size);
@@ -1582,14 +1569,14 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                        incremental = 1;
                        continue;
                }
-               if (!strncmp("--window=", arg, 9)) {
+               if (!prefixcmp(arg, "--window=")) {
                        char *end;
                        window = strtoul(arg+9, &end, 0);
                        if (!arg[9] || *end)
                                usage(pack_usage);
                        continue;
                }
-               if (!strncmp("--depth=", arg, 8)) {
+               if (!prefixcmp(arg, "--depth=")) {
                        char *end;
                        depth = strtoul(arg+8, &end, 0);
                        if (!arg[8] || *end)
@@ -1625,7 +1612,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                        continue;
                }
                if (!strcmp("--unpacked", arg) ||
-                   !strncmp("--unpacked=", arg, 11) ||
+                   !prefixcmp(arg, "--unpacked=") ||
                    !strcmp("--reflog", arg) ||
                    !strcmp("--all", arg)) {
                        use_internal_rev_list = 1;
index 3de9b3e..d080e30 100644 (file)
@@ -36,7 +36,7 @@ static int handle_one_ref(const char *path, const unsigned char *sha1,
        /* Do not pack the symbolic refs */
        if ((flags & REF_ISSYMREF))
                return 0;
-       is_tag_ref = !strncmp(path, "refs/tags/", 10);
+       is_tag_ref = !prefixcmp(path, "refs/tags/");
 
        /* ALWAYS pack refs that were already packed or are tags */
        if (!cb->all && !is_tag_ref && !(flags & REF_ISPACKED))
index 6f0ba0d..09864b7 100644 (file)
@@ -10,15 +10,10 @@ static int show_only;
 
 static int prune_object(char *path, const char *filename, const unsigned char *sha1)
 {
-       char buf[20];
-       const char *type;
-
        if (show_only) {
-               if (sha1_object_info(sha1, buf, NULL))
-                       type = "unknown";
-               else
-                       type = buf;
-               printf("%s %s\n", sha1_to_hex(sha1), type);
+               enum object_type type = sha1_object_info(sha1, NULL);
+               printf("%s %s\n", sha1_to_hex(sha1),
+                      (type > 0) ? typename(type) : "unknown");
                return 0;
        }
        unlink(mkpath("%s/%s", path, filename));
index c45649e..979efcc 100644 (file)
@@ -32,7 +32,7 @@ static int expand_one_ref(const char *ref, const unsigned char *sha1, int flag,
        /* Ignore the "refs/" at the beginning of the refname */
        ref += 5;
 
-       if (!strncmp(ref, "tags/", 5))
+       if (!prefixcmp(ref, "tags/"))
                add_refspec(xstrdup(ref));
        return 0;
 }
@@ -149,10 +149,10 @@ static int get_remotes_uri(const char *repo, const char *uri[MAX_URI])
                int is_refspec;
                char *s, *p;
 
-               if (!strncmp("URL:", buffer, 4)) {
+               if (!prefixcmp(buffer, "URL:")) {
                        is_refspec = 0;
                        s = buffer + 4;
-               } else if (!strncmp("Push:", buffer, 5)) {
+               } else if (!prefixcmp(buffer, "Push:")) {
                        is_refspec = 1;
                        s = buffer + 5;
                } else
@@ -195,7 +195,7 @@ static int config_get_receivepack;
 
 static int get_remote_config(const char* key, const char* value)
 {
-       if (!strncmp(key, "remote.", 7) &&
+       if (!prefixcmp(key, "remote.") &&
            !strncmp(key + 7, config_repo, config_repo_len)) {
                if (!strcmp(key + 7 + config_repo_len, ".url")) {
                        if (config_current_uri < MAX_URI)
@@ -324,8 +324,8 @@ static int do_push(const char *repo)
                const char **dest_refspec = refspec;
                const char *dest = uri[i];
                const char *sender = "git-send-pack";
-               if (!strncmp(dest, "http://", 7) ||
-                   !strncmp(dest, "https://", 8))
+               if (!prefixcmp(dest, "http://") ||
+                   !prefixcmp(dest, "https://"))
                        sender = "git-http-push";
                else if (thin)
                        argv[dest_argc++] = "--thin";
@@ -373,7 +373,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
                        verbose=1;
                        continue;
                }
-               if (!strncmp(arg, "--repo=", 7)) {
+               if (!prefixcmp(arg, "--repo=")) {
                        repo = arg+7;
                        continue;
                }
@@ -397,11 +397,11 @@ int cmd_push(int argc, const char **argv, const char *prefix)
                        thin = 0;
                        continue;
                }
-               if (!strncmp(arg, "--receive-pack=", 15)) {
+               if (!prefixcmp(arg, "--receive-pack=")) {
                        receivepack = arg;
                        continue;
                }
-               if (!strncmp(arg, "--exec=", 7)) {
+               if (!prefixcmp(arg, "--exec=")) {
                        receivepack = arg;
                        continue;
                }
index 8ba436d..e477155 100644 (file)
@@ -133,7 +133,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
                 *  entries and put the entries from the tree under the
                 * given subdirectory.
                 */
-               if (!strncmp(arg, "--prefix=", 9)) {
+               if (!prefixcmp(arg, "--prefix=")) {
                        if (stage || opts.merge || opts.prefix)
                                usage(read_tree_usage);
                        opts.prefix = arg + 9;
@@ -179,7 +179,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
                        continue;
                }
 
-               if (!strncmp(arg, "--exclude-per-directory=", 24)) {
+               if (!prefixcmp(arg, "--exclude-per-directory=")) {
                        struct dir_struct *dir;
 
                        if (opts.dir)
index 65b845b..186aabc 100644 (file)
@@ -55,8 +55,8 @@ static int tree_is_complete(const unsigned char *sha1)
        desc.buf = tree->buffer;
        desc.size = tree->size;
        if (!desc.buf) {
-               char type[20];
-               void *data = read_sha1_file(sha1, type, &desc.size);
+               enum object_type type;
+               void *data = read_sha1_file(sha1, &type, &desc.size);
                if (!data) {
                        tree->object.flags |= INCOMPLETE;
                        return 0;
@@ -215,8 +215,8 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
                        old = lookup_commit_reference_gently(osha1, 1);
                if (!new && !is_null_sha1(nsha1))
                        new = lookup_commit_reference_gently(nsha1, 1);
-               if ((old && !in_merge_bases(old, cb->ref_commit)) ||
-                   (new && !in_merge_bases(new, cb->ref_commit)))
+               if ((old && !in_merge_bases(old, &cb->ref_commit, 1)) ||
+                   (new && !in_merge_bases(new, &cb->ref_commit, 1)))
                        goto prune;
        }
 
@@ -321,9 +321,9 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
                const char *arg = argv[i];
                if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
                        cb.dry_run = 1;
-               else if (!strncmp(arg, "--expire=", 9))
+               else if (!prefixcmp(arg, "--expire="))
                        cb.expire_total = approxidate(arg + 9);
-               else if (!strncmp(arg, "--expire-unreachable=", 21))
+               else if (!prefixcmp(arg, "--expire-unreachable="))
                        cb.expire_unreachable = approxidate(arg + 21);
                else if (!strcmp(arg, "--stale-fix"))
                        cb.stalefix = 1;
index 58c5fed..b8867ab 100644 (file)
@@ -105,11 +105,11 @@ static int handle_file(const char *path,
                SHA1_Init(&ctx);
 
        while (fgets(buf, sizeof(buf), f)) {
-               if (!strncmp("<<<<<<< ", buf, 8))
+               if (!prefixcmp(buf, "<<<<<<< "))
                        hunk = 1;
-               else if (!strncmp("=======", buf, 7))
+               else if (!prefixcmp(buf, "======="))
                        hunk = 2;
-               else if (!strncmp(">>>>>>> ", buf, 8)) {
+               else if (!prefixcmp(buf, ">>>>>>> ")) {
                        hunk_no++;
                        hunk = 0;
                        if (memcmp(one->ptr, two->ptr, one->nr < two->nr ?
index d53deaa..37addb2 100644 (file)
@@ -233,7 +233,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                        }
                        continue;
                }
-               if (!strncmp(arg,"-n",2)) {
+               if (!prefixcmp(arg, "-n")) {
                        if ((filter & DO_FLAGS) && (filter & DO_REVS))
                                show(arg);
                        continue;
@@ -274,7 +274,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                                continue;
                        }
                        if (!strcmp(arg, "--short") ||
-                           !strncmp(arg, "--short=", 8)) {
+                           !prefixcmp(arg, "--short=")) {
                                filter &= ~(DO_FLAGS|DO_NOREV);
                                verify = 1;
                                abbrev = DEFAULT_ABBREV;
@@ -352,19 +352,19 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                                                : "false");
                                continue;
                        }
-                       if (!strncmp(arg, "--since=", 8)) {
+                       if (!prefixcmp(arg, "--since=")) {
                                show_datestring("--max-age=", arg+8);
                                continue;
                        }
-                       if (!strncmp(arg, "--after=", 8)) {
+                       if (!prefixcmp(arg, "--after=")) {
                                show_datestring("--max-age=", arg+8);
                                continue;
                        }
-                       if (!strncmp(arg, "--before=", 9)) {
+                       if (!prefixcmp(arg, "--before=")) {
                                show_datestring("--min-age=", arg+9);
                                continue;
                        }
-                       if (!strncmp(arg, "--until=", 8)) {
+                       if (!prefixcmp(arg, "--until=")) {
                                show_datestring("--min-age=", arg+8);
                                continue;
                        }
index edb4042..2f71a2a 100644 (file)
@@ -124,7 +124,7 @@ static void insert_author_oneline(struct path_list *list,
        else
                free(buffer);
 
-       if (!strncmp(oneline, "[PATCH", 6)) {
+       if (!prefixcmp(oneline, "[PATCH")) {
                char *eob = strchr(oneline, ']');
 
                if (eob) {
@@ -179,7 +179,7 @@ static void read_from_stdin(struct path_list *list)
        while (fgets(buffer, sizeof(buffer), stdin) != NULL) {
                char *bob;
                if ((buffer[0] == 'A' || buffer[0] == 'a') &&
-                               !strncmp(buffer + 1, "uthor: ", 7) &&
+                               !prefixcmp(buffer + 1, "uthor: ") &&
                                (bob = strchr(buffer + 7, '<')) != NULL) {
                        char buffer2[1024], offset = 0;
 
@@ -230,7 +230,7 @@ static void get_from_rev(struct rev_info *rev, struct path_list *list)
                        else
                                eol++;
 
-                       if (!strncmp(buffer, "author ", 7)) {
+                       if (!prefixcmp(buffer, "author ")) {
                                char *bracket = strchr(buffer, '<');
 
                                if (bracket == NULL || bracket > eol)
index 0d94e40..67ae6ba 100644 (file)
@@ -266,7 +266,7 @@ static void show_one_commit(struct commit *commit, int no_name)
                                    pretty, sizeof(pretty), 0, NULL, NULL, 0);
        else
                strcpy(pretty, "(unavailable)");
-       if (!strncmp(pretty, "[PATCH] ", 8))
+       if (!prefixcmp(pretty, "[PATCH] "))
                cp = pretty + 8;
        else
                cp = pretty;
@@ -378,7 +378,7 @@ static int append_head_ref(const char *refname, const unsigned char *sha1, int f
 {
        unsigned char tmp[20];
        int ofs = 11;
-       if (strncmp(refname, "refs/heads/", ofs))
+       if (prefixcmp(refname, "refs/heads/"))
                return 0;
        /* If both heads/foo and tags/foo exists, get_sha1 would
         * get confused.
@@ -392,7 +392,7 @@ static int append_remote_ref(const char *refname, const unsigned char *sha1, int
 {
        unsigned char tmp[20];
        int ofs = 13;
-       if (strncmp(refname, "refs/remotes/", ofs))
+       if (prefixcmp(refname, "refs/remotes/"))
                return 0;
        /* If both heads/foo and tags/foo exists, get_sha1 would
         * get confused.
@@ -404,7 +404,7 @@ static int append_remote_ref(const char *refname, const unsigned char *sha1, int
 
 static int append_tag_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
 {
-       if (strncmp(refname, "refs/tags/", 10))
+       if (prefixcmp(refname, "refs/tags/"))
                return 0;
        return append_ref(refname + 5, sha1, 0);
 }
@@ -435,9 +435,9 @@ static int append_matching_ref(const char *refname, const unsigned char *sha1, i
                return 0;
        if (fnmatch(match_ref_pattern, tail, 0))
                return 0;
-       if (!strncmp("refs/heads/", refname, 11))
+       if (!prefixcmp(refname, "refs/heads/"))
                return append_head_ref(refname, sha1, flag, cb_data);
-       if (!strncmp("refs/tags/", refname, 10))
+       if (!prefixcmp(refname, "refs/tags/"))
                return append_tag_ref(refname, sha1, flag, cb_data);
        return append_ref(refname, sha1, 0);
 }
@@ -462,11 +462,11 @@ static int rev_is_head(char *head, int headlen, char *name,
        if ((!head[0]) ||
            (head_sha1 && sha1 && hashcmp(head_sha1, sha1)))
                return 0;
-       if (!strncmp(head, "refs/heads/", 11))
+       if (!prefixcmp(head, "refs/heads/"))
                head += 11;
-       if (!strncmp(name, "refs/heads/", 11))
+       if (!prefixcmp(name, "refs/heads/"))
                name += 11;
-       else if (!strncmp(name, "heads/", 6))
+       else if (!prefixcmp(name, "heads/"))
                name += 6;
        return !strcmp(head, name);
 }
@@ -635,7 +635,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                        with_current_branch = 1;
                else if (!strcmp(arg, "--sha1-name"))
                        sha1_name = 1;
-               else if (!strncmp(arg, "--more=", 7))
+               else if (!prefixcmp(arg, "--more="))
                        extra = atoi(arg + 7);
                else if (!strcmp(arg, "--merge-base"))
                        merge_base = 1;
@@ -652,9 +652,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                else if (!strcmp(arg, "--reflog") || !strcmp(arg, "-g")) {
                        reflog = DEFAULT_REFLOG;
                }
-               else if (!strncmp(arg, "--reflog=", 9))
+               else if (!prefixcmp(arg, "--reflog="))
                        parse_reflog_param(arg + 9, &reflog, &reflog_base);
-               else if (!strncmp(arg, "-g=", 3))
+               else if (!prefixcmp(arg, "-g="))
                        parse_reflog_param(arg + 3, &reflog, &reflog_base);
                else
                        usage(show_branch_usage);
index 75211e6..9463ff0 100644 (file)
@@ -28,8 +28,8 @@ static int show_ref(const char *refname, const unsigned char *sha1, int flag, vo
        if (tags_only || heads_only) {
                int match;
 
-               match = heads_only && !strncmp(refname, "refs/heads/", 11);
-               match |= tags_only && !strncmp(refname, "refs/tags/", 10);
+               match = heads_only && !prefixcmp(refname, "refs/heads/");
+               match |= tags_only && !prefixcmp(refname, "refs/tags/");
                if (!match)
                        return 0;
        }
@@ -178,8 +178,8 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
                        hash_only = 1;
                        continue;
                }
-               if (!strncmp(arg, "--hash=", 7) ||
-                   (!strncmp(arg, "--abbrev", 8) &&
+               if (!prefixcmp(arg, "--hash=") ||
+                   (!prefixcmp(arg, "--abbrev") &&
                     (arg[8] == '=' || arg[8] == '\0'))) {
                        if (arg[2] != 'h' && !arg[8])
                                /* --abbrev only */
@@ -215,7 +215,7 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
                }
                if (!strcmp(arg, "--exclude-existing"))
                        return exclude_existing(NULL);
-               if (!strncmp(arg, "--exclude-existing=", 19))
+               if (!prefixcmp(arg, "--exclude-existing="))
                        return exclude_existing(arg + 19);
                usage(show_ref_usage);
        }
@@ -226,7 +226,7 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
                while (*pattern) {
                        unsigned char sha1[20];
 
-                       if (!strncmp(*pattern, "refs/", 5) &&
+                       if (!prefixcmp(*pattern, "refs/") &&
                            resolve_ref(*pattern, sha1, 1, NULL)) {
                                if (!quiet)
                                        show_one(*pattern, sha1);
index 8055dda..b04719e 100644 (file)
@@ -31,7 +31,7 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix)
        nargv[nargc++] = "git-archive";
        nargv[nargc++] = "--format=tar";
 
-       if (2 <= argc && !strncmp("--remote=", argv[1], 9)) {
+       if (2 <= argc && !prefixcmp(argv[1], "--remote=")) {
                nargv[nargc++] = argv[1];
                argv++;
                argc--;
index d351e02..3956c56 100644 (file)
@@ -119,18 +119,18 @@ struct obj_info {
 
 static struct obj_info *obj_list;
 
-static void added_object(unsigned nr, const char *type, void *data,
-                        unsigned long size);
+static void added_object(unsigned nr, enum object_type type,
+                        void *data, unsigned long size);
 
-static void write_object(unsigned nr, void *buf, unsigned long size,
-                        const char *type)
+static void write_object(unsigned nr, enum object_type type,
+                        void *buf, unsigned long size)
 {
-       if (write_sha1_file(buf, size, type, obj_list[nr].sha1) < 0)
+       if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
                die("failed to write object");
        added_object(nr, type, buf, size);
 }
 
-static void resolve_delta(unsigned nr, const char *type,
+static void resolve_delta(unsigned nr, enum object_type type,
                          void *base, unsigned long base_size,
                          void *delta, unsigned long delta_size)
 {
@@ -143,12 +143,12 @@ static void resolve_delta(unsigned nr, const char *type,
        if (!result)
                die("failed to apply delta");
        free(delta);
-       write_object(nr, result, result_size, type);
+       write_object(nr, type, result, result_size);
        free(result);
 }
 
-static void added_object(unsigned nr, const char *type, void *data,
-                        unsigned long size)
+static void added_object(unsigned nr, enum object_type type,
+                        void *data, unsigned long size)
 {
        struct delta_info **p = &delta_list;
        struct delta_info *info;
@@ -167,33 +167,24 @@ static void added_object(unsigned nr, const char *type, void *data,
        }
 }
 
-static void unpack_non_delta_entry(enum object_type kind, unsigned long size,
+static void unpack_non_delta_entry(enum object_type type, unsigned long size,
                                   unsigned nr)
 {
        void *buf = get_data(size);
-       const char *type;
-
-       switch (kind) {
-       case OBJ_COMMIT: type = commit_type; break;
-       case OBJ_TREE:   type = tree_type; break;
-       case OBJ_BLOB:   type = blob_type; break;
-       case OBJ_TAG:    type = tag_type; break;
-       default: die("bad type %d", kind);
-       }
+
        if (!dry_run && buf)
-               write_object(nr, buf, size, type);
+               write_object(nr, type, buf, size);
        free(buf);
 }
 
-static void unpack_delta_entry(enum object_type kind, unsigned long delta_size,
+static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
                               unsigned nr)
 {
        void *delta_data, *base;
        unsigned long base_size;
-       char type[20];
        unsigned char base_sha1[20];
 
-       if (kind == OBJ_REF_DELTA) {
+       if (type == OBJ_REF_DELTA) {
                hashcpy(base_sha1, fill(20));
                use(20);
                delta_data = get_data(delta_size);
@@ -255,7 +246,7 @@ static void unpack_delta_entry(enum object_type kind, unsigned long delta_size,
                }
        }
 
-       base = read_sha1_file(base_sha1, type, &base_size);
+       base = read_sha1_file(base_sha1, &type, &base_size);
        if (!base) {
                error("failed to read delta-pack base object %s",
                      sha1_to_hex(base_sha1));
@@ -369,7 +360,7 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
                                recover = 1;
                                continue;
                        }
-                       if (!strncmp(arg, "--pack_header=", 14)) {
+                       if (!prefixcmp(arg, "--pack_header=")) {
                                struct pack_header *hdr;
                                char *c;
 
index 772aaba..65246da 100644 (file)
@@ -487,6 +487,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
        int prefix_length = prefix ? strlen(prefix) : 0;
        char set_executable_bit = 0;
        unsigned int refresh_flags = 0;
+       int lock_error = 0;
        struct lock_file *lock_file;
 
        git_config(git_default_config);
@@ -494,7 +495,9 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
        /* We can't free this memory, it becomes part of a linked list parsed atexit() */
        lock_file = xcalloc(1, sizeof(struct lock_file));
 
-       newfd = hold_lock_file_for_update(lock_file, get_index_file(), 1);
+       newfd = hold_lock_file_for_update(lock_file, get_index_file(), 0);
+       if (newfd < 0)
+               lock_error = errno;
 
        entries = read_cache();
        if (entries < 0)
@@ -651,6 +654,12 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
 
  finish:
        if (active_cache_changed) {
+               if (newfd < 0) {
+                       if (refresh_flags & REFRESH_QUIET)
+                               exit(128);
+                       die("unable to create '%s.lock': %s",
+                           get_index_file(), strerror(lock_error));
+               }
                if (write_cache(newfd, active_cache, active_nr) ||
                    close(newfd) || commit_lock_file(lock_file))
                        die("Unable to write new index file");
index 50670dc..90fc1cf 100644 (file)
@@ -70,7 +70,7 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)
                const char *arg = argv[1];
                if (!strcmp(arg, "--missing-ok"))
                        missing_ok = 1;
-               else if (!strncmp(arg, "--prefix=", 9))
+               else if (!prefixcmp(arg, "--prefix="))
                        prefix = arg + 9;
                else
                        usage(write_tree_usage);
index 5108fd2..57e8741 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -29,7 +29,6 @@ extern int cmd_describe(int argc, const char **argv, const char *prefix);
 extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
 extern int cmd_diff_index(int argc, const char **argv, const char *prefix);
 extern int cmd_diff(int argc, const char **argv, const char *prefix);
-extern int cmd_diff_stages(int argc, const char **argv, const char *prefix);
 extern int cmd_diff_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix);
 extern int cmd_for_each_ref(int argc, const char **argv, const char *prefix);
@@ -45,6 +44,7 @@ extern int cmd_ls_files(int argc, const char **argv, const char *prefix);
 extern int cmd_ls_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_mailinfo(int argc, const char **argv, const char *prefix);
 extern int cmd_mailsplit(int argc, const char **argv, const char *prefix);
+extern int cmd_merge_base(int argc, const char **argv, const char *prefix);
 extern int cmd_merge_file(int argc, const char **argv, const char *prefix);
 extern int cmd_mv(int argc, const char **argv, const char *prefix);
 extern int cmd_name_rev(int argc, const char **argv, const char *prefix);
diff --git a/cache.h b/cache.h
index 04f8e63..b84e3de 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -127,6 +127,19 @@ extern unsigned int active_nr, active_alloc, active_cache_changed;
 extern struct cache_tree *active_cache_tree;
 extern int cache_errno;
 
+enum object_type {
+       OBJ_BAD = -1,
+       OBJ_NONE = 0,
+       OBJ_COMMIT = 1,
+       OBJ_TREE = 2,
+       OBJ_BLOB = 3,
+       OBJ_TAG = 4,
+       /* 5 for future expansion */
+       OBJ_OFS_DELTA = 6,
+       OBJ_REF_DELTA = 7,
+       OBJ_MAX,
+};
+
 #define GIT_DIR_ENVIRONMENT "GIT_DIR"
 #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
 #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
@@ -177,7 +190,7 @@ extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
 extern int ce_match_stat(struct cache_entry *ce, struct stat *st, int);
 extern int ce_modified(struct cache_entry *ce, struct stat *st, int);
 extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
-extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, const char *type);
+extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
 extern int read_pipe(int fd, char** return_buf, unsigned long* return_size);
 extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object);
 extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
@@ -211,6 +224,7 @@ extern const char *apply_default_whitespace;
 extern int zlib_compression_level;
 extern size_t packed_git_window_size;
 extern size_t packed_git_limit;
+extern int auto_crlf;
 
 #define GIT_REPO_VERSION 0
 extern int repository_format_version;
@@ -262,12 +276,12 @@ int safe_create_leading_directories(char *path);
 char *enter_repo(char *path, int strict);
 
 /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
-extern int sha1_object_info(const unsigned char *, char *, unsigned long *);
-extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size);
-extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size);
+extern int sha1_object_info(const unsigned char *, unsigned long *);
+extern void * unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size);
+extern void * read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size);
 extern int hash_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *sha1);
 extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
-extern int pretend_sha1_file(void *, unsigned long, const char *, unsigned char *);
+extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
 
 extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
 
@@ -284,18 +298,6 @@ extern int legacy_loose_object(unsigned char *);
 extern int has_pack_file(const unsigned char *sha1);
 extern int has_pack_index(const unsigned char *sha1);
 
-enum object_type {
-       OBJ_NONE = 0,
-       OBJ_COMMIT = 1,
-       OBJ_TREE = 2,
-       OBJ_BLOB = 3,
-       OBJ_TAG = 4,
-       /* 5 for future expansion */
-       OBJ_OFS_DELTA = 6,
-       OBJ_REF_DELTA = 7,
-       OBJ_BAD,
-};
-
 extern signed char hexval_table[256];
 static inline unsigned int hexval(unsigned int c)
 {
@@ -421,9 +423,9 @@ extern struct packed_git *add_packed_git(char *, int, int);
 extern int num_packed_objects(const struct packed_git *p);
 extern int nth_packed_object_sha1(const struct packed_git *, int, unsigned char*);
 extern unsigned long find_pack_entry_one(const unsigned char *, struct packed_git *);
-extern void *unpack_entry(struct packed_git *, unsigned long, char *, unsigned long *);
+extern void *unpack_entry(struct packed_git *, unsigned long, enum object_type *, unsigned long *);
 extern unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
-extern void packed_object_info_detail(struct packed_git *, unsigned long, char *, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
+extern const char *packed_object_info_detail(struct packed_git *, unsigned long, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
 
 /* Dumb servers support */
 extern int update_server_info(int);
@@ -478,4 +480,8 @@ extern int nfvasprintf(char **str, const char *fmt, va_list va);
 extern void trace_printf(const char *format, ...);
 extern void trace_argv_printf(const char **argv, int count, const char *format, ...);
 
+/* convert.c */
+extern int convert_to_git(const char *path, char **bufp, unsigned long *sizep);
+extern int convert_to_working_tree(const char *path, char **bufp, unsigned long *sizep);
+
 #endif /* CACHE_H */
index 044633d..9daa0cb 100644 (file)
@@ -92,14 +92,14 @@ struct sline {
 static char *grab_blob(const unsigned char *sha1, unsigned long *size)
 {
        char *blob;
-       char type[20];
+       enum object_type type;
        if (is_null_sha1(sha1)) {
                /* deleted blob */
                *size = 0;
                return xcalloc(1, 1);
        }
-       blob = read_sha1_file(sha1, type, size);
-       if (strcmp(type, blob_type))
+       blob = read_sha1_file(sha1, &type, size);
+       if (type != OBJ_BLOB)
                die("object '%s' is not a blob!", sha1_to_hex(sha1));
        return blob;
 }
index 3e8c872..da515a4 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -342,18 +342,18 @@ int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
 
 int parse_commit(struct commit *item)
 {
-       char type[20];
+       enum object_type type;
        void *buffer;
        unsigned long size;
        int ret;
 
        if (item->object.parsed)
                return 0;
-       buffer = read_sha1_file(item->object.sha1, type, &size);
+       buffer = read_sha1_file(item->object.sha1, &type, &size);
        if (!buffer)
                return error("Could not read %s",
                             sha1_to_hex(item->object.sha1));
-       if (strcmp(type, commit_type)) {
+       if (type != OBJ_COMMIT) {
                free(buffer);
                return error("Object %s not a commit",
                             sha1_to_hex(item->object.sha1));
@@ -1187,14 +1187,17 @@ struct commit_list *get_merge_bases(struct commit *one,
        return result;
 }
 
-int in_merge_bases(struct commit *rev1, struct commit *rev2)
+int in_merge_bases(struct commit *commit, struct commit **reference, int num)
 {
        struct commit_list *bases, *b;
        int ret = 0;
 
-       bases = get_merge_bases(rev1, rev2, 1);
+       if (num == 1)
+               bases = get_merge_bases(commit, *reference, 1);
+       else
+               die("not yet");
        for (b = bases; b; b = b->next) {
-               if (!hashcmp(rev1->object.sha1, b->item->object.sha1)) {
+               if (!hashcmp(commit->object.sha1, b->item->object.sha1)) {
                        ret = 1;
                        break;
                }
index 491b0c4..c737444 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -114,5 +114,5 @@ extern int is_repository_shallow(void);
 extern struct commit_list *get_shallow_commits(struct object_array *heads,
                int depth, int shallow_flag, int not_shallow_flag);
 
-int in_merge_bases(struct commit *rev1, struct commit *rev2);
+int in_merge_bases(struct commit *, struct commit **, int);
 #endif /* COMMIT_H */
index c938aa0..0ff413b 100644 (file)
--- a/config.c
+++ b/config.c
@@ -326,6 +326,15 @@ int git_default_config(const char *var, const char *value)
                return 0;
        }
 
+       if (!strcmp(var, "core.autocrlf")) {
+               if (value && !strcasecmp(value, "input")) {
+                       auto_crlf = -1;
+                       return 0;
+               }
+               auto_crlf = git_config_bool(var, value);
+               return 0;
+       }
+
        if (!strcmp(var, "user.name")) {
                strlcpy(git_default_name, value, sizeof(git_default_name));
                return 0;
@@ -385,6 +394,8 @@ int git_config(config_fn_t fn)
         * config file otherwise. */
        filename = getenv(CONFIG_ENVIRONMENT);
        if (!filename) {
+               if (!access(ETC_GITCONFIG, R_OK))
+                       ret += git_config_from_file(fn, ETC_GITCONFIG);
                home = getenv("HOME");
                filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
                if (!filename)
index 7cfb3a0..3a8e778 100644 (file)
@@ -114,13 +114,32 @@ AC_CHECK_LIB([expat], [XML_ParserCreate],
 [NO_EXPAT=YesPlease])
 AC_SUBST(NO_EXPAT)
 #
-# Define NEEDS_LIBICONV if linking with libc is not enough (Darwin).
+# Define NEEDS_LIBICONV if linking with libc is not enough (Darwin and
+# some Solaris installations).
 # Define NO_ICONV if neither libc nor libiconv support iconv.
-AC_CHECK_LIB([c], [iconv],
-       [NEEDS_LIBICONV=],
-       AC_CHECK_LIB([iconv], [iconv],
-               [NEEDS_LIBICONV=YesPlease],
-               [NO_ICONV=YesPlease]))
+AC_DEFUN([ICONVTEST_SRC], [
+#include <iconv.h>
+
+int main(void)
+{
+       iconv_open("", "");
+       return 0;
+}
+])
+AC_MSG_CHECKING([for iconv in -lc])
+AC_LINK_IFELSE(ICONVTEST_SRC,
+       [AC_MSG_RESULT([yes])
+       NEEDS_LIBICONV=],
+       [AC_MSG_RESULT([no])
+       old_LIBS="$LIBS"
+       LIBS="$LIBS -liconv"
+       AC_MSG_CHECKING([for iconv in -liconv])
+       AC_LINK_IFELSE(ICONVTEST_SRC,
+               [AC_MSG_RESULT([yes])
+               NEEDS_LIBICONV=YesPlease],
+               [AC_MSG_RESULT([no])
+               NO_ICONV=YesPlease])
+       LIBS="$old_LIBS"])
 AC_SUBST(NEEDS_LIBICONV)
 AC_SUBST(NO_ICONV)
 test -n "$NEEDS_LIBICONV" && LIBS="$LIBS -liconv"
index 7844888..8a8a13b 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -96,7 +96,7 @@ int get_ack(int fd, unsigned char *result_sha1)
                line[--len] = 0;
        if (!strcmp(line, "NAK"))
                return 0;
-       if (!strncmp(line, "ACK ", 4)) {
+       if (!prefixcmp(line, "ACK ")) {
                if (!get_sha1_hex(line+4, result_sha1)) {
                        if (strstr(line+45, "continue"))
                                return 2;
@@ -196,8 +196,8 @@ static int count_refspec_match(const char *pattern,
                 */
                if (namelen != patlen &&
                    patlen != namelen - 5 &&
-                   strncmp(name, "refs/heads/", 11) &&
-                   strncmp(name, "refs/tags/", 10)) {
+                   prefixcmp(name, "refs/heads/") &&
+                   prefixcmp(name, "refs/tags/")) {
                        /* We want to catch the case where only weak
                         * matches are found and there are multiple
                         * matches, and where more than one strong
index 5d3d402..7c03403 100755 (executable)
@@ -269,7 +269,6 @@ __git_commands ()
                cvsimport)        : import;;
                cvsserver)        : daemon;;
                daemon)           : daemon;;
-               diff-stages)      : nobody uses it;;
                fast-import)      : import;;
                fsck-objects)     : plumbing;;
                fetch-pack)       : plumbing;;
@@ -298,7 +297,6 @@ __git_commands ()
                reflog)           : plumbing;;
                repo-config)      : plumbing;;
                rerere)           : plumbing;;
-               resolve)          : dead dont use;;
                rev-list)         : plumbing;;
                rev-parse)        : plumbing;;
                runstatus)        : plumbing;;
index a630132..b5f41ae 100644 (file)
@@ -284,27 +284,27 @@ static void convert_commit(void *buffer, unsigned long size, unsigned char *resu
 static struct entry * convert_entry(unsigned char *sha1)
 {
        struct entry *entry = lookup_entry(sha1);
-       char type[20];
+       enum object_type type;
        void *buffer, *data;
        unsigned long size;
 
        if (entry->converted)
                return entry;
-       data = read_sha1_file(sha1, type, &size);
+       data = read_sha1_file(sha1, &type, &size);
        if (!data)
                die("unable to read object %s", sha1_to_hex(sha1));
 
        buffer = xmalloc(size);
        memcpy(buffer, data, size);
 
-       if (!strcmp(type, blob_type)) {
+       if (type == OBJ_BLOB) {
                write_sha1_file(buffer, size, blob_type, entry->new_sha1);
-       } else if (!strcmp(type, tree_type))
+       } else if (type == OBJ_TREE)
                convert_tree(buffer, size, entry->new_sha1);
-       else if (!strcmp(type, commit_type))
+       else if (type == OBJ_COMMIT)
                convert_commit(buffer, size, entry->new_sha1);
        else
-               die("unknown object type '%s' in %s", type, sha1_to_hex(sha1));
+               die("unknown object type %d in %s", type, sha1_to_hex(sha1));
        entry->converted = 1;
        free(buffer);
        free(data);
diff --git a/convert.c b/convert.c
new file mode 100644 (file)
index 0000000..898bfe3
--- /dev/null
+++ b/convert.c
@@ -0,0 +1,186 @@
+#include "cache.h"
+/*
+ * convert.c - convert a file when checking it out and checking it in.
+ *
+ * This should use the pathname to decide on whether it wants to do some
+ * more interesting conversions (automatic gzip/unzip, general format
+ * conversions etc etc), but by default it just does automatic CRLF<->LF
+ * translation when the "auto_crlf" option is set.
+ */
+
+struct text_stat {
+       /* CR, LF and CRLF counts */
+       unsigned cr, lf, crlf;
+
+       /* These are just approximations! */
+       unsigned printable, nonprintable;
+};
+
+static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats)
+{
+       unsigned long i;
+
+       memset(stats, 0, sizeof(*stats));
+
+       for (i = 0; i < size; i++) {
+               unsigned char c = buf[i];
+               if (c == '\r') {
+                       stats->cr++;
+                       if (i+1 < size && buf[i+1] == '\n')
+                               stats->crlf++;
+                       continue;
+               }
+               if (c == '\n') {
+                       stats->lf++;
+                       continue;
+               }
+               if (c == 127)
+                       /* DEL */
+                       stats->nonprintable++;
+               else if (c < 32) {
+                       switch (c) {
+                               /* BS, HT, ESC and FF */
+                       case '\b': case '\t': case '\033': case '\014':
+                               stats->printable++;
+                               break;
+                       default:
+                               stats->nonprintable++;
+                       }
+               }
+               else
+                       stats->printable++;
+       }
+}
+
+/*
+ * The same heuristics as diff.c::mmfile_is_binary()
+ */
+static int is_binary(unsigned long size, struct text_stat *stats)
+{
+
+       if ((stats->printable >> 7) < stats->nonprintable)
+               return 1;
+       /*
+        * Other heuristics? Average line length might be relevant,
+        * as might LF vs CR vs CRLF counts..
+        *
+        * NOTE! It might be normal to have a low ratio of CRLF to LF
+        * (somebody starts with a LF-only file and edits it with an editor
+        * that adds CRLF only to lines that are added..). But do  we
+        * want to support CR-only? Probably not.
+        */
+       return 0;
+}
+
+int convert_to_git(const char *path, char **bufp, unsigned long *sizep)
+{
+       char *buffer, *nbuf;
+       unsigned long size, nsize;
+       struct text_stat stats;
+
+       /*
+        * FIXME! Other pluggable conversions should go here,
+        * based on filename patterns. Right now we just do the
+        * stupid auto-CRLF one.
+        */
+       if (!auto_crlf)
+               return 0;
+
+       size = *sizep;
+       if (!size)
+               return 0;
+       buffer = *bufp;
+
+       gather_stats(buffer, size, &stats);
+
+       /* No CR? Nothing to convert, regardless. */
+       if (!stats.cr)
+               return 0;
+
+       /*
+        * We're currently not going to even try to convert stuff
+        * that has bare CR characters. Does anybody do that crazy
+        * stuff?
+        */
+       if (stats.cr != stats.crlf)
+               return 0;
+
+       /*
+        * And add some heuristics for binary vs text, of course...
+        */
+       if (is_binary(size, &stats))
+               return 0;
+
+       /*
+        * Ok, allocate a new buffer, fill it in, and return true
+        * to let the caller know that we switched buffers on it.
+        */
+       nsize = size - stats.crlf;
+       nbuf = xmalloc(nsize);
+       *bufp = nbuf;
+       *sizep = nsize;
+       do {
+               unsigned char c = *buffer++;
+               if (c != '\r')
+                       *nbuf++ = c;
+       } while (--size);
+
+       return 1;
+}
+
+int convert_to_working_tree(const char *path, char **bufp, unsigned long *sizep)
+{
+       char *buffer, *nbuf;
+       unsigned long size, nsize;
+       struct text_stat stats;
+       unsigned char last;
+
+       /*
+        * FIXME! Other pluggable conversions should go here,
+        * based on filename patterns. Right now we just do the
+        * stupid auto-CRLF one.
+        */
+       if (auto_crlf <= 0)
+               return 0;
+
+       size = *sizep;
+       if (!size)
+               return 0;
+       buffer = *bufp;
+
+       gather_stats(buffer, size, &stats);
+
+       /* No LF? Nothing to convert, regardless. */
+       if (!stats.lf)
+               return 0;
+
+       /* Was it already in CRLF format? */
+       if (stats.lf == stats.crlf)
+               return 0;
+
+       /* If we have any bare CR characters, we're not going to touch it */
+       if (stats.cr != stats.crlf)
+               return 0;
+
+       if (is_binary(size, &stats))
+               return 0;
+
+       /*
+        * Ok, allocate a new buffer, fill it in, and return true
+        * to let the caller know that we switched buffers on it.
+        */
+       nsize = size + stats.lf - stats.crlf;
+       nbuf = xmalloc(nsize);
+       *bufp = nbuf;
+       *sizep = nsize;
+       last = 0;
+       do {
+               unsigned char c = *buffer++;
+               if (c == '\n' && last != '\r')
+                       *nbuf++ = '\r';
+               *nbuf++ = c;
+               last = c;
+       } while (--size);
+
+       return 1;
+}
index 66f8d6f..e74ecac 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -286,7 +286,7 @@ static int service_enabled;
 
 static int git_daemon_config(const char *var, const char *value)
 {
-       if (!strncmp(var, "daemon.", 7) &&
+       if (!prefixcmp(var, "daemon.") &&
            !strcmp(var + 7, service_looking_at->config_name)) {
                service_enabled = git_config_bool(var, value);
                return 0;
@@ -562,7 +562,7 @@ static int execute(struct sockaddr *addr)
        for (i = 0; i < ARRAY_SIZE(daemon_service); i++) {
                struct daemon_service *s = &(daemon_service[i]);
                int namelen = strlen(s->name);
-               if (!strncmp("git-", line, 4) &&
+               if (!prefixcmp(line, "git-") &&
                    !strncmp(s->name, line + 4, namelen) &&
                    line[namelen + 4] == ' ') {
                        /*
@@ -1011,7 +1011,7 @@ int main(int argc, char **argv)
        for (i = 1; i < argc; i++) {
                char *arg = argv[i];
 
-               if (!strncmp(arg, "--listen=", 9)) {
+               if (!prefixcmp(arg, "--listen=")) {
                    char *p = arg + 9;
                    char *ph = listen_addr = xmalloc(strlen(arg + 9) + 1);
                    while (*p)
@@ -1019,7 +1019,7 @@ int main(int argc, char **argv)
                    *ph = 0;
                    continue;
                }
-               if (!strncmp(arg, "--port=", 7)) {
+               if (!prefixcmp(arg, "--port=")) {
                        char *end;
                        unsigned long n;
                        n = strtoul(arg+7, &end, 0);
@@ -1045,11 +1045,11 @@ int main(int argc, char **argv)
                        export_all_trees = 1;
                        continue;
                }
-               if (!strncmp(arg, "--timeout=", 10)) {
+               if (!prefixcmp(arg, "--timeout=")) {
                        timeout = atoi(arg+10);
                        continue;
                }
-               if (!strncmp(arg, "--init-timeout=", 15)) {
+               if (!prefixcmp(arg, "--init-timeout=")) {
                        init_timeout = atoi(arg+15);
                        continue;
                }
@@ -1057,11 +1057,11 @@ int main(int argc, char **argv)
                        strict_paths = 1;
                        continue;
                }
-               if (!strncmp(arg, "--base-path=", 12)) {
+               if (!prefixcmp(arg, "--base-path=")) {
                        base_path = arg+12;
                        continue;
                }
-               if (!strncmp(arg, "--interpolated-path=", 20)) {
+               if (!prefixcmp(arg, "--interpolated-path=")) {
                        interpolated_path = arg+20;
                        continue;
                }
@@ -1073,11 +1073,11 @@ int main(int argc, char **argv)
                        user_path = "";
                        continue;
                }
-               if (!strncmp(arg, "--user-path=", 12)) {
+               if (!prefixcmp(arg, "--user-path=")) {
                        user_path = arg + 12;
                        continue;
                }
-               if (!strncmp(arg, "--pid-file=", 11)) {
+               if (!prefixcmp(arg, "--pid-file=")) {
                        pid_file = arg + 11;
                        continue;
                }
@@ -1086,27 +1086,27 @@ int main(int argc, char **argv)
                        log_syslog = 1;
                        continue;
                }
-               if (!strncmp(arg, "--user=", 7)) {
+               if (!prefixcmp(arg, "--user=")) {
                        user_name = arg + 7;
                        continue;
                }
-               if (!strncmp(arg, "--group=", 8)) {
+               if (!prefixcmp(arg, "--group=")) {
                        group_name = arg + 8;
                        continue;
                }
-               if (!strncmp(arg, "--enable=", 9)) {
+               if (!prefixcmp(arg, "--enable=")) {
                        enable_service(arg + 9, 1);
                        continue;
                }
-               if (!strncmp(arg, "--disable=", 10)) {
+               if (!prefixcmp(arg, "--disable=")) {
                        enable_service(arg + 10, 0);
                        continue;
                }
-               if (!strncmp(arg, "--allow-override=", 17)) {
+               if (!prefixcmp(arg, "--allow-override=")) {
                        make_service_overridable(arg + 17, 1);
                        continue;
                }
-               if (!strncmp(arg, "--forbid-override=", 18)) {
+               if (!prefixcmp(arg, "--forbid-override=")) {
                        make_service_overridable(arg + 18, 0);
                        continue;
                }
index 60c0fa6..2e91619 100644 (file)
 #include "diffcore.h"
 #include "revision.h"
 #include "cache-tree.h"
+#include "path-list.h"
 
 /*
  * diff-files
  */
 
+static int read_directory(const char *path, struct path_list *list)
+{
+       DIR *dir;
+       struct dirent *e;
+
+       if (!(dir = opendir(path)))
+               return error("Could not open directory %s", path);
+
+       while ((e = readdir(dir)))
+               if (strcmp(".", e->d_name) && strcmp("..", e->d_name))
+                       path_list_insert(xstrdup(e->d_name), list);
+
+       closedir(dir);
+       return 0;
+}
+
+static int queue_diff(struct diff_options *o,
+               const char *name1, const char *name2)
+{
+       struct stat st;
+       int mode1 = 0, mode2 = 0;
+
+       if (name1) {
+               if (stat(name1, &st))
+                       return error("Could not access '%s'", name1);
+               mode1 = st.st_mode;
+       }
+       if (name2) {
+               if (stat(name2, &st))
+                       return error("Could not access '%s'", name2);
+               mode2 = st.st_mode;
+       }
+
+       if (mode1 && mode2 && S_ISDIR(mode1) != S_ISDIR(mode2))
+               return error("file/directory conflict: %s, %s", name1, name2);
+
+       if (S_ISDIR(mode1) || S_ISDIR(mode2)) {
+               char buffer1[PATH_MAX], buffer2[PATH_MAX];
+               struct path_list p1 = {NULL, 0, 0, 1}, p2 = {NULL, 0, 0, 1};
+               int len1 = 0, len2 = 0, i1, i2, ret = 0;
+
+               if (name1 && read_directory(name1, &p1))
+                       return -1;
+               if (name2 && read_directory(name2, &p2)) {
+                       path_list_clear(&p1, 0);
+                       return -1;
+               }
+
+               if (name1) {
+                       len1 = strlen(name1);
+                       if (len1 > 0 && name1[len1 - 1] == '/')
+                               len1--;
+                       memcpy(buffer1, name1, len1);
+                       buffer1[len1++] = '/';
+               }
+
+               if (name2) {
+                       len2 = strlen(name2);
+                       if (len2 > 0 && name2[len2 - 1] == '/')
+                               len2--;
+                       memcpy(buffer2, name2, len2);
+                       buffer2[len2++] = '/';
+               }
+
+               for (i1 = i2 = 0; !ret && (i1 < p1.nr || i2 < p2.nr); ) {
+                       const char *n1, *n2;
+                       int comp;
+
+                       if (i1 == p1.nr)
+                               comp = 1;
+                       else if (i2 == p2.nr)
+                               comp = -1;
+                       else
+                               comp = strcmp(p1.items[i1].path,
+                                       p2.items[i2].path);
+
+                       if (comp > 0)
+                               n1 = NULL;
+                       else {
+                               n1 = buffer1;
+                               strncpy(buffer1 + len1, p1.items[i1++].path,
+                                               PATH_MAX - len1);
+                       }
+
+                       if (comp < 0)
+                               n2 = NULL;
+                       else {
+                               n2 = buffer2;
+                               strncpy(buffer2 + len2, p2.items[i2++].path,
+                                               PATH_MAX - len2);
+                       }
+
+                       ret = queue_diff(o, n1, n2);
+               }
+               path_list_clear(&p1, 0);
+               path_list_clear(&p2, 0);
+
+               return ret;
+       } else {
+               struct diff_filespec *d1, *d2;
+
+               if (o->reverse_diff) {
+                       unsigned tmp;
+                       const char *tmp_c;
+                       tmp = mode1; mode1 = mode2; mode2 = tmp;
+                       tmp_c = name1; name1 = name2; name2 = tmp_c;
+               }
+
+               if (!name1)
+                       name1 = "/dev/null";
+               if (!name2)
+                       name2 = "/dev/null";
+               d1 = alloc_filespec(name1);
+               d2 = alloc_filespec(name2);
+               fill_filespec(d1, null_sha1, mode1);
+               fill_filespec(d2, null_sha1, mode2);
+
+               diff_queue(&diff_queued_diff, d1, d2);
+               return 0;
+       }
+}
+
+static int is_in_index(const char *path)
+{
+       int len = strlen(path);
+       int pos = cache_name_pos(path, len);
+       char c;
+
+       if (pos < 0)
+               return 0;
+       if (strncmp(active_cache[pos]->name, path, len))
+               return 0;
+       c = active_cache[pos]->name[len];
+       return c == '\0' || c == '/';
+}
+
+static int handle_diff_files_args(struct rev_info *revs,
+               int argc, const char **argv, int *silent)
+{
+       *silent = 0;
+
+       /* revs->max_count == -2 means --no-index */
+       while (1 < argc && argv[1][0] == '-') {
+               if (!strcmp(argv[1], "--base"))
+                       revs->max_count = 1;
+               else if (!strcmp(argv[1], "--ours"))
+                       revs->max_count = 2;
+               else if (!strcmp(argv[1], "--theirs"))
+                       revs->max_count = 3;
+               else if (!strcmp(argv[1], "-n") ||
+                               !strcmp(argv[1], "--no-index"))
+                       revs->max_count = -2;
+               else if (!strcmp(argv[1], "-q"))
+                       *silent = 1;
+               else
+                       return error("invalid option: %s", argv[1]);
+               argv++; argc--;
+       }
+
+       if (revs->max_count == -1 && revs->diffopt.nr_paths == 2) {
+               /*
+                * If two files are specified, and at least one is untracked,
+                * default to no-index.
+                */
+               read_cache();
+               if (!is_in_index(revs->diffopt.paths[0]) ||
+                                       !is_in_index(revs->diffopt.paths[1]))
+                       revs->max_count = -2;
+       }
+
+       /*
+        * Make sure there are NO revision (i.e. pending object) parameter,
+        * rev.max_count is reasonable (0 <= n <= 3),
+        * there is no other revision filtering parameters.
+        */
+       if (revs->pending.nr || revs->max_count > 3 ||
+           revs->min_age != -1 || revs->max_age != -1)
+               return error("no revision allowed with diff-files");
+
+       if (revs->max_count == -1 &&
+           (revs->diffopt.output_format & DIFF_FORMAT_PATCH))
+               revs->combine_merges = revs->dense_combined_merges = 1;
+
+       return 0;
+}
+
+int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv)
+{
+       int silent_on_removed;
+
+       if (handle_diff_files_args(revs, argc, argv, &silent_on_removed))
+               return -1;
+
+       if (revs->max_count == -2) {
+               if (revs->diffopt.nr_paths != 2)
+                       return error("need two files/directories with --no-index");
+               if (queue_diff(&revs->diffopt, revs->diffopt.paths[0],
+                               revs->diffopt.paths[1]))
+                       return -1;
+               diffcore_std(&revs->diffopt);
+               diff_flush(&revs->diffopt);
+               /*
+                * The return code for --no-index imitates diff(1):
+                * 0 = no changes, 1 = changes, else error
+                */
+               return revs->diffopt.found_changes;
+       }
+
+       if (read_cache() < 0) {
+               perror("read_cache");
+               return -1;
+       }
+       return run_diff_files(revs, silent_on_removed);
+}
+
 int run_diff_files(struct rev_info *revs, int silent_on_removed)
 {
        int entries, i;
@@ -20,11 +236,7 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
 
        if (diff_unmerged_stage < 0)
                diff_unmerged_stage = 2;
-       entries = read_cache();
-       if (entries < 0) {
-               perror("read_cache");
-               return -1;
-       }
+       entries = active_nr;
        for (i = 0; i < entries; i++) {
                struct stat st;
                unsigned int oldmode, newmode;
@@ -362,10 +574,6 @@ int run_diff_index(struct rev_info *revs, int cached)
        if (!revs->ignore_merges)
                match_missing = 1;
 
-       if (read_cache() < 0) {
-               perror("read_cache");
-               return -1;
-       }
        mark_merge_entries();
 
        ent = revs->pending.objects[0].item;
diff --git a/diff.c b/diff.c
index b8a90e9..e225de2 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -77,7 +77,7 @@ int git_diff_ui_config(const char *var, const char *value)
                        diff_detect_rename_default = DIFF_DETECT_RENAME;
                return 0;
        }
-       if (!strncmp(var, "diff.color.", 11) || !strncmp(var, "color.diff.", 11)) {
+       if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) {
                int slot = parse_diff_color_slot(var, 11);
                color_parse(value, var, diff_colors[slot]);
                return 0;
@@ -184,44 +184,61 @@ static void print_line_count(int count)
        }
 }
 
-static void copy_file(int prefix, const char *data, int size)
+static void copy_file(int prefix, const char *data, int size,
+               const char *set, const char *reset)
 {
        int ch, nl_just_seen = 1;
        while (0 < size--) {
                ch = *data++;
-               if (nl_just_seen)
+               if (nl_just_seen) {
+                       fputs(set, stdout);
                        putchar(prefix);
-               putchar(ch);
-               if (ch == '\n')
+               }
+               if (ch == '\n') {
                        nl_just_seen = 1;
-               else
+                       fputs(reset, stdout);
+               } else
                        nl_just_seen = 0;
+               putchar(ch);
        }
        if (!nl_just_seen)
-               printf("\n\\ No newline at end of file\n");
+               printf("%s\n\\ No newline at end of file\n", reset);
 }
 
 static void emit_rewrite_diff(const char *name_a,
                              const char *name_b,
                              struct diff_filespec *one,
-                             struct diff_filespec *two)
+                             struct diff_filespec *two,
+                             int color_diff)
 {
        int lc_a, lc_b;
+       const char *name_a_tab, *name_b_tab;
+       const char *metainfo = diff_get_color(color_diff, DIFF_METAINFO);
+       const char *fraginfo = diff_get_color(color_diff, DIFF_FRAGINFO);
+       const char *old = diff_get_color(color_diff, DIFF_FILE_OLD);
+       const char *new = diff_get_color(color_diff, DIFF_FILE_NEW);
+       const char *reset = diff_get_color(color_diff, DIFF_RESET);
+
+       name_a += (*name_a == '/');
+       name_b += (*name_b == '/');
+       name_a_tab = strchr(name_a, ' ') ? "\t" : "";
+       name_b_tab = strchr(name_b, ' ') ? "\t" : "";
+
        diff_populate_filespec(one, 0);
        diff_populate_filespec(two, 0);
        lc_a = count_lines(one->data, one->size);
        lc_b = count_lines(two->data, two->size);
-       name_a += (*name_a == '/');
-       name_b += (*name_b == '/');
-       printf("--- a/%s\n+++ b/%s\n@@ -", name_a, name_b);
+       printf("%s--- a/%s%s%s\n%s+++ b/%s%s%s\n%s@@ -",
+              metainfo, name_a, name_a_tab, reset,
+              metainfo, name_b, name_b_tab, reset, fraginfo);
        print_line_count(lc_a);
        printf(" +");
        print_line_count(lc_b);
-       printf(" @@\n");
+       printf(" @@%s\n", reset);
        if (lc_a)
-               copy_file('-', one->data, one->size);
+               copy_file('-', one->data, one->size, old, reset);
        if (lc_b)
-               copy_file('+', two->data, two->size);
+               copy_file('+', two->data, two->size, new, reset);
 }
 
 static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
@@ -365,6 +382,7 @@ struct emit_callback {
        int nparents, color_diff;
        const char **label_path;
        struct diff_words_data *diff_words;
+       int *found_changesp;
 };
 
 static void free_diff_words_data(struct emit_callback *ecbdata)
@@ -400,22 +418,16 @@ static void emit_line(const char *set, const char *reset, const char *line, int
        puts(reset);
 }
 
-static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len)
+static void emit_line_with_ws(int nparents,
+               const char *set, const char *reset, const char *ws,
+               const char *line, int len)
 {
-       int col0 = ecbdata->nparents;
+       int col0 = nparents;
        int last_tab_in_indent = -1;
        int last_space_in_indent = -1;
        int i;
        int tail = len;
        int need_highlight_leading_space = 0;
-       const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE);
-       const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW);
-
-       if (!*ws) {
-               emit_line(set, reset, line, len);
-               return;
-       }
-
        /* The line is a newly added line.  Does it have funny leading
         * whitespaces?  In indent, SP should never precede a TAB.
         */
@@ -470,6 +482,18 @@ static void emit_add_line(const char *reset, struct emit_callback *ecbdata, cons
                emit_line(set, reset, line + i, len - i);
 }
 
+static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len)
+{
+       const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE);
+       const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW);
+
+       if (!*ws)
+               emit_line(set, reset, line, len);
+       else
+               emit_line_with_ws(ecbdata->nparents, set, reset, ws,
+                               line, len);
+}
+
 static void fn_out_consume(void *priv, char *line, unsigned long len)
 {
        int i;
@@ -478,9 +502,18 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
        const char *set = diff_get_color(ecbdata->color_diff, DIFF_METAINFO);
        const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);
 
+       *(ecbdata->found_changesp) = 1;
+
        if (ecbdata->label_path[0]) {
-               printf("%s--- %s%s\n", set, ecbdata->label_path[0], reset);
-               printf("%s+++ %s%s\n", set, ecbdata->label_path[1], reset);
+               const char *name_a_tab, *name_b_tab;
+
+               name_a_tab = strchr(ecbdata->label_path[0], ' ') ? "\t" : "";
+               name_b_tab = strchr(ecbdata->label_path[1], ' ') ? "\t" : "";
+
+               printf("%s--- %s%s%s\n",
+                      set, ecbdata->label_path[0], reset, name_a_tab);
+               printf("%s+++ %s%s%s\n",
+                      set, ecbdata->label_path[1], reset, name_b_tab);
                ecbdata->label_path[0] = ecbdata->label_path[1] = NULL;
        }
 
@@ -872,30 +905,44 @@ static void show_numstat(struct diffstat_t* data, struct diff_options *options)
 struct checkdiff_t {
        struct xdiff_emit_state xm;
        const char *filename;
-       int lineno;
+       int lineno, color_diff;
 };
 
 static void checkdiff_consume(void *priv, char *line, unsigned long len)
 {
        struct checkdiff_t *data = priv;
+       const char *ws = diff_get_color(data->color_diff, DIFF_WHITESPACE);
+       const char *reset = diff_get_color(data->color_diff, DIFF_RESET);
+       const char *set = diff_get_color(data->color_diff, DIFF_FILE_NEW);
 
        if (line[0] == '+') {
-               int i, spaces = 0;
+               int i, spaces = 0, space_before_tab = 0, white_space_at_end = 0;
 
                /* check space before tab */
                for (i = 1; i < len && (line[i] == ' ' || line[i] == '\t'); i++)
                        if (line[i] == ' ')
                                spaces++;
                if (line[i - 1] == '\t' && spaces)
-                       printf("%s:%d: space before tab:%.*s\n",
-                               data->filename, data->lineno, (int)len, line);
+                       space_before_tab = 1;
 
                /* check white space at line end */
                if (line[len - 1] == '\n')
                        len--;
                if (isspace(line[len - 1]))
-                       printf("%s:%d: white space at end: %.*s\n",
-                               data->filename, data->lineno, (int)len, line);
+                       white_space_at_end = 1;
+
+               if (space_before_tab || white_space_at_end) {
+                       printf("%s:%d: %s", data->filename, data->lineno, ws);
+                       if (space_before_tab) {
+                               printf("space before tab");
+                               if (white_space_at_end)
+                                       putchar(',');
+                       }
+                       if (white_space_at_end)
+                               printf("white space at end");
+                       printf(":%s ", reset);
+                       emit_line_with_ws(1, set, reset, ws, line, len);
+               }
 
                data->lineno++;
        } else if (line[0] == ' ')
@@ -1052,7 +1099,9 @@ static void builtin_diff(const char *name_a,
                if ((one->mode ^ two->mode) & S_IFMT)
                        goto free_ab_and_return;
                if (complete_rewrite) {
-                       emit_rewrite_diff(name_a, name_b, one, two);
+                       emit_rewrite_diff(name_a, name_b, one, two,
+                                       o->color_diff);
+                       o->found_changes = 1;
                        goto free_ab_and_return;
                }
        }
@@ -1070,6 +1119,7 @@ static void builtin_diff(const char *name_a,
                else
                        printf("Binary files %s and %s differ\n",
                               lbl[0], lbl[1]);
+               o->found_changes = 1;
        }
        else {
                /* Crazy xdl interfaces.. */
@@ -1082,14 +1132,15 @@ static void builtin_diff(const char *name_a,
                memset(&ecbdata, 0, sizeof(ecbdata));
                ecbdata.label_path = lbl;
                ecbdata.color_diff = o->color_diff;
+               ecbdata.found_changesp = &o->found_changes;
                xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
                xecfg.ctxlen = o->context;
                xecfg.flags = XDL_EMIT_FUNCNAMES;
                if (!diffopts)
                        ;
-               else if (!strncmp(diffopts, "--unified=", 10))
+               else if (!prefixcmp(diffopts, "--unified="))
                        xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10);
-               else if (!strncmp(diffopts, "-u", 2))
+               else if (!prefixcmp(diffopts, "-u"))
                        xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10);
                ecb.outf = xdiff_outf;
                ecb.priv = &ecbdata;
@@ -1153,7 +1204,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
 
 static void builtin_checkdiff(const char *name_a, const char *name_b,
                             struct diff_filespec *one,
-                            struct diff_filespec *two)
+                            struct diff_filespec *two, struct diff_options *o)
 {
        mmfile_t mf1, mf2;
        struct checkdiff_t data;
@@ -1165,6 +1216,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
        data.xm.consume = checkdiff_consume;
        data.filename = name_b ? name_b : name_a;
        data.lineno = 0;
+       data.color_diff = o->color_diff;
 
        if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
                die("unable to read files to diff");
@@ -1334,6 +1386,9 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
            reuse_worktree_file(s->path, s->sha1, 0)) {
                struct stat st;
                int fd;
+               char *buf;
+               unsigned long size;
+
                if (lstat(s->path, &st) < 0) {
                        if (errno == ENOENT) {
                        err_empty:
@@ -1366,10 +1421,22 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
                s->data = xmmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0);
                close(fd);
                s->should_munmap = 1;
-               /* FIXME! CRLF -> LF conversion goes here, based on "s->path" */
+
+               /*
+                * Convert from working tree format to canonical git format
+                */
+               buf = s->data;
+               size = s->size;
+               if (convert_to_git(s->path, &buf, &size)) {
+                       munmap(s->data, s->size);
+                       s->should_munmap = 0;
+                       s->data = buf;
+                       s->size = size;
+                       s->should_free = 1;
+               }
        }
        else {
-               char type[20];
+               enum object_type type;
                struct sha1_size_cache *e;
 
                if (size_only) {
@@ -1378,11 +1445,12 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
                                s->size = e->size;
                                return 0;
                        }
-                       if (!sha1_object_info(s->sha1, type, &s->size))
+                       type = sha1_object_info(s->sha1, &s->size);
+                       if (type < 0)
                                locate_size_cache(s->sha1, 0, s->size);
                }
                else {
-                       s->data = read_sha1_file(s->sha1, type, &s->size);
+                       s->data = read_sha1_file(s->sha1, &type, &s->size);
                        s->should_free = 1;
                }
        }
@@ -1775,7 +1843,7 @@ static void run_checkdiff(struct diff_filepair *p, struct diff_options *o)
        diff_fill_sha1_info(p->one);
        diff_fill_sha1_info(p->two);
 
-       builtin_checkdiff(name, other, p->one, p->two);
+       builtin_checkdiff(name, other, p->one, p->two, o);
 }
 
 void diff_setup(struct diff_options *options)
@@ -1924,7 +1992,7 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
        else if (!strcmp(arg, "--shortstat")) {
                options->output_format |= DIFF_FORMAT_SHORTSTAT;
        }
-       else if (!strncmp(arg, "--stat", 6)) {
+       else if (!prefixcmp(arg, "--stat")) {
                char *end;
                int width = options->stat_width;
                int name_width = options->stat_name_width;
@@ -1933,9 +2001,9 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
 
                switch (*arg) {
                case '-':
-                       if (!strncmp(arg, "-width=", 7))
+                       if (!prefixcmp(arg, "-width="))
                                width = strtoul(arg + 7, &end, 10);
-                       else if (!strncmp(arg, "-name-width=", 12))
+                       else if (!prefixcmp(arg, "-name-width="))
                                name_width = strtoul(arg + 12, &end, 10);
                        break;
                case '=':
@@ -1960,7 +2028,7 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
        }
        else if (!strcmp(arg, "-z"))
                options->line_termination = 0;
-       else if (!strncmp(arg, "-l", 2))
+       else if (!prefixcmp(arg, "-l"))
                options->rename_limit = strtoul(arg+2, NULL, 10);
        else if (!strcmp(arg, "--full-index"))
                options->full_index = 1;
@@ -1977,31 +2045,31 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                options->output_format |= DIFF_FORMAT_NAME_STATUS;
        else if (!strcmp(arg, "-R"))
                options->reverse_diff = 1;
-       else if (!strncmp(arg, "-S", 2))
+       else if (!prefixcmp(arg, "-S"))
                options->pickaxe = arg + 2;
        else if (!strcmp(arg, "-s")) {
                options->output_format |= DIFF_FORMAT_NO_OUTPUT;
        }
-       else if (!strncmp(arg, "-O", 2))
+       else if (!prefixcmp(arg, "-O"))
                options->orderfile = arg + 2;
-       else if (!strncmp(arg, "--diff-filter=", 14))
+       else if (!prefixcmp(arg, "--diff-filter="))
                options->filter = arg + 14;
        else if (!strcmp(arg, "--pickaxe-all"))
                options->pickaxe_opts = DIFF_PICKAXE_ALL;
        else if (!strcmp(arg, "--pickaxe-regex"))
                options->pickaxe_opts = DIFF_PICKAXE_REGEX;
-       else if (!strncmp(arg, "-B", 2)) {
+       else if (!prefixcmp(arg, "-B")) {
                if ((options->break_opt =
                     diff_scoreopt_parse(arg)) == -1)
                        return -1;
        }
-       else if (!strncmp(arg, "-M", 2)) {
+       else if (!prefixcmp(arg, "-M")) {
                if ((options->rename_score =
                     diff_scoreopt_parse(arg)) == -1)
                        return -1;
                options->detect_rename = DIFF_DETECT_RENAME;
        }
-       else if (!strncmp(arg, "-C", 2)) {
+       else if (!prefixcmp(arg, "-C")) {
                if ((options->rename_score =
                     diff_scoreopt_parse(arg)) == -1)
                        return -1;
@@ -2011,7 +2079,7 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                options->find_copies_harder = 1;
        else if (!strcmp(arg, "--abbrev"))
                options->abbrev = DEFAULT_ABBREV;
-       else if (!strncmp(arg, "--abbrev=", 9)) {
+       else if (!prefixcmp(arg, "--abbrev=")) {
                options->abbrev = strtoul(arg + 9, NULL, 10);
                if (options->abbrev < MINIMUM_ABBREV)
                        options->abbrev = MINIMUM_ABBREV;
@@ -2026,6 +2094,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                options->xdl_opts |= XDF_IGNORE_WHITESPACE;
        else if (!strcmp(arg, "-b") || !strcmp(arg, "--ignore-space-change"))
                options->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE;
+       else if (!strcmp(arg, "--ignore-space-at-eol"))
+               options->xdl_opts |= XDF_IGNORE_WHITESPACE_AT_EOL;
        else if (!strcmp(arg, "--color-words"))
                options->color_diff = options->color_diff_words = 1;
        else if (!strcmp(arg, "--no-renames"))
@@ -2392,7 +2462,8 @@ static void diff_resolve_rename_copy(void)
                                p->status = DIFF_STATUS_RENAMED;
                }
                else if (hashcmp(p->one->sha1, p->two->sha1) ||
-                        p->one->mode != p->two->mode)
+                        p->one->mode != p->two->mode ||
+                        is_null_sha1(p->one->sha1))
                        p->status = DIFF_STATUS_MODIFIED;
                else {
                        /* This is a "no-change" entry and should not
@@ -2518,7 +2589,7 @@ static void patch_id_consume(void *priv, char *line, unsigned long len)
        int new_len;
 
        /* Ignore line numbers when computing the SHA1 of the patch */
-       if (!strncmp(line, "@@ -", 4))
+       if (!prefixcmp(line, "@@ -"))
                return;
 
        new_len = remove_space(line, len);
diff --git a/diff.h b/diff.h
index eece65d..4043cec 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -75,6 +75,9 @@ struct diff_options {
        int stat_width;
        int stat_name_width;
 
+       /* this is set by diffcore for DIFF_FORMAT_PATCH */
+       int found_changes;
+
        int nr_paths;
        const char **paths;
        int *pathlens;
@@ -219,6 +222,7 @@ extern void diff_flush(struct diff_options*);
 extern const char *diff_unique_abbrev(const unsigned char *, int);
 
 extern int run_diff_files(struct rev_info *revs, int silent_on_removed);
+extern int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv);
 
 extern int run_diff_index(struct rev_info *revs, int cached);
 
diff --git a/entry.c b/entry.c
index c2641dd..21b5f2e 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -68,16 +68,19 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat
        void *new;
        unsigned long size;
        long wrote;
-       char type[20];
+       enum object_type type;
 
-       new = read_sha1_file(ce->sha1, type, &size);
-       if (!new || strcmp(type, blob_type)) {
+       new = read_sha1_file(ce->sha1, &type, &size);
+       if (!new || type != OBJ_BLOB) {
                if (new)
                        free(new);
                return error("git-checkout-index: unable to read sha1 file of %s (%s)",
                        path, sha1_to_hex(ce->sha1));
        }
        switch (ntohl(ce->ce_mode) & S_IFMT) {
+               char *buf;
+               unsigned long nsize;
+
        case S_IFREG:
                if (to_tempfile) {
                        strcpy(path, ".merge_file_XXXXXX");
@@ -89,7 +92,18 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat
                        return error("git-checkout-index: unable to create file %s (%s)",
                                path, strerror(errno));
                }
-               /* FIXME: LF -> CRLF conversion goes here, based on "ce->name" */
+
+               /*
+                * Convert from git internal format to working tree format
+                */
+               buf = new;
+               nsize = size;
+               if (convert_to_working_tree(ce->name, &buf, &nsize)) {
+                       free(new);
+                       new = buf;
+                       size = nsize;
+               }
+
                wrote = write_in_full(fd, new, size);
                close(fd);
                free(new);
index 54c22f8..570e32a 100644 (file)
@@ -28,6 +28,7 @@ size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
 size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
 int pager_in_use;
 int pager_use_color = 1;
+int auto_crlf = 0;     /* 1: both ways, -1: only when adding git objects */
 
 static const char *git_dir;
 static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file;
index 3996bce..9b74ed2 100644 (file)
@@ -56,7 +56,7 @@ int execv_git_cmd(const char **argv)
                        len = strlen(git_command);
 
                        /* Trivial cleanup */
-                       while (!strncmp(exec_dir, "./", 2)) {
+                       while (!prefixcmp(exec_dir, "./")) {
                                exec_dir += 2;
                                while (*exec_dir == '/')
                                        exec_dir++;
index 1ae125a..65e99c2 100644 (file)
@@ -891,7 +891,7 @@ static int store_object(
        SHA_CTX c;
        z_stream s;
 
-       hdrlen = sprintf((char*)hdr,"%s %lu", type_names[type],
+       hdrlen = sprintf((char*)hdr,"%s %lu", typename(type),
                (unsigned long)datlen) + 1;
        SHA1_Init(&c);
        SHA1_Update(&c, hdr, hdrlen);
@@ -1008,11 +1008,11 @@ static void *gfi_unpack_entry(
        struct object_entry *oe,
        unsigned long *sizep)
 {
-       static char type[20];
+       enum object_type type;
        struct packed_git *p = all_packs[oe->pack_id];
        if (p == pack_data)
                p->pack_size = pack_size + 20;
-       return unpack_entry(p, oe->offset, type, sizep);
+       return unpack_entry(p, oe->offset, &type, sizep);
 }
 
 static const char *get_mode(const char *str, uint16_t *modep)
@@ -1049,9 +1049,9 @@ static void load_tree(struct tree_entry *root)
                t->delta_depth = 0;
                buf = gfi_unpack_entry(myoe, &size);
        } else {
-               char type[20];
-               buf = read_sha1_file(sha1, type, &size);
-               if (!buf || strcmp(type, tree_type))
+               enum object_type type;
+               buf = read_sha1_file(sha1, &type, &size);
+               if (!buf || type != OBJ_TREE)
                        die("Can't load tree %s", sha1_to_hex(sha1));
        }
 
@@ -1312,7 +1312,7 @@ static int update_branch(struct branch *b)
                        return error("Branch %s is missing commits.", b->name);
                }
 
-               if (!in_merge_bases(old_cmit, new_cmit)) {
+               if (!in_merge_bases(old_cmit, &new_cmit, 1)) {
                        unlock_ref(lock);
                        warn("Not updating %s"
                                " (new tip %s does not contain %s)",
@@ -1392,7 +1392,7 @@ static void read_next_command(void)
 
 static void cmd_mark(void)
 {
-       if (!strncmp("mark :", command_buf.buf, 6)) {
+       if (!prefixcmp(command_buf.buf, "mark :")) {
                next_mark = strtoumax(command_buf.buf + 6, NULL, 10);
                read_next_command();
        }
@@ -1405,10 +1405,10 @@ static void *cmd_data (size_t *size)
        size_t length;
        char *buffer;
 
-       if (strncmp("data ", command_buf.buf, 5))
+       if (prefixcmp(command_buf.buf, "data "))
                die("Expected 'data n' command, found: %s", command_buf.buf);
 
-       if (!strncmp("<<", command_buf.buf + 5, 2)) {
+       if (!prefixcmp(command_buf.buf + 5, "<<")) {
                char *term = xstrdup(command_buf.buf + 5 + 2);
                size_t sz = 8192, term_len = command_buf.len - 5 - 2;
                length = 0;
@@ -1573,7 +1573,6 @@ static void file_change_m(struct branch *b)
        struct object_entry *oe = oe;
        unsigned char sha1[20];
        uint16_t mode, inline_data = 0;
-       char type[20];
 
        p = get_mode(p, &mode);
        if (!p)
@@ -1595,7 +1594,7 @@ static void file_change_m(struct branch *b)
                oe = find_mark(strtoumax(p + 1, &x, 10));
                hashcpy(sha1, oe->sha1);
                p = x;
-       } else if (!strncmp("inline", p, 6)) {
+       } else if (!prefixcmp(p, "inline")) {
                inline_data = 1;
                p += 6;
        } else {
@@ -1626,13 +1625,14 @@ static void file_change_m(struct branch *b)
        } else if (oe) {
                if (oe->type != OBJ_BLOB)
                        die("Not a blob (actually a %s): %s",
-                               command_buf.buf, type_names[oe->type]);
+                               command_buf.buf, typename(oe->type));
        } else {
-               if (sha1_object_info(sha1, type, NULL))
+               enum object_type type = sha1_object_info(sha1, NULL);
+               if (type < 0)
                        die("Blob not found: %s", command_buf.buf);
-               if (strcmp(blob_type, type))
+               if (type != OBJ_BLOB)
                        die("Not a blob (actually a %s): %s",
-                               command_buf.buf, type);
+                           typename(type), command_buf.buf);
        }
 
        tree_content_set(&b->branch_tree, p, sha1, S_IFREG | mode);
@@ -1668,7 +1668,7 @@ static void cmd_from(struct branch *b)
        const char *from;
        struct branch *s;
 
-       if (strncmp("from ", command_buf.buf, 5))
+       if (prefixcmp(command_buf.buf, "from "))
                return;
 
        if (b->branch_tree.tree) {
@@ -1711,7 +1711,7 @@ static void cmd_from(struct branch *b)
                        char *buf;
 
                        buf = read_object_with_reference(b->sha1,
-                               type_names[OBJ_COMMIT], &size, b->sha1);
+                               commit_type, &size, b->sha1);
                        if (!buf || size < 46)
                                die("Not a valid commit: %s", from);
                        if (memcmp("tree ", buf, 5)
@@ -1734,7 +1734,7 @@ static struct hash_list *cmd_merge(unsigned int *count)
        struct branch *s;
 
        *count = 0;
-       while (!strncmp("merge ", command_buf.buf, 6)) {
+       while (!prefixcmp(command_buf.buf, "merge ")) {
                from = strchr(command_buf.buf, ' ') + 1;
                n = xmalloc(sizeof(*n));
                s = lookup_branch(from);
@@ -1780,11 +1780,11 @@ static void cmd_new_commit(void)
 
        read_next_command();
        cmd_mark();
-       if (!strncmp("author ", command_buf.buf, 7)) {
+       if (!prefixcmp(command_buf.buf, "author ")) {
                author = parse_ident(command_buf.buf + 7);
                read_next_command();
        }
-       if (!strncmp("committer ", command_buf.buf, 10)) {
+       if (!prefixcmp(command_buf.buf, "committer ")) {
                committer = parse_ident(command_buf.buf + 10);
                read_next_command();
        }
@@ -1805,9 +1805,9 @@ static void cmd_new_commit(void)
        for (;;) {
                if (1 == command_buf.len)
                        break;
-               else if (!strncmp("M ", command_buf.buf, 2))
+               else if (!prefixcmp(command_buf.buf, "M "))
                        file_change_m(b);
-               else if (!strncmp("D ", command_buf.buf, 2))
+               else if (!prefixcmp(command_buf.buf, "D "))
                        file_change_d(b);
                else if (!strcmp("deleteall", command_buf.buf))
                        file_change_deleteall(b);
@@ -1877,7 +1877,7 @@ static void cmd_new_tag(void)
        read_next_command();
 
        /* from ... */
-       if (strncmp("from ", command_buf.buf, 5))
+       if (prefixcmp(command_buf.buf, "from "))
                die("Expected from command, got %s", command_buf.buf);
        from = strchr(command_buf.buf, ' ') + 1;
        s = lookup_branch(from);
@@ -1895,7 +1895,7 @@ static void cmd_new_tag(void)
                char *buf;
 
                buf = read_object_with_reference(sha1,
-                       type_names[OBJ_COMMIT], &size, sha1);
+                       commit_type, &size, sha1);
                if (!buf || size < 46)
                        die("Not a valid commit: %s", from);
                free(buf);
@@ -1904,7 +1904,7 @@ static void cmd_new_tag(void)
        read_next_command();
 
        /* tagger ... */
-       if (strncmp("tagger ", command_buf.buf, 7))
+       if (prefixcmp(command_buf.buf, "tagger "))
                die("Expected tagger command, got %s", command_buf.buf);
        tagger = parse_ident(command_buf.buf + 7);
 
@@ -1916,7 +1916,7 @@ static void cmd_new_tag(void)
        size_dbuf(&new_data, 67+strlen(t->name)+strlen(tagger)+msglen);
        sp = new_data.buffer;
        sp += sprintf(sp, "object %s\n", sha1_to_hex(sha1));
-       sp += sprintf(sp, "type %s\n", type_names[OBJ_COMMIT]);
+       sp += sprintf(sp, "type %s\n", commit_type);
        sp += sprintf(sp, "tag %s\n", t->name);
        sp += sprintf(sp, "tagger %s\n", tagger);
        *sp++ = '\n';
@@ -1981,7 +1981,7 @@ int main(int argc, const char **argv)
 
                if (*a != '-' || !strcmp(a, "--"))
                        break;
-               else if (!strncmp(a, "--date-format=", 14)) {
+               else if (!prefixcmp(a, "--date-format=")) {
                        const char *fmt = a + 14;
                        if (!strcmp(fmt, "raw"))
                                whenspec = WHENSPEC_RAW;
@@ -1992,15 +1992,15 @@ int main(int argc, const char **argv)
                        else
                                die("unknown --date-format argument %s", fmt);
                }
-               else if (!strncmp(a, "--max-pack-size=", 16))
+               else if (!prefixcmp(a, "--max-pack-size="))
                        max_packsize = strtoumax(a + 16, NULL, 0) * 1024 * 1024;
-               else if (!strncmp(a, "--depth=", 8))
+               else if (!prefixcmp(a, "--depth="))
                        max_depth = strtoul(a + 8, NULL, 0);
-               else if (!strncmp(a, "--active-branches=", 18))
+               else if (!prefixcmp(a, "--active-branches="))
                        max_active_branches = strtoul(a + 18, NULL, 0);
-               else if (!strncmp(a, "--export-marks=", 15))
+               else if (!prefixcmp(a, "--export-marks="))
                        mark_file = a + 15;
-               else if (!strncmp(a, "--export-pack-edges=", 20)) {
+               else if (!prefixcmp(a, "--export-pack-edges=")) {
                        if (pack_edges)
                                fclose(pack_edges);
                        pack_edges = fopen(a + 20, "a");
@@ -2033,11 +2033,11 @@ int main(int argc, const char **argv)
                        break;
                else if (!strcmp("blob", command_buf.buf))
                        cmd_new_blob();
-               else if (!strncmp("commit ", command_buf.buf, 7))
+               else if (!prefixcmp(command_buf.buf, "commit "))
                        cmd_new_commit();
-               else if (!strncmp("tag ", command_buf.buf, 4))
+               else if (!prefixcmp(command_buf.buf, "tag "))
                        cmd_new_tag();
-               else if (!strncmp("reset ", command_buf.buf, 6))
+               else if (!prefixcmp(command_buf.buf, "reset "))
                        cmd_reset_branch();
                else if (!strcmp("checkpoint", command_buf.buf))
                        cmd_checkpoint();
index c787106..41bdd27 100644 (file)
@@ -198,13 +198,13 @@ static int find_common(int fd[2], unsigned char *result_sha1,
                int len;
 
                while ((len = packet_read_line(fd[0], line, sizeof(line)))) {
-                       if (!strncmp("shallow ", line, 8)) {
+                       if (!prefixcmp(line, "shallow ")) {
                                if (get_sha1_hex(line + 8, sha1))
                                        die("invalid shallow line: %s", line);
                                register_shallow(sha1);
                                continue;
                        }
-                       if (!strncmp("unshallow ", line, 10)) {
+                       if (!prefixcmp(line, "unshallow ")) {
                                if (get_sha1_hex(line + 10, sha1))
                                        die("invalid unshallow line: %s", line);
                                if (!lookup_object(sha1))
@@ -346,7 +346,7 @@ static void filter_refs(struct ref **refs, int nr_match, char **match)
                    check_ref_format(ref->name + 5))
                        ; /* trash */
                else if (fetch_all &&
-                        (!depth || strncmp(ref->name, "refs/tags/", 10) )) {
+                        (!depth || prefixcmp(ref->name, "refs/tags/") )) {
                        *newtail = ref;
                        ref->next = NULL;
                        newtail = &ref->next;
@@ -683,11 +683,11 @@ int main(int argc, char **argv)
                char *arg = argv[i];
 
                if (*arg == '-') {
-                       if (!strncmp("--upload-pack=", arg, 14)) {
+                       if (!prefixcmp(arg, "--upload-pack=")) {
                                uploadpack = arg + 14;
                                continue;
                        }
-                       if (!strncmp("--exec=", arg, 7)) {
+                       if (!prefixcmp(arg, "--exec=")) {
                                uploadpack = arg + 7;
                                continue;
                        }
@@ -712,7 +712,7 @@ int main(int argc, char **argv)
                                verbose = 1;
                                continue;
                        }
-                       if (!strncmp("--depth=", arg, 8)) {
+                       if (!prefixcmp(arg, "--depth=")) {
                                depth = strtol(arg + 8, NULL, 0);
                                if (stat(git_path("shallow"), &st))
                                        st.st_mtime = 0;
index 476f4f1..be3677c 100755 (executable)
@@ -13,10 +13,10 @@ git-rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t
 case "$0" in
 *status)
        status_only=t
-       unmerged_ok_if_status=--unmerged ;;
+       ;;
 *commit)
        status_only=
-       unmerged_ok_if_status= ;;
+       ;;
 esac
 
 refuse_partial () {
@@ -393,16 +393,17 @@ else
        USE_INDEX="$THIS_INDEX"
 fi
 
-GIT_INDEX_FILE="$USE_INDEX" \
-       git-update-index -q $unmerged_ok_if_status --refresh || exit
-
-################################################################
-# If the request is status, just show it and exit.
-
-case "$0" in
-*status)
+case "$status_only" in
+t)
+       # This will silently fail in a read-only repository, which is
+       # what we want.
+       GIT_INDEX_FILE="$USE_INDEX" git-update-index -q --unmerged --refresh
        run_status
        exit $?
+       ;;
+'')
+       GIT_INDEX_FILE="$USE_INDEX" git-update-index -q --refresh || exit
+       ;;
 esac
 
 ################################################################
index 9863cf6..5d154fa 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef GIT_COMPAT_UTIL_H
 #define GIT_COMPAT_UTIL_H
 
+#define _FILE_OFFSET_BITS 64
+
 #ifndef FLEX_ARRAY
 #if defined(__GNUC__) && (__GNUC__ < 3)
 #define FLEX_ARRAY 0
@@ -279,4 +281,9 @@ static inline int sane_case(int x, int high)
        return x;
 }
 
+static inline int prefixcmp(const char *str, const char *prefix)
+{
+       return strncmp(str, prefix, strlen(prefix));
+}
+
 #endif
index 32a4883..67224b4 100755 (executable)
@@ -15,14 +15,21 @@ unless ($ENV{GIT_DIR} && -r $ENV{GIT_DIR}){
     die "GIT_DIR is not defined or is unreadable";
 }
 
-our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m );
+our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m, $opt_d);
 
-getopts('hPpvcfam:');
+getopts('hPpvcfam:d:');
 
 $opt_h && usage();
 
 die "Need at least one commit identifier!" unless @ARGV;
 
+my @cvs;
+if ($opt_d) {
+       @cvs = ('cvs', '-d', $opt_d);
+} else {
+       @cvs = ('cvs');
+}
+
 # setup a tempdir
 our ($tmpdir, $tmpdirname) = tempdir('git-cvsapplycommit-XXXXXX',
                                     TMPDIR => 1,
@@ -160,7 +167,7 @@ foreach my $f (@afiles) {
        my $p = $1;
        next if (grep { $_ eq $p } @dirs);
     }
-    my @status = grep(m/^File/,  safe_pipe_capture('cvs', '-q', 'status' ,$f));
+    my @status = grep(m/^File/,  safe_pipe_capture(@cvs, '-q', 'status' ,$f));
     if (@status > 1) { warn 'Strange! cvs status returned more than one line?'};
     if (-d dirname $f and $status[0] !~ m/Status: Unknown$/
        and $status[0] !~ m/^File: no file /) {
@@ -173,7 +180,7 @@ foreach my $f (@afiles) {
 foreach my $f (@files) {
     next if grep { $_ eq $f } @afiles;
     # TODO:we need to handle removed in cvs
-    my @status = grep(m/^File/,  safe_pipe_capture('cvs', '-q', 'status' ,$f));
+    my @status = grep(m/^File/,  safe_pipe_capture(@cvs, '-q', 'status' ,$f));
     if (@status > 1) { warn 'Strange! cvs status returned more than one line?'};
     unless ($status[0] =~ m/Status: Up-to-date$/) {
        $dirty = 1;
@@ -194,7 +201,7 @@ print "Applying\n";
 print "Patch applied successfully. Adding new files and directories to CVS\n";
 my $dirtypatch = 0;
 foreach my $d (@dirs) {
-    if (system('cvs','add',$d)) {
+    if (system(@cvs,'add',$d)) {
        $dirtypatch = 1;
        warn "Failed to cvs add directory $d -- you may need to do it manually";
     }
@@ -202,9 +209,9 @@ foreach my $d (@dirs) {
 
 foreach my $f (@afiles) {
     if (grep { $_ eq $f } @bfiles) {
-      system('cvs', 'add','-kb',$f);
+      system(@cvs, 'add','-kb',$f);
     } else {
-      system('cvs', 'add', $f);
+      system(@cvs, 'add', $f);
     }
     if ($?) {
        $dirtypatch = 1;
@@ -213,7 +220,7 @@ foreach my $f (@afiles) {
 }
 
 foreach my $f (@dfiles) {
-    system('cvs', 'rm', '-f', $f);
+    system(@cvs, 'rm', '-f', $f);
     if ($?) {
        $dirtypatch = 1;
        warn "Failed to cvs rm -f $f -- you may need to do it manually";
@@ -223,7 +230,7 @@ foreach my $f (@dfiles) {
 print "Commit to CVS\n";
 print "Patch title (first comment line): $title\n";
 my @commitfiles = map { unless (m/\s/) { '\''.$_.'\''; } else { $_; }; } (@files);
-my $cmd = "cvs commit -F .msg @commitfiles";
+my $cmd = join(' ', @cvs)." commit -F .msg @commitfiles";
 
 if ($dirtypatch) {
     print "NOTE: One or more hunks failed to apply cleanly.\n";
@@ -236,7 +243,7 @@ if ($dirtypatch) {
 
 if ($opt_c) {
     print "Autocommit\n  $cmd\n";
-    print safe_pipe_capture('cvs', 'commit', '-F', '.msg', @files);
+    print safe_pipe_capture(@cvs, 'commit', '-F', '.msg', @files);
     if ($?) {
        die "Exiting: The commit did not succeed";
     }
index 9371788..1bf892e 100755 (executable)
@@ -374,7 +374,8 @@ sub req_add
 
         print "Checked-in $dirpart\n";
         print "$filename\n";
-        print "/$filepart/0///\n";
+        my $kopts = kopts_from_path($filepart);
+        print "/$filepart/0//$kopts/\n";
 
         $addcount++;
     }
@@ -455,7 +456,8 @@ sub req_remove
 
         print "Checked-in $dirpart\n";
         print "$filename\n";
-        print "/$filepart/-1.$wrev///\n";
+        my $kopts = kopts_from_path($filepart);
+        print "/$filepart/-1.$wrev//$kopts/\n";
 
         $rmcount++;
     }
@@ -726,7 +728,8 @@ sub req_co
        print $state->{CVSROOT} . "/$module/" . ( defined ( $git->{dir} ) and $git->{dir} ne "./" ? $git->{dir} . "/" : "" ) . "$git->{name}\n";
 
         # this is an "entries" line
-        print "/$git->{name}/1.$git->{revision}///\n";
+        my $kopts = kopts_from_path($git->{name});
+        print "/$git->{name}/1.$git->{revision}//$kopts/\n";
         # permissions
         print "u=$git->{mode},g=$git->{mode},o=$git->{mode}\n";
 
@@ -917,8 +920,9 @@ sub req_update
                print $state->{CVSROOT} . "/$state->{module}/$filename\n";
 
                # this is an "entries" line
-               $log->debug("/$filepart/1.$meta->{revision}///");
-               print "/$filepart/1.$meta->{revision}///\n";
+               my $kopts = kopts_from_path($filepart);
+               $log->debug("/$filepart/1.$meta->{revision}//$kopts/");
+               print "/$filepart/1.$meta->{revision}//$kopts/\n";
 
                # permissions
                $log->debug("SEND : u=$meta->{mode},g=$meta->{mode},o=$meta->{mode}");
@@ -961,8 +965,9 @@ sub req_update
                     print "Update-existing $dirpart\n";
                     $log->debug($state->{CVSROOT} . "/$state->{module}/$filename");
                     print $state->{CVSROOT} . "/$state->{module}/$filename\n";
-                    $log->debug("/$filepart/1.$meta->{revision}///");
-                    print "/$filepart/1.$meta->{revision}///\n";
+                    my $kopts = kopts_from_path($filepart);
+                    $log->debug("/$filepart/1.$meta->{revision}//$kopts/");
+                    print "/$filepart/1.$meta->{revision}//$kopts/\n";
                 }
             }
             elsif ( $return == 1 )
@@ -975,7 +980,8 @@ sub req_update
                 {
                     print "Update-existing $dirpart\n";
                     print $state->{CVSROOT} . "/$state->{module}/$filename\n";
-                    print "/$filepart/1.$meta->{revision}/+//\n";
+                    my $kopts = kopts_from_path($filepart);
+                    print "/$filepart/1.$meta->{revision}/+/$kopts/\n";
                 }
             }
             else
@@ -1031,36 +1037,35 @@ sub req_ci
         exit;
     }
 
-    my $lockfile = "$state->{CVSROOT}/refs/heads/$state->{module}.lock";
-    unless ( sysopen(LOCKFILE,$lockfile,O_EXCL|O_CREAT|O_WRONLY) )
-    {
-        $log->warn("lockfile '$lockfile' already exists, please try again");
-        print "error 1 Lock file '$lockfile' already exists, please try again\n";
-        exit;
-    }
-
     # Grab a handle to the SQLite db and do any necessary updates
     my $updater = GITCVS::updater->new($state->{CVSROOT}, $state->{module}, $log);
     $updater->update();
 
     my $tmpdir = tempdir ( DIR => $TEMP_DIR );
     my ( undef, $file_index ) = tempfile ( DIR => $TEMP_DIR, OPEN => 0 );
-    $log->info("Lock successful, basing commit on '$tmpdir', index file is '$file_index'");
+    $log->info("Lockless commit start, basing commit on '$tmpdir', index file is '$file_index'");
 
     $ENV{GIT_DIR} = $state->{CVSROOT} . "/";
     $ENV{GIT_INDEX_FILE} = $file_index;
 
+    # Remember where the head was at the beginning.
+    my $parenthash = `git show-ref -s refs/heads/$state->{module}`;
+    chomp $parenthash;
+    if ($parenthash !~ /^[0-9a-f]{40}$/) {
+           print "error 1 pserver cannot find the current HEAD of module";
+           exit;
+    }
+
     chdir $tmpdir;
 
     # populate the temporary index based
-    system("git-read-tree", $state->{module});
+    system("git-read-tree", $parenthash);
     unless ($? == 0)
     {
        die "Error running git-read-tree $state->{module} $file_index $!";
     }
     $log->info("Created index '$file_index' with for head $state->{module} - exit status $?");
 
-
     my @committedfiles = ();
 
     # foreach file specified on the command line ...
@@ -1095,8 +1100,6 @@ sub req_ci
         {
             # fail everything if an up to date check fails
             print "error 1 Up to date check failed for $filename\n";
-            close LOCKFILE;
-            unlink($lockfile);
             chdir "/";
             exit;
         }
@@ -1139,16 +1142,12 @@ sub req_ci
     {
         print "E No files to commit\n";
         print "ok\n";
-        close LOCKFILE;
-        unlink($lockfile);
         chdir "/";
         return;
     }
 
     my $treehash = `git-write-tree`;
-    my $parenthash = `cat $ENV{GIT_DIR}refs/heads/$state->{module}`;
     chomp $treehash;
-    chomp $parenthash;
 
     $log->debug("Treehash : $treehash, Parenthash : $parenthash");
 
@@ -1159,19 +1158,36 @@ sub req_ci
     close $msg_fh;
 
     my $commithash = `git-commit-tree $treehash -p $parenthash < $msg_filename`;
+    chomp($commithash);
     $log->info("Commit hash : $commithash");
 
     unless ( $commithash =~ /[a-zA-Z0-9]{40}/ )
     {
         $log->warn("Commit failed (Invalid commit hash)");
         print "error 1 Commit failed (unknown reason)\n";
-        close LOCKFILE;
-        unlink($lockfile);
         chdir "/";
         exit;
     }
 
-    print LOCKFILE $commithash;
+       # Check that this is allowed, just as we would with a receive-pack
+       my @cmd = ( $ENV{GIT_DIR}.'hooks/update', "refs/heads/$state->{module}",
+                       $parenthash, $commithash );
+       if( -x $cmd[0] ) {
+               unless( system( @cmd ) == 0 )
+               {
+                       $log->warn("Commit failed (update hook declined to update ref)");
+                       print "error 1 Commit failed (update hook declined)\n";
+                       chdir "/";
+                       exit;
+               }
+       }
+
+       if (system(qw(git update-ref -m), "cvsserver ci",
+                       "refs/heads/$state->{module}", $commithash, $parenthash)) {
+               $log->warn("update-ref for $state->{module} failed.");
+               print "error 1 Cannot commit -- update first\n";
+               exit;
+       }
 
     $updater->update();
 
@@ -1196,16 +1212,12 @@ sub req_ci
         } else {
             print "Checked-in $dirpart\n";
             print "$filename\n";
-            print "/$filepart/1.$meta->{revision}///\n";
+            my $kopts = kopts_from_path($filepart);
+            print "/$filepart/1.$meta->{revision}//$kopts/\n";
         }
     }
 
-    close LOCKFILE;
-    my $reffile = "$ENV{GIT_DIR}refs/heads/$state->{module}";
-    unlink($reffile);
-    rename($lockfile, $reffile);
     chdir "/";
-
     print "ok\n";
 }
 
@@ -1882,6 +1894,28 @@ sub filecleanup
     return $filename;
 }
 
+# Given a path, this function returns a string containing the kopts
+# that should go into that path's Entries line.  For example, a binary
+# file should get -kb.
+sub kopts_from_path
+{
+       my ($path) = @_;
+
+       # Once it exists, the git attributes system should be used to look up
+       # what attributes apply to this path.
+
+       # Until then, take the setting from the config file
+    unless ( defined ( $cfg->{gitcvs}{allbinary} ) and $cfg->{gitcvs}{allbinary} =~ /^\s*(1|true|yes)\s*$/i )
+    {
+               # Return "" to give no special treatment to any path
+               return "";
+    } else {
+               # Alternatively, to have all files treated as if they are binary (which
+               # is more like git itself), always return the "-kb" option
+               return "-kb";
+    }
+}
+
 package GITCVS::log;
 
 ####
index ca984e7..d230995 100755 (executable)
@@ -243,6 +243,15 @@ then
        orig_head=$(git-rev-parse --verify HEAD 2>/dev/null)
 fi
 
+# Allow --notags from remote.$1.tagopt
+case "$tags$no_tags" in
+'')
+       case "$(git-config --get "remote.$1.tagopt")" in
+       --no-tags)
+               no_tags=t ;;
+       esac
+esac
+
 # If --tags (and later --heads or --all) is specified, then we are
 # not talking about defaults stored in Pull: line of remotes or
 # branches file, and just fetch those and refspecs explicitly given.
index 670bafb..bd70bf1 100755 (executable)
@@ -274,6 +274,31 @@ sub add_remote {
        }
 }
 
+sub update_remote {
+       my ($name) = @_;
+
+        my $conf = $git->config("remotes." . $name);
+       if (defined($conf)) {
+               @remotes = split(' ', $conf);
+       } elsif ($name eq 'default') {
+               undef @remotes;
+               for (sort keys %$remote) {
+                       my $do_fetch = $git->config_boolean("remote." . $_ .
+                                                   ".skipDefaultUpdate");
+                       if (!defined($do_fetch) || $do_fetch ne "true") {
+                               push @remotes, $_;
+                       }
+               }
+       } else {
+               print STDERR "Remote group $name does not exists.\n";
+               exit(1);
+       }
+       for (@remotes) {
+               print "Updating $_\n";
+               $git->command('fetch', "$_");
+       }
+}
+
 sub add_usage {
        print STDERR "Usage: git remote add [-f] [-t track]* [-m master] <name> <url>\n";
        exit(1);
@@ -303,6 +328,15 @@ elsif ($ARGV[0] eq 'show') {
                show_remote($ARGV[$i], $ls_remote);
        }
 }
+elsif ($ARGV[0] eq 'update') {
+       if (@ARGV <= 1) {
+               update_remote("default");
+               exit(1);
+       }
+       for ($i = 1; $i < @ARGV; $i++) {
+               update_remote($ARGV[$i]);
+       }
+}
 elsif ($ARGV[0] eq 'prune') {
        my $ls_remote = 1;
        my $i;
@@ -360,5 +394,6 @@ else {
        print STDERR "       git remote add <name> <url>\n";
        print STDERR "       git remote show <name>\n";
        print STDERR "       git remote prune <name>\n";
+       print STDERR "       git remote update [group]\n";
        exit(1);
 }
index 6a285bf..a71a192 100755 (executable)
@@ -34,6 +34,53 @@ sub readline {
 }
 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.
+
+   --bcc          Specify a list of email addresses that should be Bcc:
+                 on all the emails.
+
+   --compose      Use \$EDITOR 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.
+
+   --no-signed-off-cc Suppress the automatic addition of email addresses
+                 that appear in a Signed-off-by: line, to the cc: list.
+                Note: Using this option is not recommended.
+
+   --smtp-server  If set, specifies the outgoing SMTP server to use.
+                  Defaults to localhost.
+
+   --suppress-from Suppress sending emails to yourself if your address
+                  appears in a From: line.
+
+   --quiet       Make git-send-email less verbose.  One line per email
+                  should be all that is output.
+
+EOT
+       exit(1);
+}
+
 # most mail servers generate the Date: header, but not all...
 sub format_2822_time {
        my ($time) = @_;
@@ -120,6 +167,10 @@ my $rc = GetOptions("from=s" => \$from,
                    "dry-run" => \$dry_run,
         );
 
+unless ($rc) {
+    usage();
+}
+
 # Verify the user input
 
 foreach my $entry (@to) {
@@ -311,50 +362,8 @@ if (@files) {
                print $_,"\n" for (@files);
        }
 } else {
-       print <<EOT;
-git-send-email [options] <file | directory> [... 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.
-
-   --bcc          Specify a list of email addresses that should be Bcc:
-                 on all the emails.
-
-   --compose      Use \$EDITOR 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.
-
-   --no-signed-off-cc Suppress the automatic addition of email addresses
-                 that appear in a Signed-off-by: line, to the cc: list.
-                Note: Using this option is not recommended.
-
-   --smtp-server  If set, specifies the outgoing SMTP server to use.
-                  Defaults to localhost.