Merge branch 'qq/maint'
authorJunio C Hamano <gitster@pobox.com>
Sun, 6 Jul 2008 01:33:16 +0000 (18:33 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sun, 6 Jul 2008 01:33:16 +0000 (18:33 -0700)
* qq/maint:
clone -q: honor "quiet" option over native transports.
attribute documentation: keep EXAMPLE at end
builtin-commit.c: Use 'git_config_string' to get 'commit.template'
http.c: Use 'git_config_string' to clean up SSL config.
diff.c: Use 'git_config_string' to get 'diff.external'
convert.c: Use 'git_config_string' to get 'smudge' and 'clean'
builtin-log.c: Use 'git_config_string' to get 'format.subjectprefix' and 'format.suffix'
Documentation cvs: Clarify when a bare repository is needed
Documentation: be precise about which date --pretty uses

Conflicts:

Documentation/gitattributes.txt

1  2 
Documentation/git-cvsimport.txt
Documentation/git-cvsserver.txt
Documentation/gitattributes.txt
Documentation/gitcvs-migration.txt
builtin-commit.c
diff.c
transport.c
index 1614e8df89d5eae6afda812aa5e9abc808426dbf,93b7d2dc998f9e7c8bedf39f686b81c95deffa6c..b7a8c10b8709108c1c8a0d14f661c179c2b4f22c
@@@ -9,7 -9,7 +9,7 @@@ git-cvsimport - Salvage your data out o
  SYNOPSIS
  --------
  [verse]
 -'git-cvsimport' [-o <branch-for-HEAD>] [-h] [-v] [-d <CVSROOT>]
 +'git cvsimport' [-o <branch-for-HEAD>] [-h] [-v] [-d <CVSROOT>]
              [-A <author-conv-file>] [-p <options-for-cvsps>] [-P <file>]
              [-C <git_repository>] [-z <fuzz>] [-i] [-k] [-u] [-s <subst>]
              [-a] [-m] [-M <regex>] [-S <regex>] [-L <commitlimit>]
@@@ -25,12 -25,18 +25,18 @@@ Splitting the CVS log into patch sets i
  At least version 2.1 is required.
  
  You should *never* do any work of your own on the branches that are
 -created by git-cvsimport.  By default initial import will create and populate a
 +created by 'git-cvsimport'.  By default initial import will create and populate a
  "master" branch from the CVS repository's main branch which you're free
 -to work with; after that, you need to 'git merge' incremental imports, or
 +to work with; after that, you need to 'git-merge' incremental imports, or
  any CVS branches, yourself.  It is advisable to specify a named remote via
  -r to separate and protect the incoming branches.
  
+ If you intend to set up a shared public repository that all developers can
+ read/write, or if you want to use linkgit:git-cvsserver[1], then you
+ probably want to make a bare clone of the imported repository,
+ and use the clone as the shared repository.
+ See linkgit:gitcvs-migration[7].
  
  OPTIONS
  -------
  -d <CVSROOT>::
        The root of the CVS archive. May be local (a simple path) or remote;
        currently, only the :local:, :ext: and :pserver: access methods
 -      are supported. If not given, git-cvsimport will try to read it
 +      are supported. If not given, 'git-cvsimport' will try to read it
        from `CVS/Root`. If no such file exists, it checks for the
        `CVSROOT` environment variable.
  
  <CVS_module>::
        The CVS module you want to import. Relative to <CVSROOT>.
 -      If not given, git-cvsimport tries to read it from
 +      If not given, 'git-cvsimport' tries to read it from
        `CVS/Repository`.
  
  -C <target-dir>::
  -r <remote>::
        The git remote to import this CVS repository into.
        Moves all CVS branches into remotes/<remote>/<branch>
 -      akin to the git-clone --use-separate-remote option.
 +      akin to the 'git-clone' "--use-separate-remote" option.
  
  -o <branch-for-HEAD>::
        When no remote is specified (via -r) the 'HEAD' branch
        from CVS is imported to the 'origin' branch within the git
        repository, as 'HEAD' already has a special meaning for git.
        When a remote is specified the 'HEAD' branch is named
 -      remotes/<remote>/master mirroring git-clone behaviour.
 +      remotes/<remote>/master mirroring 'git-clone' behaviour.
        Use this option if you want to import into a different
        branch.
  +
@@@ -136,17 -142,17 +142,17 @@@ This option can be used several times t
  
  ---------
  +
 -git-cvsimport will make it appear as those authors had
 +'git-cvsimport' will make it appear as those authors had
  their GIT_AUTHOR_NAME and GIT_AUTHOR_EMAIL set properly
  all along.
  +
  For convenience, this data is saved to `$GIT_DIR/cvs-authors`
  each time the '-A' option is provided and read from that same
 -file each time git-cvsimport is run.
 +file each time 'git-cvsimport' is run.
  +
  It is not recommended to use this feature if you intend to
  export changes back to CVS again later with
 -linkgit:git-cvsexportcommit[1].
 +'git-cvsexportcommit'.
  
  -h::
        Print a short usage message and exit.
index 2aacdc628f670d0f68f060515e23d6614f396eb4,19da87e71d252e666335de7c97a5abcdd5fadbf8..c2d3c90d27084e7de7e0f7c37b40f130f6960244
@@@ -22,7 -22,7 +22,7 @@@ cvspserver stream tcp nowait nobody /us
  Usage:
  
  [verse]
 -'git-cvsserver' [options] [pserver|server] [<directory> ...]
 +'git cvsserver' [options] [pserver|server] [<directory> ...]
  
  OPTIONS
  -------
@@@ -77,7 -77,7 +77,7 @@@ over pserver for anonymous CVS access
  
  CVS clients cannot tag, branch or perform GIT merges.
  
 -git-cvsserver maps GIT branches to CVS modules. This is very different
 +'git-cvsserver' maps GIT branches to CVS modules. This is very different
  from what most CVS users would expect since in CVS modules usually represent
  one or more directories.
  
@@@ -103,7 -103,7 +103,7 @@@ looks lik
  ------
  No special setup is needed for SSH access, other than having GIT tools
  in the PATH. If you have clients that do not accept the CVS_SERVER
 -environment variable, you can rename git-cvsserver to cvs.
 +environment variable, you can rename 'git-cvsserver' to `cvs`.
  
  Note: Newer CVS versions (>= 1.12.11) also support specifying
  CVS_SERVER directly in CVSROOT like
@@@ -113,9 -113,9 +113,9 @@@ cvs -d ":ext;CVS_SERVER=git-cvsserver:u
  ------
  This has the advantage that it will be saved in your 'CVS/Root' files and
  you don't need to worry about always setting the correct environment
 -variable.  SSH users restricted to git-shell don't need to override the default
 -with CVS_SERVER (and shouldn't) as git-shell understands `cvs` to mean
 -git-cvsserver and pretends that the other end runs the real cvs better.
 +variable.  SSH users restricted to 'git-shell' don't need to override the default
 +with CVS_SERVER (and shouldn't) as 'git-shell' understands `cvs` to mean
 +'git-cvsserver' and pretends that the other end runs the real 'cvs' better.
  --
  2. For each repo that you want accessible from CVS you need to edit config in
     the repo and add the following section.
          logfile=/path/to/logfile
  
  ------
 -Note: you need to ensure each user that is going to invoke git-cvsserver has
 +Note: you need to ensure each user that is going to invoke 'git-cvsserver' has
  write access to the log file and to the database (see
  <<dbbackend,Database Backend>>. If you want to offer write access over
  SSH, the users of course also need write access to the git repository itself.
  
+ You also need to ensure that each repository is "bare" (without a git index
+ file) for `cvs commit` to work. See linkgit:gitcvs-migration[7].
  [[configaccessmethod]]
  All configuration variables can also be overridden for a specific method of
  access. Valid method names are "ext" (for SSH access) and "pserver". The
@@@ -150,7 -153,7 +153,7 @@@ allowing access over SSH
     automatically saving it in your 'CVS/Root' files, then you need to set them
     explicitly in your environment.  CVSROOT should be set as per normal, but the
     directory should point at the appropriate git repo.  As above, for SSH clients
 -   _not_ restricted to git-shell, CVS_SERVER should be set to git-cvsserver.
 +   _not_ restricted to 'git-shell', CVS_SERVER should be set to 'git-cvsserver'.
  +
  --
  ------
  Database Backend
  ----------------
  
 -git-cvsserver uses one database per git head (i.e. CVS module) to
 +'git-cvsserver' uses one database per git head (i.e. CVS module) to
  store information about the repository for faster access. The
  database doesn't contain any persistent data and can be completely
  regenerated from the git repository at any time. The database
  needs to be updated (i.e. written to) after every commit.
  
 -If the commit is done directly by using git (as opposed to
 -using git-cvsserver) the update will need to happen on the
 -next repository access by git-cvsserver, independent of
 +If the commit is done directly by using `git` (as opposed to
 +using 'git-cvsserver') the update will need to happen on the
 +next repository access by 'git-cvsserver', independent of
  access method and requested operation.
  
  That means that even if you offer only read access (e.g. by using
 -the pserver method), git-cvsserver should have write access to
 +the pserver method), 'git-cvsserver' should have write access to
  the database to work reliably (otherwise you need to make sure
 -that the database is up-to-date any time git-cvsserver is executed).
 +that the database is up-to-date any time 'git-cvsserver' is executed).
  
  By default it uses SQLite databases in the git directory, named
  `gitcvs.<module_name>.sqlite`. Note that the SQLite backend creates
  temporary files in the same directory as the database file on
  write so it might not be enough to grant the users using
 -git-cvsserver write access to the database file without granting
 +'git-cvsserver' write access to the database file without granting
  them write access to the directory, too.
  
  You can configure the database backend with the following
@@@ -207,7 -210,7 +210,7 @@@ configuration variables
  Configuring database backend
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
 -git-cvsserver uses the Perl DBI module. Please also read
 +'git-cvsserver' uses the Perl DBI module. Please also read
  its documentation if changing these variables, especially
  about `DBI->connect()`.
  
@@@ -259,7 -262,7 +262,7 @@@ In `dbdriver` and `dbuser` you can use 
  %a::
        access method (one of "ext" or "pserver")
  %u::
 -      Name of the user running git-cvsserver.
 +      Name of the user running 'git-cvsserver'.
        If no name can be determined, the
        numeric uid is used.
  
@@@ -285,8 -288,8 +288,8 @@@ you will definitely want to have SSH ke
  
  Alternatively, you can just use the non-standard extssh protocol that Eclipse
  offer. In that case CVS_SERVER is ignored, and you will have to replace
 -the cvs utility on the server with git-cvsserver or manipulate your `.bashrc`
 -so that calling 'cvs' effectively calls git-cvsserver.
 +the cvs utility on the server with 'git-cvsserver' or manipulate your `.bashrc`
 +so that calling 'cvs' effectively calls 'git-cvsserver'.
  
  Clients known to work
  ---------------------
@@@ -328,13 -331,14 +331,13 @@@ is left blank. But if `gitcvs.allbinary
  the correct '-k' mode will be guessed based on the contents of
  the file.
  
 -For best consistency with cvs, it is probably best to override the
 +For best consistency with 'cvs', it is probably best to override the
  defaults by setting `gitcvs.usecrlfattr` to true,
  and `gitcvs.allbinary` to "guess".
  
  Dependencies
  ------------
 -
 -git-cvsserver depends on DBD::SQLite.
 +'git-cvsserver' depends on DBD::SQLite.
  
  Copyright and Authors
  ---------------------
index 6a246eb1fc3229d4ba8f78f015af682eebf885e0,ef06d94ca8dd57762fcefe3b87921799d49dffb6..d7b41142d2c843bc5460f03c73c609b1c53ff4a6
@@@ -87,9 -87,9 +87,9 @@@ Checking-out and checking-i
  
  These attributes affect how the contents stored in the
  repository are copied to the working tree files when commands
 -such as `git checkout` and `git merge` run.  They also affect how
 +such as 'git-checkout' and 'git-merge' run.  They also affect how
  git stores the contents you prepare in the working tree in the
 -repository upon `git add` and `git commit`.
 +repository upon 'git-add' and 'git-commit'.
  
  `crlf`
  ^^^^^^
@@@ -148,16 -148,16 +148,16 @@@ an irreversible conversion.  The safet
  a conversion done to the files in the work tree, but there are a
  few exceptions.  Even though...
  
 -- "git add" itself does not touch the files in the work tree, the
 +- 'git-add' itself does not touch the files in the work tree, the
    next checkout would, so the safety triggers;
  
 -- "git apply" to update a text file with a patch does touch the files
 +- 'git-apply' to update a text file with a patch does touch the files
    in the work tree, but the operation is about text files and CRLF
    conversion is about fixing the line ending inconsistencies, so the
    safety does not trigger;
  
 -- "git diff" itself does not touch the files in the work tree, it is
 -  often run to inspect the changes you intend to next "git add".  To
 +- 'git-diff' itself does not touch the files in the work tree, it is
 +  often run to inspect the changes you intend to next 'git-add'.  To
    catch potential problems early, safety triggers.
  
  
@@@ -214,7 -214,7 +214,7 @@@ with `crlf`, and then `ident` and fed t
  Generating diff text
  ~~~~~~~~~~~~~~~~~~~~
  
 -The attribute `diff` affects if `git diff` generates textual
 +The attribute `diff` affects if 'git-diff' generates textual
  patch for the path or just says `Binary files differ`.  It also
  can affect what line is shown on the hunk header `@@ -k,l +n,m @@`
  line.
@@@ -278,7 -278,7 +278,7 @@@ is prefixed with a line of the form
  
  The text is called 'hunk header', and by default a line that
  begins with an alphabet, an underscore or a dollar sign is used,
 -which matches what GNU `diff -p` output uses.  This default
 +which matches what GNU 'diff -p' output uses.  This default
  selection however is not suited for some contents, and you can
  use customized pattern to make a selection.
  
@@@ -322,7 -322,7 +322,7 @@@ and other programs such as `git revert
  Set::
  
        Built-in 3-way merge driver is used to merge the
 -      contents in a way similar to `merge` command of `RCS`
 +      contents in a way similar to 'merge' command of `RCS`
        suite.  This is suitable for ordinary text files.
  
  Unset::
@@@ -426,7 -426,7 +426,7 @@@ Checking whitespace error
  ^^^^^^^^^^^^
  
  The `core.whitespace` configuration variable allows you to define what
 -`diff` and `apply` should consider whitespace errors for all paths in
 +'diff' and 'apply' should consider whitespace errors for all paths in
  the project (See linkgit:git-config[1]).  This attribute gives you finer
  control per path.
  
@@@ -450,6 -450,23 +450,29 @@@ String:
        variable.
  
  
 -expansion depends on the availability of a commit ID, i.e. if
+ Creating an archive
+ ~~~~~~~~~~~~~~~~~~~
++`export-ignore`
++^^^^^^^^^^^^^^^
++
++Files and directories with the attribute `export-ignore` won't be added to
++archive files.
++
+ `export-subst`
+ ^^^^^^^^^^^^^^
+ If the attribute `export-subst` is set for a file then git will expand
+ several placeholders when adding this file to an archive.  The
++expansion depends on the availability of a commit ID, i.e., if
+ linkgit:git-archive[1] has been given a tree instead of a commit or a
+ tag then no replacement will be done.  The placeholders are the same
+ as those for the option `--pretty=format:` of linkgit:git-log[1],
+ except that they need to be wrapped like this: `$Format:PLACEHOLDERS$`
+ in the file.  E.g. the string `$Format:%H$` will be replaced by the
+ commit hash.
  EXAMPLE
  -------
  
@@@ -499,28 -516,6 +522,6 @@@ frotz     unspecifie
  ----------------------------------------------------------------
  
  
- Creating an archive
- ~~~~~~~~~~~~~~~~~~~
- `export-ignore`
- ^^^^^^^^^^^^^^^
- Files and directories with the attribute `export-ignore` won't be added to
- archive files.
- `export-subst`
- ^^^^^^^^^^^^^^
- If the attribute `export-subst` is set for a file then git will expand
- several placeholders when adding this file to an archive.  The
- expansion depends on the availability of a commit ID, i.e., if
- 'git-archive' has been given a tree instead of a commit or a
- tag then no replacement will be done.  The placeholders are the same
- as those for the option `--pretty=format:` of linkgit:git-log[1],
- except that they need to be wrapped like this: `$Format:PLACEHOLDERS$`
- in the file.  E.g. the string `$Format:%H$` will be replaced by the
- commit hash.
  
  GIT
  ---
index 2eb6972a93f1033281b79fe03af6d80c06d576dc,0325d6759d5ee329f284dac625ef4c40c31082c7..aaa7ef737a4c190c60e37e2849ce42f3bdb5dda7
@@@ -18,9 -18,9 +18,9 @@@ important than any other.  However, yo
  designating a single shared repository which people can synchronize with;
  this document explains how to do that.
  
 -Some basic familiarity with git is required.  This
 -linkgit:gittutorial[7][tutorial introduction to git] and the
 -linkgit:gitglossary[7][git glossary] should be sufficient.
 +Some basic familiarity with git is required. Having gone through
 +linkgit:gittutorial[7] and
 +linkgit:gitglossary[7] should be sufficient.
  
  Developing against a shared repository
  --------------------------------------
@@@ -34,7 -34,7 +34,7 @@@ $ git clone foo.com:/pub/repo.git/ my-p
  $ cd my-project
  ------------------------------------------------
  
 -and hack away.  The equivalent of `cvs update` is
 +and hack away.  The equivalent of 'cvs update' is
  
  ------------------------------------------------
  $ git pull origin
@@@ -46,28 -46,28 +46,28 @@@ them first before running git pull
  
  [NOTE]
  ================================
 -The `pull` command knows where to get updates from because of certain
 -configuration variables that were set by the first `git clone`
 +The 'pull' command knows where to get updates from because of certain
 +configuration variables that were set by the first 'git-clone'
  command; see `git config -l` and the linkgit:git-config[1] man
  page for details.
  ================================
  
  You can update the shared repository with your changes by first committing
 -your changes, and then using the linkgit:git-push[1] command:
 +your changes, and then using the 'git-push' command:
  
  ------------------------------------------------
  $ git push origin master
  ------------------------------------------------
  
  to "push" those commits to the shared repository.  If someone else has
 -updated the repository more recently, `git push`, like `cvs commit`, will
 +updated the repository more recently, 'git-push', like 'cvs commit', will
  complain, in which case you must pull any changes before attempting the
  push again.
  
 -In the `git push` command above we specify the name of the remote branch
 -to update (`master`).  If we leave that out, `git push` tries to update
 +In the 'git-push' command above we specify the name of the remote branch
 +to update (`master`).  If we leave that out, 'git-push' tries to update
  any branches in the remote repository that have the same name as a branch
 -in the local repository.  So the last `push` can be done with either of:
 +in the local repository.  So the last 'push' can be done with either of:
  
  ------------
  $ git push origin
@@@ -81,8 -81,8 +81,8 @@@ Setting Up a Shared Repositor
  ------------------------------
  
  We assume you have already created a git repository for your project,
 -possibly created from scratch or from a tarball (see the
 -linkgit:gittutorial[7][tutorial]), or imported from an already existing CVS
 +possibly created from scratch or from a tarball (see
 +linkgit:gittutorial[7]), or imported from an already existing CVS
  repository (see the next section).
  
  Assume your existing repo is at /home/alice/myproject.  Create a new "bare"
@@@ -118,7 -118,7 +118,7 @@@ Importing a CVS archiv
  First, install version 2.1 or higher of cvsps from
  link:http://www.cobite.com/cvsps/[http://www.cobite.com/cvsps/] and make
  sure it is in your path.  Then cd to a checked out CVS working directory
 -of the project you are interested in and run linkgit:git-cvsimport[1]:
 +of the project you are interested in and run 'git-cvsimport':
  
  -------------------------------------------
  $ git cvsimport -C <destination> <module>
@@@ -143,12 -143,17 +143,17 @@@ work, you must not modify the imported 
  branches for your own changes, and merge in the imported branches as
  necessary.
  
+ If you want a shared repository, you will need to make a bare clone
+ of the imported directory, as described above. Then treat the imported
+ directory as another development clone for purposes of merging
+ incremental imports.
  Advanced Shared Repository Management
  -------------------------------------
  
  Git allows you to specify scripts called "hooks" to be run at certain
  points.  You can use these, for example, to send all commits to the shared
 -repository to a mailing list.  See linkgit:githooks[5][Hooks used by git].
 +repository to a mailing list.  See linkgit:githooks[5].
  
  You can enforce finer grained permissions using update hooks.  See
  link:howto/update-hook-example.txt[Controlling access to branches using
diff --combined builtin-commit.c
index e3ad38b3bd78bc2d19c5e5d1ebfbe0388b22582e,bcbea3893b6ddb40388f5a5ab49b022af5a88df1..745c11e7735ffcb070683d1af607b4ad85f48e23
@@@ -45,12 -45,12 +45,13 @@@ static enum 
        COMMIT_PARTIAL,
  } commit_style;
  
- static char *logfile, *force_author, *template_file;
+ static char *logfile, *force_author;
+ static const char *template_file;
  static char *edit_message, *use_message;
  static char *author_name, *author_email, *author_date;
  static int all, edit_flag, also, interactive, only, amend, signoff;
 -static int quiet, verbose, untracked_files, no_verify, allow_empty;
 +static int quiet, verbose, no_verify, allow_empty;
 +static char *untracked_files_arg;
  /*
   * The default commit message cleanup mode will remove the lines
   * beginning with # (shell comments) and leading and trailing
@@@ -103,7 -103,7 +104,7 @@@ static struct option builtin_commit_opt
        OPT_BOOLEAN('o', "only", &only, "commit only specified files"),
        OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"),
        OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
 -      OPT_BOOLEAN('u', "untracked-files", &untracked_files, "show all untracked files"),
 +      { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
        OPT_BOOLEAN(0, "allow-empty", &allow_empty, "ok to record an empty change"),
        OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"),
  
@@@ -348,7 -348,7 +349,7 @@@ static int run_status(FILE *fp, const c
                s.reference = "HEAD^1";
        }
        s.verbose = verbose;
 -      s.untracked = untracked_files;
 +      s.untracked = (show_untracked_files == SHOW_ALL_UNTRACKED_FILES);
        s.index_file = index_file;
        s.fp = fp;
        s.nowarn = nowarn;
@@@ -503,8 -503,7 +504,8 @@@ static int prepare_to_commit(const cha
  
        fp = fopen(git_path(commit_editmsg), "w");
        if (fp == NULL)
 -              die("could not open %s", git_path(commit_editmsg));
 +              die("could not open %s: %s",
 +                  git_path(commit_editmsg), strerror(errno));
  
        if (cleanup_mode != CLEANUP_NONE)
                stripspace(&sb, 0);
@@@ -797,17 -796,6 +798,17 @@@ static int parse_and_validate_options(i
        else
                die("Invalid cleanup mode %s", cleanup_arg);
  
 +      if (!untracked_files_arg)
 +              ; /* default already initialized */
 +      else if (!strcmp(untracked_files_arg, "no"))
 +              show_untracked_files = SHOW_NO_UNTRACKED_FILES;
 +      else if (!strcmp(untracked_files_arg, "normal"))
 +              show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
 +      else if (!strcmp(untracked_files_arg, "all"))
 +              show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
 +      else
 +              die("Invalid untracked files mode '%s'", untracked_files_arg);
 +
        if (all && argc > 0)
                die("Paths with -a does not make sense.");
        else if (interactive && argc > 0)
@@@ -877,12 -865,8 +878,8 @@@ static void print_summary(const char *p
  
  int git_commit_config(const char *k, const char *v, void *cb)
  {
-       if (!strcmp(k, "commit.template")) {
-               if (!v)
-                       return config_error_nonbool(v);
-               template_file = xstrdup(v);
-               return 0;
-       }
+       if (!strcmp(k, "commit.template"))
+               return git_config_string(&template_file, k, v);
  
        return git_status_config(k, v, cb);
  }
diff --combined diff.c
index 803fbba451dfe8226097dcb791c339ee2ccd6735,78c4d3a35a975d0ffef51dbe999d14938d0a90e3..6a39b393f3e276dd0e0352b5c05eec6989940854
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -153,12 -153,8 +153,8 @@@ int git_diff_ui_config(const char *var
                diff_auto_refresh_index = git_config_bool(var, value);
                return 0;
        }
-       if (!strcmp(var, "diff.external")) {
-               if (!value)
-                       return config_error_nonbool(var);
-               external_diff_cmd_cfg = xstrdup(value);
-               return 0;
-       }
+       if (!strcmp(var, "diff.external"))
+               return git_config_string(&external_diff_cmd_cfg, var, value);
        if (!prefixcmp(var, "diff.")) {
                const char *ep = strrchr(var, '.');
  
@@@ -535,9 -531,9 +531,9 @@@ static void emit_add_line(const char *r
        else {
                /* Emit just the prefix, then the rest. */
                emit_line(ecbdata->file, set, reset, line, ecbdata->nparents);
 -              (void)check_and_emit_line(line + ecbdata->nparents,
 -                  len - ecbdata->nparents, ecbdata->ws_rule,
 -                  ecbdata->file, set, reset, ws);
 +              ws_check_emit(line + ecbdata->nparents,
 +                            len - ecbdata->nparents, ecbdata->ws_rule,
 +                            ecbdata->file, set, reset, ws);
        }
  }
  
@@@ -830,12 -826,12 +826,12 @@@ static void show_stats(struct diffstat_
        /* Sanity: give at least 5 columns to the graph,
         * but leave at least 10 columns for the name.
         */
 -      if (width < name_width + 15) {
 -              if (name_width <= 25)
 -                      width = name_width + 15;
 -              else
 -                      name_width = width - 15;
 -      }
 +      if (width < 25)
 +              width = 25;
 +      if (name_width < 10)
 +              name_width = 10;
 +      else if (width < name_width + 15)
 +              name_width = width - 15;
  
        /* Find the longest filename and max number of changes */
        reset = diff_get_color_opt(options, DIFF_RESET);
                        total = add + del;
                }
                show_name(options->file, prefix, name, len, reset, set);
 -              fprintf(options->file, "%5d ", added + deleted);
 +              fprintf(options->file, "%5d%s", added + deleted,
 +                              added + deleted ? " " : "");
                show_graph(options->file, '+', add, add_c, reset);
                show_graph(options->file, '-', del, del_c, reset);
                fprintf(options->file, "\n");
@@@ -1136,85 -1131,42 +1132,85 @@@ static void free_diffstat_info(struct d
  struct checkdiff_t {
        struct xdiff_emit_state xm;
        const char *filename;
 -      int lineno, color_diff;
 +      int lineno;
 +      struct diff_options *o;
        unsigned ws_rule;
        unsigned status;
 -      FILE *file;
 +      int trailing_blanks_start;
  };
  
 +static int is_conflict_marker(const char *line, unsigned long len)
 +{
 +      char firstchar;
 +      int cnt;
 +
 +      if (len < 8)
 +              return 0;
 +      firstchar = line[0];
 +      switch (firstchar) {
 +      case '=': case '>': case '<':
 +              break;
 +      default:
 +              return 0;
 +      }
 +      for (cnt = 1; cnt < 7; cnt++)
 +              if (line[cnt] != firstchar)
 +                      return 0;
 +      /* line[0] thru line[6] are same as firstchar */
 +      if (firstchar == '=') {
 +              /* divider between ours and theirs? */
 +              if (len != 8 || line[7] != '\n')
 +                      return 0;
 +      } else if (len < 8 || !isspace(line[7])) {
 +              /* not divider before ours nor after theirs */
 +              return 0;
 +      }
 +      return 1;
 +}
 +
  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);
 +      int color_diff = DIFF_OPT_TST(data->o, COLOR_DIFF);
 +      const char *ws = diff_get_color(color_diff, DIFF_WHITESPACE);
 +      const char *reset = diff_get_color(color_diff, DIFF_RESET);
 +      const char *set = diff_get_color(color_diff, DIFF_FILE_NEW);
        char *err;
  
        if (line[0] == '+') {
                unsigned bad;
                data->lineno++;
 -              bad = check_and_emit_line(line + 1, len - 1,
 -                  data->ws_rule, NULL, NULL, NULL, NULL);
 +              if (!ws_blank_line(line + 1, len - 1, data->ws_rule))
 +                      data->trailing_blanks_start = 0;
 +              else if (!data->trailing_blanks_start)
 +                      data->trailing_blanks_start = data->lineno;
 +              if (is_conflict_marker(line + 1, len - 1)) {
 +                      data->status |= 1;
 +                      fprintf(data->o->file,
 +                              "%s:%d: leftover conflict marker\n",
 +                              data->filename, data->lineno);
 +              }
 +              bad = ws_check(line + 1, len - 1, data->ws_rule);
                if (!bad)
                        return;
                data->status |= bad;
                err = whitespace_error_string(bad);
 -              fprintf(data->file, "%s:%d: %s.\n", data->filename, data->lineno, err);
 +              fprintf(data->o->file, "%s:%d: %s.\n",
 +                      data->filename, data->lineno, err);
                free(err);
 -              emit_line(data->file, set, reset, line, 1);
 -              (void)check_and_emit_line(line + 1, len - 1, data->ws_rule,
 -                  data->file, set, reset, ws);
 -      } else if (line[0] == ' ')
 +              emit_line(data->o->file, set, reset, line, 1);
 +              ws_check_emit(line + 1, len - 1, data->ws_rule,
 +                            data->o->file, set, reset, ws);
 +      } else if (line[0] == ' ') {
                data->lineno++;
 -      else if (line[0] == '@') {
 +              data->trailing_blanks_start = 0;
 +      } else if (line[0] == '@') {
                char *plus = strchr(line, '+');
                if (plus)
                        data->lineno = strtol(plus, NULL, 10) - 1;
                else
                        die("invalid diff");
 +              data->trailing_blanks_start = 0;
        }
  }
  
@@@ -1587,9 -1539,8 +1583,9 @@@ static void builtin_diffstat(const cha
  
  static void builtin_checkdiff(const char *name_a, const char *name_b,
                              const char *attr_path,
 -                           struct diff_filespec *one,
 -                           struct diff_filespec *two, struct diff_options *o)
 +                            struct diff_filespec *one,
 +                            struct diff_filespec *two,
 +                            struct diff_options *o)
  {
        mmfile_t mf1, mf2;
        struct checkdiff_t data;
        data.xm.consume = checkdiff_consume;
        data.filename = name_b ? name_b : name_a;
        data.lineno = 0;
 -      data.color_diff = DIFF_OPT_TST(o, COLOR_DIFF);
 +      data.o = o;
        data.ws_rule = whitespace_rule(attr_path);
 -      data.file = o->file;
  
        if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
                die("unable to read files to diff");
  
 +      /*
 +       * All the other codepaths check both sides, but not checking
 +       * the "old" side here is deliberate.  We are checking the newly
 +       * introduced changes, and as long as the "new" side is text, we
 +       * can and should check what it introduces.
 +       */
        if (diff_filespec_is_binary(two))
                goto free_and_return;
        else {
                ecb.outf = xdiff_outf;
                ecb.priv = &data;
                xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
 +
 +              if (data.trailing_blanks_start) {
 +                      fprintf(o->file, "%s:%d: ends with blank lines.\n",
 +                              data.filename, data.trailing_blanks_start);
 +                      data.status = 1; /* report errors */
 +              }
        }
   free_and_return:
        diff_free_filespec_data(one);
diff --combined transport.c
index 4145eed9794a956b05967f049fe2caedcaa67feb,6f549b336ba1f7c84f45bd13317949bae4f9c704..6eb65b873afc9dfd457e974b63d88350bb8dc913
@@@ -645,7 -645,9 +645,9 @@@ static int fetch_refs_via_pack(struct t
        args.lock_pack = 1;
        args.use_thin_pack = data->thin;
        args.include_tag = data->followtags;
-       args.verbose = transport->verbose > 0;
+       args.verbose = (transport->verbose > 0);
+       args.quiet = args.no_progress = (transport->verbose < 0);
+       args.no_progress = !isatty(1);
        args.depth = data->depth;
  
        for (i = 0; i < nr_heads; i++)
@@@ -709,8 -711,7 +711,8 @@@ static int is_local(const char *url
  {
        const char *colon = strchr(url, ':');
        const char *slash = strchr(url, '/');
 -      return !colon || (slash && slash < colon);
 +      return !colon || (slash && slash < colon) ||
 +              has_dos_drive_prefix(url);
  }
  
  static int is_file(const char *url)