Merge branch 'mv/defer-gc'
authorJunio C Hamano <gitster@pobox.com>
Sun, 20 Apr 2008 04:12:24 +0000 (21:12 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sun, 20 Apr 2008 04:12:24 +0000 (21:12 -0700)
* mv/defer-gc:
contrib/hooks: add an example pre-auto-gc hook
Documentation/hooks: add pre-auto-gc hook
git-gc --auto: add pre-auto-gc hook

68 files changed:
Documentation/config.txt
Documentation/core-tutorial.txt
Documentation/git-bisect.txt
Documentation/git-commit.txt
Documentation/git-config.txt
Documentation/git-cvsserver.txt
Documentation/git-request-pull.txt
Documentation/git-rm.txt
Documentation/git-shortlog.txt
Documentation/git-status.txt
Documentation/git-submodule.txt
Documentation/git-tag.txt
Documentation/git-unpack-objects.txt
Documentation/gitk.txt
Documentation/howto/setup-git-server-over-http.txt
Documentation/pretty-formats.txt
Makefile
archive-tar.c
archive-zip.c
builtin-apply.c
builtin-clean.c
builtin-commit.c
builtin-config.c
builtin-fetch.c
builtin-fmt-merge-msg.c
builtin-log.c
builtin-remote.c
builtin-shortlog.c
builtin-tag.c
builtin-unpack-objects.c
cache.h
commit.h
config.c
diffcore-rename.c
dir.c
git-add--interactive.perl
git-am.sh
git-bisect.sh
git-rebase.sh
git-send-email.perl
git-submodule.sh
git-svn.perl
gitweb/INSTALL
gitweb/README
gitweb/gitweb.perl
log-tree.c
parse-options.c
perl/Git.pm
pretty.c
receive-pack.c
remote.c
remote.h
revision.c
revision.h
t/t1300-repo-config.sh
t/t3408-rebase-multi-line.sh [new file with mode: 0755]
t/t3701-add-interactive.sh
t/t5000-tar-tree.sh
t/t5300-pack-object.sh
t/t5505-remote.sh
t/t5516-fetch-push.sh
t/t6030-bisect-porcelain.sh
t/t7300-clean.sh
t/t7401-submodule-summary.sh
t/t7502-status.sh
t/t9500-gitweb-standalone-no-errors.sh
var.c
wt-status.c
index 04c01c5fdca566b1760e8eed02687607017e89aa..fe43b12572fcb1a0b4b91972d2d504b2b594a4da 100644 (file)
@@ -991,6 +991,12 @@ imap::
        The configuration variables in the 'imap' section are described
        in linkgit:git-imap-send[1].
 
+receive.fsckObjects::
+       If it is set to true, git-receive-pack will check all received
+       objects. It will abort in the case of a malformed object or a
+       broken link. The result of an abort are only dangling objects.
+       Defaults to false.
+
 receive.unpackLimit::
        If the number of objects received in a push is below this
        limit then the objects will be unpacked into loose object
index aa40dfd36a6f210c5808791225014e023d18c0de..5a5531222d8f514b27ba63d9fc9ecc17335cdc3c 100644 (file)
@@ -535,18 +535,18 @@ with the associated patches use the more complex (and much more
 powerful)
 
 ----------------
-$ git-whatchanged -p --root
+$ git-whatchanged -p
 ----------------
 
 and you will see exactly what has changed in the repository over its
 short history.
 
 [NOTE]
-The `\--root` flag is a flag to `git-diff-tree` to tell it to
-show the initial aka 'root' commit too. Normally you'd probably not
-want to see the initial import diff, but since the tutorial project
-was started from scratch and is so small, we use it to make the result
-a bit more interesting.
+When using the above two commands, the initial commit will be shown.
+If this is a problem because it is huge, you can hide it by setting
+the log.showroot configuration variable to false. Having this, you
+can still show it for each command just adding the `\--root` option,
+which is a flag for `git-diff-tree` accepted by both commands.
 
 With that, you should now be having some inkling of what git does, and
 can explore on your own.
index 96585ae8d9455654b63e83d61e7c34a7aeb94291..698ffde7ce844e38abe2719b2f8043783742f134 100644 (file)
@@ -15,6 +15,7 @@ DESCRIPTION
 The command takes various subcommands, and different options depending
 on the subcommand:
 
+ git bisect help
  git bisect start [<bad> [<good>...]] [--] [<paths>...]
  git bisect bad [<rev>]
  git bisect good [<rev>...]
@@ -29,6 +30,12 @@ This command uses 'git-rev-list --bisect' option to help drive the
 binary search process to find which change introduced a bug, given an
 old "good" commit object name and a later "bad" commit object name.
 
+Getting help
+~~~~~~~~~~~~
+
+Use "git bisect" to get a short usage description, and "git bisect
+help" or "git bisect -h" to get a long usage description.
+
 Basic bisect commands: start, bad, good
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
index b4ae61ff46f4b7ff9e71e9e91a999fdc8fc17560..4bb51cc06ec5e1f47b748b14353e49a0acfdc775 100644 (file)
@@ -139,6 +139,17 @@ but can be used to amend a merge commit.
        as well.  This is usually not what you want unless you
        are concluding a conflicted merge.
 
+-o|--only::
+       Make a commit only from the paths specified on the
+       command line, disregarding any contents that have been
+       staged so far. This is the default mode of operation of
+       'git commit' if any paths are given on the command line,
+       in which case this option can be omitted.
+       If this option is specified together with '--amend', then
+       no paths need be specified, which can be used to amend
+       the last commit without committing changes that have
+       already been staged.
+
 -u|--untracked-files::
        Show all untracked files, also those in uninteresting
        directories, in the "Untracked files:" section of commit
index fa161718dd33a0b4c3b58fb3898e74369bcc3d94..5de5d051b7917daabd0ef7c0681c6b75307a931a 100644 (file)
@@ -144,6 +144,8 @@ See also <<FILES>>.
        "auto".  If `stdout-is-tty` is missing, then checks the standard
        output of the command itself, and exits with status 0 if color
        is to be used, or exits with status 1 otherwise.
+       When the color setting for `name` is undefined, the command uses
+       `color.ui` as fallback.
 
 --get-color name default::
 
index 9cec8021b8c66b6bac692e2a9f14204503f7f18a..b1106714b2f7100124826819315e78f7f28325fb 100644 (file)
@@ -110,7 +110,9 @@ cvs -d ":ext;CVS_SERVER=git-cvsserver:user@server/path/repo.git" co <HEAD_name>
 ------
 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.
+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.
@@ -141,25 +143,29 @@ allowing access over SSH.
         enabled=1
 ------
 --
-3. On the client machine you need to set the following variables.
-   CVSROOT should be set as per normal, but the directory should point at the
-   appropriate git repo. For example:
+3. If you didn't specify the CVSROOT/CVS_SERVER directly in the checkout command,
+   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.
 +
 --
-For SSH access, CVS_SERVER should be set to git-cvsserver
-
-Example:
-
 ------
      export CVSROOT=:ext:user@server:/var/git/project.git
      export CVS_SERVER=git-cvsserver
 ------
 --
-4. For SSH clients that will make commits, make sure their .bashrc file
-   sets the GIT_AUTHOR and GIT_COMMITTER variables.
+4. For SSH clients that will make commits, make sure their server-side
+   .ssh/environment files (or .bashrc, etc., according to their specific shell)
+   export appropriate values for GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL,
+   GIT_COMMITTER_NAME, and GIT_COMMITTER_EMAIL.  For SSH clients whose login
+   shell is bash, .bashrc may be a reasonable alternative.
 
 5. Clients should now be able to check out the project. Use the CVS 'module'
-   name to indicate what GIT 'head' you want to check out. Example:
+   name to indicate what GIT 'head' you want to check out.  This also sets the
+   name of your newly checked-out directory, unless you tell it otherwise with
+   `-d <dir_name>`.  For example, this checks out 'master' branch to the
+   `project-master` directory:
 +
 ------
      cvs co -d project-master master
index 270df9b185a53977665c2143bdffa6f3c275d326..9a14c04e39bd6c5c41de988f7dd9d18477e92c85 100644 (file)
@@ -24,7 +24,7 @@ OPTIONS
        URL to include in the summary.
 
 <end>::
-       Commit to send at; defaults to HEAD.
+       Commit to end at; defaults to HEAD.
 
 Author
 ------
index dc36c662ae0d60b7dc706fce67a7c81849caace6..9c81b72dbebfec9b77128fb58d5aab33a143d594 100644 (file)
@@ -11,28 +11,37 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Remove files from the working tree and from the index.  The
-files have to be identical to the tip of the branch, and no
-updates to its contents must have been placed in the staging
-area (aka index).  When --cached is given, the staged content has to
-match either the tip of the branch *or* the file on disk.
+Remove files from the index, or from the working tree and the index.
+`git rm` will not remove a file from just your working directory.
+(There is no option to remove a file only from the work tree
+and yet keep it in the index; use `/bin/rm` if you want to do that.)
+The files being removed have to be identical to the tip of the branch,
+and no updates to their contents can be staged in the index,
+though that default behavior can be overridden with the `-f` option.
+When '--cached' is given, the staged content has to
+match either the tip of the branch or the file on disk,
+allowing the file to be removed from just the index.
 
 
 OPTIONS
 -------
 <file>...::
        Files to remove.  Fileglobs (e.g. `*.c`) can be given to
-       remove all matching files.  Also a leading directory name
-       (e.g. `dir` to add `dir/file1` and `dir/file2`) can be
-       given to remove all files in the directory, recursively,
-       but this requires `-r` option to be given for safety.
+       remove all matching files.  If you want git to expand
+       file glob characters, you may need to shell-escape them.
+       A leading directory name
+       (e.g. `dir` to remove `dir/file1` and `dir/file2`) can be
+       given to remove all files in the directory, and recursively
+       all sub-directories,
+       but this requires the `-r` option to be explicitly given.
 
 -f::
        Override the up-to-date check.
 
 -n, \--dry-run::
-        Don't actually remove the file(s), just show if they exist in
-        the index.
+       Don't actually remove any file(s).  Instead, just show
+       if they exist in the index and would otherwise be removed
+       by the command.
 
 -r::
         Allow recursive removal when a leading directory name is
@@ -44,9 +53,9 @@ OPTIONS
        for command-line options).
 
 \--cached::
-       This option can be used to tell the command to remove
-       the paths only from the index, leaving working tree
-       files.
+       Use this option to unstage and remove paths only from the index.
+       Working tree files, whether modified or not, will be
+       left alone.
 
 \--ignore-unmatch::
        Exit with a zero status even if no files matched.
@@ -59,11 +68,15 @@ OPTIONS
 DISCUSSION
 ----------
 
-The list of <file> given to the command can be exact pathnames,
-file glob patterns, or leading directory name.  The command
-removes only the paths that is known to git.  Giving the name of
+The <file> list given to the command can be exact pathnames,
+file glob patterns, or leading directory names.  The command
+removes only the paths that are known to git.  Giving the name of
 a file that you have not told git about does not remove that file.
 
+File globbing matches across directory boundaries.  Thus, given
+two directories `d` and `d2`, there is a difference between
+using `git rm \'d\*\'` and `git rm \'d/\*\'`, as the former will
+also remove all of directory `d2`.
 
 EXAMPLES
 --------
@@ -72,11 +85,10 @@ git-rm Documentation/\\*.txt::
        `Documentation` directory and any of its subdirectories.
 +
 Note that the asterisk `\*` is quoted from the shell in this
-example; this lets the command include the files from
-subdirectories of `Documentation/` directory.
+example; this lets git, and not the shell, expand the pathnames
+of files and subdirectories under the `Documentation/` directory.
 
 git-rm -f git-*.sh::
-       Remove all git-*.sh scripts that are in the index.
        Because this example lets the shell expand the asterisk
        (i.e. you are listing the files explicitly), it
        does not remove `subdir/git-foo.sh`.
index c7752575d8f5f35657cb9ef5a7e9e18b82ddc8b8..d7cb4c0468e713543042d41ff57a638a7fda2881 100644 (file)
@@ -8,8 +8,8 @@ git-shortlog - Summarize 'git log' output
 SYNOPSIS
 --------
 [verse]
-git-log --pretty=short | 'git-shortlog' [-h] [-n] [-s] [-e]
-git-shortlog [-n|--numbered] [-s|--summary] [-e|--email] [<committish>...]
+git-log --pretty=short | 'git-shortlog' [-h] [-n] [-s] [-e] [-w]
+git-shortlog [-n|--numbered] [-s|--summary] [-e|--email] [-w[<width>[,<indent1>[,<indent2>]]]] [<committish>...]
 
 DESCRIPTION
 -----------
@@ -35,6 +35,12 @@ OPTIONS
 -e, \--email::
        Show the email address of each author.
 
+-w[<width>[,<indent1>[,<indent2>]]]::
+       Linewrap the output by wrapping each line at `width`.  The first
+       line of each entry is indented by `indent1` spaces, and the second
+       and subsequent lines are indented by `indent2` spaces. `width`,
+       `indent1`, and `indent2` default to 76, 6 and 9 respectively.
+
 FILES
 -----
 
index 3ea269aa7a192d9f48ad2dc71f9cd790634c7852..ea4376a17f17eb2658bdf5d7faad1bd091a4de0e 100644 (file)
@@ -52,6 +52,11 @@ If the config variable `status.relativePaths` is set to false, then all
 paths shown are relative to the repository root, not to the current
 directory.
 
+If `status.submodulesummary` is set to a non zero number or true (identical
+to -1 or an unlimited number), the submodule summary will be enabled and a
+summary of commits for modified submodules will be shown (see --summary-limit
+option of linkgit:git-submodule[1]).
+
 See Also
 --------
 linkgit:gitignore[5]
index 41f9f635665b82806350c87de5117e1cfa806c1a..6ffd896fbc78b783a7e00ed462f879cbff29d758 100644 (file)
@@ -70,7 +70,7 @@ OPTIONS
 -n, --summary-limit::
        This option is only valid for the summary command.
        Limit the summary size (number of commits shown in total).
-       Giving 0 will disable the summary; a negative number means unlimted
+       Giving 0 will disable the summary; a negative number means unlimited
        (the default). This limit only applies to modified submodules. The
        size is always limited to 1 for added/deleted/typechanged submodules.
 
index c22fb71176984f40e4b549d0d492f75af85e0e1b..9712392f7946366129056ed8a0b7b8fab83c0ed5 100644 (file)
@@ -11,7 +11,7 @@ SYNOPSIS
 [verse]
 'git-tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]  <name> [<head>]
 'git-tag' -d <name>...
-'git-tag' [-n [<num>]] -l [<pattern>]
+'git-tag' [-n[<num>]] -l [<pattern>]
 'git-tag' -v <name>...
 
 DESCRIPTION
@@ -57,7 +57,7 @@ OPTIONS
 -v::
        Verify the gpg signature of the given tag names.
 
--n <num>::
+-n<num>::
        <num> specifies how many lines from the annotation, if any,
        are printed when using -l.
        The default is not to print any annotation lines.
@@ -233,14 +233,14 @@ the tag object affects, for example, the ordering of tags in the
 gitweb interface.
 
 To set the date used in future tag objects, set the environment
-variable GIT_AUTHOR_DATE to one or more of the date and time.  The
+variable GIT_COMMITTER_DATE to one or more of the date and time.  The
 date and time can be specified in a number of ways; the most common
 is "YYYY-MM-DD HH:MM".
 
 An example follows.
 
 ------------
-$ GIT_AUTHOR_DATE="2006-10-02 10:31" git tag -s v1.0.1
+$ GIT_COMMITTER_DATE="2006-10-02 10:31" git tag -s v1.0.1
 ------------
 
 
index b79be3fd4ced9dac416fb0fb7f97ab2d10775d01..3697896a06b460d9d29f962240dc46388487990a 100644 (file)
@@ -40,6 +40,9 @@ OPTIONS
        and make the best effort to recover as many objects as
        possible.
 
+--strict::
+       Don't write objects with broken content or links.
+
 
 Author
 ------
index 29edafcedac6bcb95315e7429ea56d2d283ef6f6..ed3ba83c530411801dd1cd8980cad4d005962690 100644 (file)
@@ -74,6 +74,11 @@ gitk --max-count=100 --all \-- Makefile::
        Show at most 100 changes made to the file 'Makefile'. Instead of only
        looking for changes in the current branch look in all branches.
 
+Files
+-----
+Gitk creates the .gitk file in your $HOME directory to store preferences
+such as display options, font, and colors.
+
 See Also
 --------
 'qgit(1)'::
index 8eadc2049402cc21fd80818ca9f29d15f4cd8462..b7d09c1ec69ac0e76302cef44d5f6884d05a0e0f 100644 (file)
@@ -1,5 +1,5 @@
 From: Rutger Nijlunsing <rutger@nospam.com>
-Subject: Setting up a git repository which can be pushed into and pulled from over HTTP.
+Subject: Setting up a git repository which can be pushed into and pulled from over HTTP(S).
 Date: Thu, 10 Aug 2006 22:00:26 +0200
 
 Since Apache is one of those packages people like to compile
@@ -40,9 +40,13 @@ What's needed:
 
 - have permissions to chown a directory
 
-- have git installed at the server _and_ client
+- have git installed on the client, and
 
-In effect, this probably means you're going to be root.
+- either have git installed on the server or have a webdav client on
+  the client.
+
+In effect, this means you're going to be root, or that you're using a
+preconfigured WebDAV server.
 
 
 Step 1: setup a bare GIT repository
@@ -50,9 +54,9 @@ Step 1: setup a bare GIT repository
 
 At the time of writing, git-http-push cannot remotely create a GIT
 repository. So we have to do that at the server side with git. Another
-option would be to generate an empty repository at the client and copy
-it to the server with WebDAV. But then you're probably the first to
-try that out :)
+option is to generate an empty bare repository at the client and copy
+it to the server with a WebDAV client (which is the only option if Git
+is not installed on the server).
 
 Create the directory under the DocumentRoot of the directories served
 by Apache. As an example we take /usr/local/apache2, but try "grep
@@ -169,7 +173,9 @@ On Debian:
 
    Most tests should pass.
 
-A command line tool to test WebDAV is cadaver.
+A command line tool to test WebDAV is cadaver. If you prefer GUIs, for
+example, konqueror can open WebDAV URLs as "webdav://..." or
+"webdavs://...".
 
 If you're into Windows, from XP onwards Internet Explorer supports
 WebDAV. For this, do Internet Explorer -> Open Location ->
@@ -179,8 +185,9 @@ http://<servername>/my-new-repo.git [x] Open as webfolder -> login .
 Step 3: setup the client
 ------------------------
 
-Make sure that you have HTTP support, i.e. your git was built with curl.
-The easiest way to check is to look for the executable 'git-http-push'.
+Make sure that you have HTTP support, i.e. your git was built with
+curl (version more recent than 7.10). The command 'git http-push' with
+no argument should display a usage message.
 
 Then, add the following to your $HOME/.netrc (you can do without, but will be
 asked to input your password a _lot_ of times):
@@ -197,10 +204,10 @@ instead of the server name.
 
 To check whether all is OK, do:
 
-   curl --netrc --location -v http://<username>@<servername>/my-new-repo.git/
-
-...this should give a directory listing in HTML of /var/www/my-new-repo.git .
+   curl --netrc --location -v http://<username>@<servername>/my-new-repo.git/HEAD
 
+...this should give something like 'ref: refs/heads/master', which is
+the content of the file HEAD on the server.
 
 Now, add the remote in your existing repository which contains the project
 you want to export:
@@ -225,6 +232,15 @@ want to export) to repository called 'upload', which we previously
 defined with git-config.
 
 
+Using a proxy:
+--------------
+
+If you have to access the WebDAV server from behind an HTTP(S) proxy,
+set the variable 'all_proxy' to 'http://proxy-host.com:port', or
+'http://login-on-proxy:passwd-on-proxy@proxy-host.com:port'. See 'man
+curl' for details.
+
+
 Troubleshooting:
 ----------------
 
@@ -248,9 +264,14 @@ Reading /usr/local/apache2/logs/error_log is often helpful.
 
   On Debian: Read /var/log/apache2/error.log instead.
 
+If you access HTTPS locations, git may fail verifying the SSL
+certificate (this is return code 60). Setting http.sslVerify=false can
+help diagnosing the problem, but removes security checks.
+
 
 Debian References: http://www.debian-administration.org/articles/285
 
 Authors
   Johannes Schindelin <Johannes.Schindelin@gmx.de>
   Rutger Nijlunsing <git@wingding.demon.nl>
+  Matthieu Moy <Matthieu.Moy@imag.fr>
index 0193c3ce58de4f51a164d43e68023fdf5639a920..e8bea3e18e569e702233d0bb986fc7e52266d445 100644 (file)
@@ -123,3 +123,4 @@ The placeholders are:
 - '%Creset': reset color
 - '%m': left, right or boundary mark
 - '%n': newline
+- '%x00': print a byte from a hex code
index 7c70b00b826f8f51c0b39ca2454e960b2747c403..78b773862197d46247aa73e5e38aac30edceecc2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -189,6 +189,7 @@ ETC_GITCONFIG = $(sysconfdir)/gitconfig
 
 # default configuration for gitweb
 GITWEB_CONFIG = gitweb_config.perl
+GITWEB_CONFIG_SYSTEM = /etc/gitweb.conf
 GITWEB_HOME_LINK_STR = projects
 GITWEB_SITENAME =
 GITWEB_PROJECTROOT = /pub/git
@@ -1034,6 +1035,7 @@ gitweb/gitweb.cgi: gitweb/gitweb.perl
            -e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
            -e 's|++GIT_BINDIR++|$(bindir)|g' \
            -e 's|++GITWEB_CONFIG++|$(GITWEB_CONFIG)|g' \
+           -e 's|++GITWEB_CONFIG_SYSTEM++|$(GITWEB_CONFIG_SYSTEM)|g' \
            -e 's|++GITWEB_HOME_LINK_STR++|$(GITWEB_HOME_LINK_STR)|g' \
            -e 's|++GITWEB_SITENAME++|$(GITWEB_SITENAME)|g' \
            -e 's|++GITWEB_PROJECTROOT++|$(GITWEB_PROJECTROOT)|g' \
index 30aa2e23fdbb1630dffb27db4509bc529bbd884a..4add80284e4570d1da44861e9025fa75eeb775d6 100644 (file)
@@ -17,6 +17,7 @@ static time_t archive_time;
 static int tar_umask = 002;
 static int verbose;
 static const struct commit *commit;
+static size_t base_len;
 
 /* writes out the whole block, but only if it is full */
 static void write_if_needed(void)
@@ -251,8 +252,8 @@ static int write_tar_entry(const unsigned char *sha1,
                buffer = NULL;
                size = 0;
        } else {
-               buffer = sha1_file_to_archive(path.buf, sha1, mode, &type,
-                                             &size, commit);
+               buffer = sha1_file_to_archive(path.buf + base_len, sha1, mode,
+                               &type, &size, commit);
                if (!buffer)
                        die("cannot read %s", sha1_to_hex(sha1));
        }
@@ -272,6 +273,7 @@ int write_tar_archive(struct archiver_args *args)
        archive_time = args->time;
        verbose = args->verbose;
        commit = args->commit;
+       base_len = args->base ? strlen(args->base) : 0;
 
        if (args->commit_sha1)
                write_global_extended_header(args->commit_sha1);
index 74e30f6205f41112dc2bafe9371a790aca55f70c..18c0f8710c6150e3b0211d311a70bf4b34608370 100644 (file)
@@ -13,6 +13,7 @@ static int verbose;
 static int zip_date;
 static int zip_time;
 static const struct commit *commit;
+static size_t base_len;
 
 static unsigned char *zip_dir;
 static unsigned int zip_dir_size;
@@ -197,8 +198,8 @@ static int write_zip_entry(const unsigned char *sha1,
                if (S_ISREG(mode) && zlib_compression_level != 0)
                        method = 8;
                result = 0;
-               buffer = sha1_file_to_archive(path, sha1, mode, &type, &size,
-                                             commit);
+               buffer = sha1_file_to_archive(path + base_len, sha1, mode,
+                               &type, &size, commit);
                if (!buffer)
                        die("cannot read %s", sha1_to_hex(sha1));
                crc = crc32(crc, buffer, size);
@@ -321,6 +322,7 @@ int write_zip_archive(struct archiver_args *args)
        zip_dir_size = ZIP_DIRECTORY_MIN_SIZE;
        verbose = args->verbose;
        commit = args->commit;
+       base_len = args->base ? strlen(args->base) : 0;
 
        if (args->base && plen > 0 && args->base[plen - 1] == '/') {
                char *base = xstrdup(args->base);
index abe73a0f8194e95c2a10a27c2007560e6d57f3d5..caa3f2aa0ca147091d28013c3d2c11346e350675 100644 (file)
@@ -2981,12 +2981,8 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
 
 static int git_apply_config(const char *var, const char *value)
 {
-       if (!strcmp(var, "apply.whitespace")) {
-               if (!value)
-                       return config_error_nonbool(var);
-               apply_default_whitespace = xstrdup(value);
-               return 0;
-       }
+       if (!strcmp(var, "apply.whitespace"))
+               return git_config_string(&apply_default_whitespace, var, value);
        return git_default_config(var, value);
 }
 
@@ -3121,7 +3117,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
 
                fd = open(arg, O_RDONLY);
                if (fd < 0)
-                       usage(apply_usage);
+                       die("can't open patch '%s': %s", arg, strerror(errno));
                read_stdin = 0;
                set_default_whitespace_mode(whitespace_option);
                errs |= apply_patch(fd, arg, inaccurate_eof);
index fefec3010c434219234e7832051ada9ed2e52335..6778a03ae4c901d216e4b91cd41f2073e0e98589 100644 (file)
@@ -95,7 +95,8 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
 
        for (i = 0; i < dir.nr; i++) {
                struct dir_entry *ent = dir.entries[i];
-               int len, pos, matches;
+               int len, pos;
+               int matches = 0;
                struct cache_entry *ce;
                struct stat st;
 
@@ -127,18 +128,18 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
 
                if (pathspec) {
                        memset(seen, 0, argc > 0 ? argc : 1);
-                       matches = match_pathspec(pathspec, ent->name, ent->len,
+                       matches = match_pathspec(pathspec, ent->name, len,
                                                 baselen, seen);
-               } else {
-                       matches = 0;
                }
 
                if (S_ISDIR(st.st_mode)) {
                        strbuf_addstr(&directory, ent->name);
                        qname = quote_path_relative(directory.buf, directory.len, &buf, prefix);
-                       if (show_only && (remove_directories || matches)) {
+                       if (show_only && (remove_directories ||
+                           (matches == MATCHED_EXACTLY))) {
                                printf("Would remove %s\n", qname);
-                       } else if (remove_directories || matches) {
+                       } else if (remove_directories ||
+                                  (matches == MATCHED_EXACTLY)) {
                                if (!quiet)
                                        printf("Removing %s\n", qname);
                                if (remove_dir_recursively(&directory, 0) != 0) {
index 660a3458f7f4ef24dfa4fd5bdf902174da1eefb4..b41d4a3561d6fd4376c1520c3b7dd436674e8325 100644 (file)
@@ -98,7 +98,7 @@ static struct option builtin_commit_options[] = {
        OPT_BOOLEAN('a', "all", &all, "commit all changed files"),
        OPT_BOOLEAN('i', "include", &also, "add specified files to index for commit"),
        OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"),
-       OPT_BOOLEAN('o', "only", &only, ""),
+       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(0, "untracked-files", &untracked_files, "show all untracked files"),
@@ -745,10 +745,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
                die("No paths with --include/--only does not make sense.");
        if (argc == 0 && only && amend)
                only_include_assumed = "Clever... amending the last one with dirty index.";
-       if (argc > 0 && !also && !only) {
+       if (argc > 0 && !also && !only)
                only_include_assumed = "Explicit paths specified without -i nor -o; assuming --only paths...";
-               also = 0;
-       }
        if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
                cleanup_mode = use_editor ? CLEANUP_ALL : CLEANUP_SPACE;
        else if (!strcmp(cleanup_arg, "verbatim"))
@@ -810,7 +808,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1)
 
        rev.verbose_header = 1;
        rev.show_root_diff = 1;
-       rev.commit_format = get_commit_format("format:%h: %s");
+       get_commit_format("format:%h: %s", &rev);
        rev.always_show_header = 0;
        rev.diffopt.detect_rename = 1;
        rev.diffopt.rename_limit = 100;
index c34bc8b6a6957ccee1db23a3c44c99e058384689..8ee01bdecde1ede4062a630761ce56f3366f3a14 100644 (file)
@@ -3,7 +3,7 @@
 #include "color.h"
 
 static const char git_config_set_usage[] =
-"git-config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty]";
+"git-config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int | --bool-or-int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty]";
 
 static char *key;
 static regex_t *key_regexp;
@@ -16,7 +16,7 @@ static int seen;
 static char delim = '=';
 static char key_delim = ' ';
 static char term = '\n';
-static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;
+static enum { T_RAW, T_INT, T_BOOL, T_BOOL_OR_INT } type = T_RAW;
 
 static int show_all_config(const char *key_, const char *value_)
 {
@@ -53,6 +53,14 @@ static int show_config(const char* key_, const char* value_)
                sprintf(value, "%d", git_config_int(key_, value_?value_:""));
        else if (type == T_BOOL)
                vptr = git_config_bool(key_, value_) ? "true" : "false";
+       else if (type == T_BOOL_OR_INT) {
+               int is_bool, v;
+               v = git_config_bool_or_int(key_, value_, &is_bool);
+               if (is_bool)
+                       vptr = v ? "true" : "false";
+               else
+                       sprintf(value, "%d", v);
+       }
        else
                vptr = value_?value_:"";
        seen++;
@@ -157,6 +165,14 @@ char *normalize_value(const char *key, const char *value)
                else if (type == T_BOOL)
                        sprintf(normalized, "%s",
                                git_config_bool(key, value) ? "true" : "false");
+               else if (type == T_BOOL_OR_INT) {
+                       int is_bool, v;
+                       v = git_config_bool_or_int(key, value, &is_bool);
+                       if (!is_bool)
+                               sprintf(normalized, "%d", v);
+                       else
+                               sprintf(normalized, "%s", v ? "true" : "false");
+               }
        }
 
        return normalized;
@@ -224,6 +240,10 @@ static int git_get_colorbool_config(const char *var, const char *value)
                get_diff_color_found =
                        git_config_colorbool(var, value, stdout_is_tty);
        }
+       if (!strcmp(var, "color.ui")) {
+               git_use_color_default = git_config_colorbool(var, value, stdout_is_tty);
+               return 0;
+       }
        return 0;
 }
 
@@ -251,7 +271,7 @@ static int get_colorbool(int argc, const char **argv)
                if (!strcmp(get_color_slot, "color.diff"))
                        get_colorbool_found = get_diff_color_found;
                if (get_colorbool_found < 0)
-                       get_colorbool_found = 0;
+                       get_colorbool_found = git_use_color_default;
        }
 
        if (argc == 1) {
@@ -273,6 +293,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                        type = T_INT;
                else if (!strcmp(argv[1], "--bool"))
                        type = T_BOOL;
+               else if (!strcmp(argv[1], "--bool-or-int"))
+                       type = T_BOOL_OR_INT;
                else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) {
                        if (argc != 2)
                                usage(git_config_set_usage);
index 5841b3e51a5c908a32761398d6237968ddac4d46..139a6b10c50d38fa3caf224e8031a152eac1a22e 100644 (file)
@@ -215,13 +215,6 @@ static int update_local_ref(struct ref *ref,
        if (type < 0)
                die("object %s not found", sha1_to_hex(ref->new_sha1));
 
-       if (!*ref->name) {
-               /* Not storing */
-               if (verbose)
-                       sprintf(display, "* branch %s -> FETCH_HEAD", remote);
-               return 0;
-       }
-
        if (!hashcmp(ref->old_sha1, ref->new_sha1)) {
                if (verbose)
                        sprintf(display, "= %-*s %-*s -> %s", SUMMARY_WIDTH,
@@ -365,16 +358,21 @@ static int store_updated_refs(const char *url, struct ref *ref_map)
                        rm->merge ? "" : "not-for-merge",
                        note);
 
-               if (ref) {
+               if (ref)
                        update_local_ref(ref, what, verbose, note);
-                       if (*note) {
-                               if (!shown_url) {
-                                       fprintf(stderr, "From %.*s\n",
-                                                       url_len, url);
-                                       shown_url = 1;
-                               }
-                               fprintf(stderr, " %s\n", note);
+               else if (verbose)
+                       sprintf(note, "* %-*s %-*s -> FETCH_HEAD",
+                               SUMMARY_WIDTH, *kind ? kind : "branch",
+                                REFCOL_WIDTH, *what ? what : "HEAD");
+               else
+                       *note = '\0';
+               if (*note) {
+                       if (!shown_url) {
+                               fprintf(stderr, "From %.*s\n",
+                                               url_len, url);
+                               shown_url = 1;
                        }
+                       fprintf(stderr, " %s\n", note);
                }
        }
        fclose(fp);
index ebb3f37cf158dc479f364111893279805fa9a230..7077d524776e748e0add4ff85478cd62512add15 100644 (file)
@@ -201,6 +201,15 @@ static void shortlog(const char *name, unsigned char *sha1,
                        continue;
 
                bol = strstr(commit->buffer, "\n\n");
+               if (bol) {
+                       unsigned char c;
+                       do {
+                               c = *++bol;
+                       } while (isspace(c));
+                       if (!c)
+                               bol = NULL;
+               }
+
                if (!bol) {
                        append_to_list(&subjects, xstrdup(sha1_to_hex(
                                                        commit->object.sha1)),
@@ -208,7 +217,6 @@ static void shortlog(const char *name, unsigned char *sha1,
                        continue;
                }
 
-               bol += 2;
                eol = strchr(bol, '\n');
                if (eol) {
                        oneline = xmemdupz(bol, eol - bol);
index 5c00725f030460ba34c702b9ad31e577ca70d361..1670d0b334efe7d01cbf0118f7b9dca874f8d473 100644 (file)
@@ -56,7 +56,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
        rev->abbrev = DEFAULT_ABBREV;
        rev->commit_format = CMIT_FMT_DEFAULT;
        if (fmt_pretty)
-               rev->commit_format = get_commit_format(fmt_pretty);
+               get_commit_format(fmt_pretty, rev);
        rev->verbose_header = 1;
        DIFF_OPT_SET(&rev->diffopt, RECURSIVE);
        rev->show_root_diff = default_show_root;
@@ -400,6 +400,7 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
         * allow us to set a different default.
         */
        rev.commit_format = CMIT_FMT_ONELINE;
+       rev.use_terminator = 1;
        rev.always_show_header = 1;
 
        /*
index d77f10a0eaa64466b919bcede37ad8c67b70b3fc..a3ee1ac3937b179799fbaa048927c4c8a9963cc9 100644 (file)
@@ -19,6 +19,8 @@ static const char * const builtin_remote_usage[] = {
 
 static int verbose;
 
+static int show_all(void);
+
 static inline int postfixcmp(const char *string, const char *postfix)
 {
        int len1 = strlen(string), len2 = strlen(postfix);
@@ -88,18 +90,22 @@ static int add(int argc, const char **argv)
        strbuf_init(&buf, 0);
        strbuf_init(&buf2, 0);
 
+       strbuf_addf(&buf2, "refs/heads/test:refs/remotes/%s/test", name);
+       if (!valid_fetch_refspec(buf2.buf))
+               die("'%s' is not a valid remote name", name);
+
        strbuf_addf(&buf, "remote.%s.url", name);
        if (git_config_set(buf.buf, url))
                return 1;
 
+       strbuf_reset(&buf);
+       strbuf_addf(&buf, "remote.%s.fetch", name);
+
        if (track.nr == 0)
                path_list_append("*", &track);
        for (i = 0; i < track.nr; i++) {
                struct path_list_item *item = track.items + i;
 
-               strbuf_reset(&buf);
-               strbuf_addf(&buf, "remote.%s.fetch", name);
-
                strbuf_reset(&buf2);
                if (mirror)
                        strbuf_addf(&buf2, "refs/%s:refs/%s",
@@ -380,8 +386,11 @@ static int show_or_prune(int argc, const char **argv, int prune)
 
        argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
 
-       if (argc < 1)
+       if (argc < 1) {
+               if (!prune)
+                       return show_all();
                usage_with_options(builtin_remote_usage, options);
+       }
 
        memset(&states, 0, sizeof(states));
        for (; argc; argc--, argv++) {
index bd795b1db7a4054a0218d1ec96794ad25d656896..e6a2865019cceadfcbfc8575a2bd1f97b7159dcb 100644 (file)
@@ -9,7 +9,7 @@
 #include "shortlog.h"
 
 static const char shortlog_usage[] =
-"git-shortlog [-n] [-s] [-e] [<commit-id>... ]";
+"git-shortlog [-n] [-s] [-e] [-w] [<commit-id>... ]";
 
 static int compare_by_number(const void *a1, const void *a2)
 {
index 8dd959fe1c74507023f8e82c7f4682c1588ebac6..129ff57f11d2cdfdacc6be9685736ada07caef7f 100644 (file)
@@ -16,7 +16,7 @@
 static const char * const git_tag_usage[] = {
        "git-tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]",
        "git-tag -d <tagname>...",
-       "git-tag -l [-n [<num>]] [<pattern>]",
+       "git-tag -l [-n[<num>]] [<pattern>]",
        "git-tag -v <tagname>...",
        NULL
 };
index 50e07faa12f495b3270e1446573b88a255336877..fecf0be7796f34fbb06a6bbbe61e9e3d042f6780 100644 (file)
@@ -7,11 +7,13 @@
 #include "commit.h"
 #include "tag.h"
 #include "tree.h"
+#include "tree-walk.h"
 #include "progress.h"
 #include "decorate.h"
+#include "fsck.h"
 
-static int dry_run, quiet, recover, has_errors;
-static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] < pack-file";
+static int dry_run, quiet, recover, has_errors, strict;
+static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] [--strict] < pack-file";
 
 /* We always read in 4kB chunks. */
 static unsigned char buffer[4096];
@@ -19,6 +21,11 @@ static unsigned int offset, len;
 static off_t consumed_bytes;
 static SHA_CTX ctx;
 
+/*
+ * When running under --strict mode, objects whose reachability are
+ * suspect are kept in core without getting written in the object
+ * store.
+ */
 struct obj_buffer {
        char *buffer;
        unsigned long size;
@@ -31,6 +38,16 @@ static struct obj_buffer *lookup_object_buffer(struct object *base)
        return lookup_decoration(&obj_decorate, base);
 }
 
+static void add_object_buffer(struct object *object, char *buffer, unsigned long size)
+{
+       struct obj_buffer *obj;
+       obj = xcalloc(1, sizeof(struct obj_buffer));
+       obj->buffer = buffer;
+       obj->size = size;
+       if (add_decoration(&obj_decorate, object, obj))
+               die("object %s tried to add buffer twice!", sha1_to_hex(object->sha1));
+}
+
 /*
  * Make sure at least "min" bytes are available in the buffer, and
  * return the pointer to the buffer.
@@ -134,19 +151,110 @@ static void add_delta_to_list(unsigned nr, unsigned const char *base_sha1,
 struct obj_info {
        off_t offset;
        unsigned char sha1[20];
+       struct object *obj;
 };
 
+#define FLAG_OPEN (1u<<20)
+#define FLAG_WRITTEN (1u<<21)
+
 static struct obj_info *obj_list;
+unsigned nr_objects;
+
+/*
+ * Called only from check_object() after it verified this object
+ * is Ok.
+ */
+static void write_cached_object(struct object *obj)
+{
+       unsigned char sha1[20];
+       struct obj_buffer *obj_buf = lookup_object_buffer(obj);
+       if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), sha1) < 0)
+               die("failed to write object %s", sha1_to_hex(obj->sha1));
+       obj->flags |= FLAG_WRITTEN;
+}
+
+/*
+ * At the very end of the processing, write_rest() scans the objects
+ * that have reachability requirements and calls this function.
+ * Verify its reachability and validity recursively and write it out.
+ */
+static int check_object(struct object *obj, int type, void *data)
+{
+       if (!obj)
+               return 0;
+
+       if (obj->flags & FLAG_WRITTEN)
+               return 1;
+
+       if (type != OBJ_ANY && obj->type != type)
+               die("object type mismatch");
+
+       if (!(obj->flags & FLAG_OPEN)) {
+               unsigned long size;
+               int type = sha1_object_info(obj->sha1, &size);
+               if (type != obj->type || type <= 0)
+                       die("object of unexpected type");
+               obj->flags |= FLAG_WRITTEN;
+               return 1;
+       }
+
+       if (fsck_object(obj, 1, fsck_error_function))
+               die("Error in object");
+       if (!fsck_walk(obj, check_object, 0))
+               die("Error on reachable objects of %s", sha1_to_hex(obj->sha1));
+       write_cached_object(obj);
+       return 1;
+}
+
+static void write_rest(void)
+{
+       unsigned i;
+       for (i = 0; i < nr_objects; i++)
+               check_object(obj_list[i].obj, OBJ_ANY, 0);
+}
 
 static void added_object(unsigned nr, enum object_type type,
                         void *data, unsigned long size);
 
+/*
+ * Write out nr-th object from the list, now we know the contents
+ * of it.  Under --strict, this buffers structured objects in-core,
+ * to be checked at the end.
+ */
 static void write_object(unsigned nr, enum object_type type,
                         void *buf, unsigned long size)
 {
-       if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
-               die("failed to write object");
-       added_object(nr, type, buf, size);
+       if (!strict) {
+               if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
+                       die("failed to write object");
+               added_object(nr, type, buf, size);
+               free(buf);
+               obj_list[nr].obj = NULL;
+       } else if (type == OBJ_BLOB) {
+               struct blob *blob;
+               if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0)
+                       die("failed to write object");
+               added_object(nr, type, buf, size);
+               free(buf);
+
+               blob = lookup_blob(obj_list[nr].sha1);
+               if (blob)
+                       blob->object.flags |= FLAG_WRITTEN;
+               else
+                       die("invalid blob object");
+               obj_list[nr].obj = NULL;
+       } else {
+               struct object *obj;
+               int eaten;
+               hash_sha1_file(buf, size, typename(type), obj_list[nr].sha1);
+               added_object(nr, type, buf, size);
+               obj = parse_object_buffer(obj_list[nr].sha1, type, size, buf, &eaten);
+               if (!obj)
+                       die("invalid %s", typename(type));
+               add_object_buffer(obj, buf, size);
+               obj->flags |= FLAG_OPEN;
+               obj_list[nr].obj = obj;
+       }
 }
 
 static void resolve_delta(unsigned nr, enum object_type type,
@@ -163,9 +271,12 @@ static void resolve_delta(unsigned nr, enum object_type type,
                die("failed to apply delta");
        free(delta);
        write_object(nr, type, result, result_size);
-       free(result);
 }
 
+/*
+ * We now know the contents of an object (which is nr-th in the pack);
+ * resolve all the deltified objects that are based on it.
+ */
 static void added_object(unsigned nr, enum object_type type,
                         void *data, unsigned long size)
 {
@@ -193,7 +304,24 @@ static void unpack_non_delta_entry(enum object_type type, unsigned long size,
 
        if (!dry_run && buf)
                write_object(nr, type, buf, size);
-       free(buf);
+       else
+               free(buf);
+}
+
+static int resolve_against_held(unsigned nr, const unsigned char *base,
+                               void *delta_data, unsigned long delta_size)
+{
+       struct object *obj;
+       struct obj_buffer *obj_buffer;
+       obj = lookup_object(base);
+       if (!obj)
+               return 0;
+       obj_buffer = lookup_object_buffer(obj);
+       if (!obj_buffer)
+               return 0;
+       resolve_delta(nr, obj->type, obj_buffer->buffer,
+                     obj_buffer->size, delta_data, delta_size);
+       return 1;
 }
 
 static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
@@ -202,7 +330,6 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
        void *delta_data, *base;
        unsigned long base_size;
        unsigned char base_sha1[20];
-       struct object *obj;
 
        if (type == OBJ_REF_DELTA) {
                hashcpy(base_sha1, fill(20));
@@ -212,7 +339,13 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
                        free(delta_data);
                        return;
                }
-               if (!has_sha1_file(base_sha1)) {
+               if (has_sha1_file(base_sha1))
+                       ; /* Ok we have this one */
+               else if (resolve_against_held(nr, base_sha1,
+                                             delta_data, delta_size))
+                       return; /* we are done */
+               else {
+                       /* cannot resolve yet --- queue it */
                        hashcpy(obj_list[nr].sha1, null_sha1);
                        add_delta_to_list(nr, base_sha1, 0, delta_data, delta_size);
                        return;
@@ -258,22 +391,18 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
                        }
                }
                if (!base_found) {
-                       /* The delta base object is itself a delta that
-                          has not been resolved yet. */
+                       /*
+                        * The delta base object is itself a delta that
+                        * has not been resolved yet.
+                        */
                        hashcpy(obj_list[nr].sha1, null_sha1);
                        add_delta_to_list(nr, null_sha1, base_offset, delta_data, delta_size);
                        return;
                }
        }
 
-       obj = lookup_object(base_sha1);
-       if (obj) {
-               struct obj_buffer *obj_buf = lookup_object_buffer(obj);
-               if (obj_buf) {
-                       resolve_delta(nr, obj->type, obj_buf->buffer, obj_buf->size, delta_data, delta_size);
-                       return;
-               }
-       }
+       if (resolve_against_held(nr, base_sha1, delta_data, delta_size))
+               return;
 
        base = read_sha1_file(base_sha1, &type, &base_size);
        if (!base) {
@@ -336,7 +465,8 @@ static void unpack_all(void)
        int i;
        struct progress *progress = NULL;
        struct pack_header *hdr = fill(sizeof(struct pack_header));
-       unsigned nr_objects = ntohl(hdr->hdr_entries);
+
+       nr_objects = ntohl(hdr->hdr_entries);
 
        if (ntohl(hdr->hdr_signature) != PACK_SIGNATURE)
                die("bad pack file");
@@ -347,6 +477,7 @@ static void unpack_all(void)
        if (!quiet)
                progress = start_progress("Unpacking objects", nr_objects);
        obj_list = xmalloc(nr_objects * sizeof(*obj_list));
+       memset(obj_list, 0, nr_objects * sizeof(*obj_list));
        for (i = 0; i < nr_objects; i++) {
                unpack_one(i);
                display_progress(progress, i + 1);
@@ -382,6 +513,10 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
                                recover = 1;
                                continue;
                        }
+                       if (!strcmp(arg, "--strict")) {
+                               strict = 1;
+                               continue;
+                       }
                        if (!prefixcmp(arg, "--pack_header=")) {
                                struct pack_header *hdr;
                                char *c;
@@ -407,6 +542,8 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
        unpack_all();
        SHA1_Update(&ctx, buffer, offset);
        SHA1_Final(sha1, &ctx);
+       if (strict)
+               write_rest();
        if (hashcmp(fill(20), sha1))
                die("final sha1 did not match");
        use(20);
diff --git a/cache.h b/cache.h
index 2a1e7ec6b2bf712af80813936b5aed434d02090e..50b28fad0126d14d012769d5e8b95eb9ab6853d3 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -692,6 +692,7 @@ extern int git_parse_long(const char *, long *);
 extern int git_parse_ulong(const char *, unsigned long *);
 extern int git_config_int(const char *, const char *);
 extern unsigned long git_config_ulong(const char *, const char *);
+extern int git_config_bool_or_int(const char *, const char *, int *);
 extern int git_config_bool(const char *, const char *);
 extern int git_config_string(const char **, const char *, const char *);
 extern int git_config_set(const char *, const char *);
index 2f63bc8b2fac0d748e13d4435d550d61002092b3..2d94d4148ed4048469ba79cae4f6ff2a2e3f9bca 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -63,7 +63,8 @@ enum cmit_fmt {
 };
 
 extern int non_ascii(int);
-extern enum cmit_fmt get_commit_format(const char *arg);
+struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
+extern void get_commit_format(const char *arg, struct rev_info *);
 extern void format_commit_message(const struct commit *commit,
                                   const void *format, struct strbuf *sb);
 extern void pretty_print_commit(enum cmit_fmt fmt, const struct commit*,
index 062449459e1a4cfc2a605c065ed281669e0e7452..b0ada515b9d839fc8691bc9af320353ff323b251 100644 (file)
--- a/config.c
+++ b/config.c
@@ -303,8 +303,9 @@ unsigned long git_config_ulong(const char *name, const char *value)
        return ret;
 }
 
-int git_config_bool(const char *name, const char *value)
+int git_config_bool_or_int(const char *name, const char *value, int *is_bool)
 {
+       *is_bool = 1;
        if (!value)
                return 1;
        if (!*value)
@@ -313,7 +314,14 @@ int git_config_bool(const char *name, const char *value)
                return 1;
        if (!strcasecmp(value, "false") || !strcasecmp(value, "no"))
                return 0;
-       return git_config_int(name, value) != 0;
+       *is_bool = 0;
+       return git_config_int(name, value);
+}
+
+int git_config_bool(const char *name, const char *value)
+{
+       int discard;
+       return !!git_config_bool_or_int(name, value, &discard);
 }
 
 int git_config_string(const char **dest, const char *var, const char *value)
index 31941bcbbf457fe02097f8c46d25f1f9fc7c4f9f..1369a5ec45349c1ef04e4df2d7d7d4dd28cd3596 100644 (file)
@@ -112,8 +112,8 @@ static int basename_same(struct diff_filespec *src, struct diff_filespec *dst)
 struct diff_score {
        int src; /* index in rename_src */
        int dst; /* index in rename_dst */
-       int score;
-       int name_score;
+       unsigned short score;
+       short name_score;
 };
 
 static int estimate_similarity(struct diff_filespec *src,
@@ -223,6 +223,12 @@ static int score_compare(const void *a_, const void *b_)
 {
        const struct diff_score *a = a_, *b = b_;
 
+       /* sink the unused ones to the bottom */
+       if (a->dst < 0)
+               return (0 <= b->dst);
+       else if (b->dst < 0)
+               return -1;
+
        if (a->score == b->score)
                return b->name_score - a->name_score;
 
@@ -387,6 +393,22 @@ static int find_exact_renames(void)
        return i;
 }
 
+#define NUM_CANDIDATE_PER_DST 4
+static void record_if_better(struct diff_score m[], struct diff_score *o)
+{
+       int i, worst;
+
+       /* find the worst one */
+       worst = 0;
+       for (i = 1; i < NUM_CANDIDATE_PER_DST; i++)
+               if (score_compare(&m[i], &m[worst]) > 0)
+                       worst = i;
+
+       /* is it better than the worst one? */
+       if (score_compare(&m[worst], o) > 0)
+               m[worst] = *o;
+}
+
 void diffcore_rename(struct diff_options *options)
 {
        int detect_rename = options->detect_rename;
@@ -474,47 +496,61 @@ void diffcore_rename(struct diff_options *options)
                goto cleanup;
        }
 
-       mx = xmalloc(sizeof(*mx) * num_create * num_src);
+       mx = xcalloc(num_create * NUM_CANDIDATE_PER_DST, sizeof(*mx));
        for (dst_cnt = i = 0; i < rename_dst_nr; i++) {
-               int base = dst_cnt * num_src;
                struct diff_filespec *two = rename_dst[i].two;
+               struct diff_score *m;
+
                if (rename_dst[i].pair)
                        continue; /* dealt with exact match already. */
+
+               m = &mx[dst_cnt * NUM_CANDIDATE_PER_DST];
+               for (j = 0; j < NUM_CANDIDATE_PER_DST; j++)
+                       m[j].dst = -1;
+
                for (j = 0; j < rename_src_nr; j++) {
                        struct diff_filespec *one = rename_src[j].one;
-                       struct diff_score *m = &mx[base+j];
-                       m->src = j;
-                       m->dst = i;
-                       m->score = estimate_similarity(one, two,
-                                                      minimum_score);
-                       m->name_score = basename_same(one, two);
+                       struct diff_score this_src;
+                       this_src.score = estimate_similarity(one, two,
+                                                            minimum_score);
+                       this_src.name_score = basename_same(one, two);
+                       this_src.dst = i;
+                       this_src.src = j;
+                       record_if_better(m, &this_src);
                        diff_free_filespec_blob(one);
                }
                /* We do not need the text anymore */
                diff_free_filespec_blob(two);
                dst_cnt++;
        }
+
        /* cost matrix sorted by most to least similar pair */
-       qsort(mx, num_create * num_src, sizeof(*mx), score_compare);
-       for (i = 0; i < num_create * num_src; i++) {
-               struct diff_rename_dst *dst = &rename_dst[mx[i].dst];
-               struct diff_filespec *src;
+       qsort(mx, dst_cnt * NUM_CANDIDATE_PER_DST, sizeof(*mx), score_compare);
+
+       for (i = 0; i < dst_cnt * NUM_CANDIDATE_PER_DST; i++) {
+               struct diff_rename_dst *dst;
+
+               if ((mx[i].dst < 0) ||
+                   (mx[i].score < minimum_score))
+                       break; /* there is no more usable pair. */
+               dst = &rename_dst[mx[i].dst];
                if (dst->pair)
                        continue; /* already done, either exact or fuzzy. */
-               if (mx[i].score < minimum_score)
-                       break; /* there is no more usable pair. */
-               src = rename_src[mx[i].src].one;
-               if (src->rename_used)
+               if (rename_src[mx[i].src].one->rename_used)
                        continue;
                record_rename_pair(mx[i].dst, mx[i].src, mx[i].score);
                rename_count++;
        }
-       for (i = 0; i < num_create * num_src; i++) {
-               struct diff_rename_dst *dst = &rename_dst[mx[i].dst];
+
+       for (i = 0; i < dst_cnt * NUM_CANDIDATE_PER_DST; i++) {
+               struct diff_rename_dst *dst;
+
+               if ((mx[i].dst < 0) ||
+                   (mx[i].score < minimum_score))
+                       break; /* there is no more usable pair. */
+               dst = &rename_dst[mx[i].dst];
                if (dst->pair)
                        continue; /* already done, either exact or fuzzy. */
-               if (mx[i].score < minimum_score)
-                       break; /* there is no more usable pair. */
                record_rename_pair(mx[i].dst, mx[i].src, mx[i].score);
                rename_count++;
        }
diff --git a/dir.c b/dir.c
index edc458e020772a7ab704e9cf69786d3aa641bcd4..d79762c7c0bc9e762ed8dc5f00fb2fd3ce01ad57 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -80,7 +80,7 @@ static int match_one(const char *match, const char *name, int namelen)
        if (strncmp(match, name, matchlen))
                return !fnmatch(match, name, 0) ? MATCHED_FNMATCH : 0;
 
-       if (!name[matchlen])
+       if (namelen == matchlen)
                return MATCHED_EXACTLY;
        if (match[matchlen-1] == '/' || name[matchlen] == '/')
                return MATCHED_RECURSIVELY;
index a0a81f134a6288dfc1d87431698f29597ed5e488..903953e68e98535e754b5a5dd6ba22eb6074ef20 100755 (executable)
@@ -550,6 +550,21 @@ sub parse_diff {
        return @hunk;
 }
 
+sub parse_diff_header {
+       my $src = shift;
+
+       my $head = { TEXT => [], DISPLAY => [] };
+       my $mode = { TEXT => [], DISPLAY => [] };
+
+       for (my $i = 0; $i < @{$src->{TEXT}}; $i++) {
+               my $dest = $src->{TEXT}->[$i] =~ /^(old|new) mode (\d+)$/ ?
+                       $mode : $head;
+               push @{$dest->{TEXT}}, $src->{TEXT}->[$i];
+               push @{$dest->{DISPLAY}}, $src->{DISPLAY}->[$i];
+       }
+       return ($head, $mode);
+}
+
 sub hunk_splittable {
        my ($text) = @_;
 
@@ -795,9 +810,40 @@ sub patch_update_file {
        my ($ix, $num);
        my $path = shift;
        my ($head, @hunk) = parse_diff($path);
+       ($head, my $mode) = parse_diff_header($head);
        for (@{$head->{DISPLAY}}) {
                print;
        }
+
+       if (@{$mode->{TEXT}}) {
+               while (1) {
+                       print @{$mode->{DISPLAY}};
+                       print colored $prompt_color,
+                               "Stage mode change [y/n/a/d/?]? ";
+                       my $line = <STDIN>;
+                       if ($line =~ /^y/i) {
+                               $mode->{USE} = 1;
+                               last;
+                       }
+                       elsif ($line =~ /^n/i) {
+                               $mode->{USE} = 0;
+                               last;
+                       }
+                       elsif ($line =~ /^a/i) {
+                               $_->{USE} = 1 foreach ($mode, @hunk);
+                               last;
+                       }
+                       elsif ($line =~ /^d/i) {
+                               $_->{USE} = 0 foreach ($mode, @hunk);
+                               last;
+                       }
+                       else {
+                               help_patch_cmd('');
+                               next;
+                       }
+               }
+       }
+
        $num = scalar @hunk;
        $ix = 0;
 
@@ -920,6 +966,9 @@ sub patch_update_file {
 
        my $n_lofs = 0;
        my @result = ();
+       if ($mode->{USE}) {
+               push @result, @{$mode->{TEXT}};
+       }
        for (@hunk) {
                my $text = $_->{TEXT};
                my ($o_ofs, $o_cnt, $n_ofs, $n_cnt) =
index ac5c388060789e559f80d61d6eae1db926b66ad4..75886a8f2fb0c2244ba921398ae2339dc9ffea26 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -107,7 +107,7 @@ It does not apply to blobs recorded in its index."
     # patch did not touch, so recursive ends up canceling them,
     # saying that we reverted all those changes.
 
-    eval GITHEAD_$his_tree='"$SUBJECT"'
+    eval GITHEAD_$his_tree='"$FIRSTLINE"'
     export GITHEAD_$his_tree
     git-merge-recursive $orig_tree -- HEAD $his_tree || {
            git rerere
@@ -117,10 +117,6 @@ It does not apply to blobs recorded in its index."
     unset GITHEAD_$his_tree
 }
 
-reread_subject () {
-       git stripspace <"$1" | sed -e 1q
-}
-
 prec=4
 dotest=".dotest"
 sign= utf8=t keep= skip= interactive= resolved= binary= rebasing=
@@ -331,7 +327,20 @@ do
                        echo "Patch is empty.  Was it split wrong?"
                        stop_here $this
                }
-               git stripspace < "$dotest/msg" > "$dotest/msg-clean"
+               if test -f "$dotest/rebasing" &&
+                       commit=$(sed -e 's/^From \([0-9a-f]*\) .*/\1/' \
+                               -e q "$dotest/$msgnum") &&
+                       test "$(git cat-file -t "$commit")" = commit
+               then
+                       git cat-file commit "$commit" |
+                       sed -e '1,/^$/d' >"$dotest/msg-clean"
+               else
+                       SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")"
+                       case "$keep_subject" in -k)  SUBJECT="[PATCH] $SUBJECT" ;; esac
+
+                       (printf '%s\n\n' "$SUBJECT"; cat "$dotest/msg") |
+                               git stripspace > "$dotest/msg-clean"
+               fi
                ;;
        esac
 
@@ -347,9 +356,6 @@ do
 
        export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
 
-       SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")"
-       case "$keep_subject" in -k)  SUBJECT="[PATCH] $SUBJECT" ;; esac
-
        case "$resume" in
        '')
            if test '' != "$SIGNOFF"
@@ -368,10 +374,8 @@ do
                ADD_SIGNOFF=
            fi
            {
-               printf '%s\n' "$SUBJECT"
                if test -s "$dotest/msg-clean"
                then
-                       echo
                        cat "$dotest/msg-clean"
                fi
                if test '' != "$ADD_SIGNOFF"
@@ -408,7 +412,6 @@ do
                [aA]*) action=yes interactive= ;;
                [nN]*) action=skip ;;
                [eE]*) git_editor "$dotest/final-commit"
-                      SUBJECT=$(reread_subject "$dotest/final-commit")
                       action=again ;;
                [vV]*) action=again
                       LESS=-S ${PAGER:-less} "$dotest/patch" ;;
@@ -418,6 +421,7 @@ do
        else
            action=yes
        fi
+       FIRSTLINE=$(head -1 "$dotest/final-commit")
 
        if test $action = skip
        then
@@ -431,7 +435,7 @@ do
                stop_here $this
        fi
 
-       printf 'Applying %s\n' "$SUBJECT"
+       printf 'Applying %s\n' "$FIRSTLINE"
 
        case "$resolved" in
        '')
@@ -489,7 +493,7 @@ do
        tree=$(git write-tree) &&
        parent=$(git rev-parse --verify HEAD) &&
        commit=$(git commit-tree $tree -p $parent <"$dotest/final-commit") &&
-       git update-ref -m "$GIT_REFLOG_ACTION: $SUBJECT" HEAD $commit $parent ||
+       git update-ref -m "$GIT_REFLOG_ACTION: $FIRSTLINE" HEAD $commit $parent ||
        stop_here $this
 
        if test -x "$GIT_DIR"/hooks/post-applypatch
index 48fb92d612f065166072e09f49ee4c1e58b34a3a..d8d9bfde4cdd4b558992c68cb7cdaaa1b8a1212d 100755 (executable)
@@ -1,7 +1,9 @@
 #!/bin/sh
 
-USAGE='[start|bad|good|skip|next|reset|visualize|replay|log|run]'
-LONG_USAGE='git bisect start [<bad> [<good>...]] [--] [<pathspec>...]
+USAGE='[help|start|bad|good|skip|next|reset|visualize|replay|log|run]'
+LONG_USAGE='git bisect help
+        print this long help message.
+git bisect start [<bad> [<good>...]] [--] [<pathspec>...]
         reset bisect state and start bisection.
 git bisect bad [<rev>]
         mark <rev> a known-bad revision.
@@ -20,7 +22,9 @@ git bisect replay <logfile>
 git bisect log
         show bisect log.
 git bisect run <cmd>...
-        use <cmd>... to automatically bisect.'
+        use <cmd>... to automatically bisect.
+
+Please use "git help bisect" to get the full man page.'
 
 OPTIONS_SPEC=
 . git-sh-setup
@@ -62,9 +66,10 @@ bisect_start() {
        # Verify HEAD. If we were bisecting before this, reset to the
        # top-of-line master first!
        #
-       head=$(GIT_DIR="$GIT_DIR" git symbolic-ref HEAD) ||
+       head=$(GIT_DIR="$GIT_DIR" git symbolic-ref -q HEAD) ||
        head=$(GIT_DIR="$GIT_DIR" git rev-parse --verify HEAD) ||
        die "Bad HEAD - I need a HEAD"
+       start_head=''
        case "$head" in
        refs/heads/bisect)
                if [ -s "$GIT_DIR/BISECT_START" ]; then
@@ -78,7 +83,7 @@ bisect_start() {
                # This error message should only be triggered by cogito usage,
                # and cogito users should understand it relates to cg-seek.
                [ -s "$GIT_DIR/head-name" ] && die "won't bisect on seeked tree"
-               echo "${head#refs/heads/}" >"$GIT_DIR/BISECT_START"
+               start_head="${head#refs/heads/}"
                ;;
        *)
                die "Bad HEAD - strange symbolic ref"
@@ -99,6 +104,7 @@ bisect_start() {
        done
        orig_args=$(sq "$@")
        bad_seen=0
+       eval=''
        while [ $# -gt 0 ]; do
            arg="$1"
            case "$arg" in
@@ -116,13 +122,15 @@ bisect_start() {
                0) state='bad' ; bad_seen=1 ;;
                *) state='good' ;;
                esac
-               bisect_write "$state" "$rev" 'nolog'
+               eval="$eval bisect_write '$state' '$rev' 'nolog'; "
                shift
                ;;
            esac
        done
 
        sq "$@" >"$GIT_DIR/BISECT_NAMES"
+       test -n "$start_head" && echo "$start_head" >"$GIT_DIR/BISECT_START"
+       eval "$eval"
        echo "git-bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG"
        bisect_auto_next
 }
@@ -151,20 +159,18 @@ bisect_state() {
                rev=$(git rev-parse --verify HEAD) ||
                        die "Bad rev input: HEAD"
                bisect_write "$state" "$rev" ;;
-       2,bad)
-               rev=$(git rev-parse --verify "$2^{commit}") ||
-                       die "Bad rev input: $2"
-               bisect_write "$state" "$rev" ;;
-       *,good|*,skip)
+       2,bad|*,good|*,skip)
                shift
-               revs=$(git rev-parse --revs-only --no-flags "$@") &&
-                       test '' != "$revs" || die "Bad rev input: $@"
-               for rev in $revs
+               eval=''
+               for rev in "$@"
                do
-                       rev=$(git rev-parse --verify "$rev^{commit}") ||
-                               die "Bad rev commit: $rev^{commit}"
-                       bisect_write "$state" "$rev"
-               done ;;
+                       sha=$(git rev-parse --verify "$rev^{commit}") ||
+                               die "Bad rev input: $rev"
+                       eval="$eval bisect_write '$state' '$sha'; "
+               done
+               eval "$eval" ;;
+       *,bad)
+               die "'git bisect bad' can take only one argument." ;;
        *)
                usage ;;
        esac
@@ -465,6 +471,8 @@ case "$#" in
     cmd="$1"
     shift
     case "$cmd" in
+    help)
+        git bisect -h ;;
     start)
         bisect_start "$@" ;;
     bad|good|skip)
index 60c458f201f8f98bb1c6e115c009525659c2ee20..9b13b833cb5762542848ee3e85e23d3ca0f76fa6 100755 (executable)
@@ -309,22 +309,42 @@ then
        }
 fi
 
-# If the branch to rebase is given, first switch to it.
+# If the branch to rebase is given, that is the branch we will rebase
+# $branch_name -- branch being rebased, or HEAD (already detached)
+# $orig_head -- commit object name of tip of the branch before rebasing
+# $head_name -- refs/heads/<that-branch> or "detached HEAD"
+switch_to=
 case "$#" in
 2)
+       # Is it "rebase other $branchname" or "rebase other $commit"?
        branch_name="$2"
-       git-checkout "$2" || usage
+       switch_to="$2"
+
+       if git show-ref --verify --quiet -- "refs/heads/$2" &&
+          branch=$(git rev-parse --verify "refs/heads/$2" 2>/dev/null)
+       then
+               head_name="refs/heads/$2"
+       elif branch=$(git rev-parse --verify "$2" 2>/dev/null)
+       then
+               head_name="detached HEAD"
+       else
+               usage
+       fi
        ;;
 *)
+       # Do not need to switch branches, we are already on it.
        if branch_name=`git symbolic-ref -q HEAD`
        then
+               head_name=$branch_name
                branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'`
        else
+               head_name="detached HEAD"
                branch_name=HEAD ;# detached
        fi
+       branch=$(git rev-parse --verify "${branch_name}^0") || exit
        ;;
 esac
-branch=$(git rev-parse --verify "${branch_name}^0") || exit
+orig_head=$branch
 
 # Now we are rebasing commits $upstream..$branch on top of $onto
 
@@ -335,6 +355,8 @@ if test "$upstream" = "$onto" && test "$mb" = "$onto" &&
        # linear history?
        ! git rev-list --parents "$onto".."$branch" | grep " .* " > /dev/null
 then
+       # Lazily switch to the target branch if needed...
+       test -z "$switch_to" || git checkout "$switch_to"
        echo >&2 "Current branch $branch_name is up to date."
        exit 0
 fi
@@ -346,22 +368,11 @@ then
        GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
 fi
 
-# move to a detached HEAD
-orig_head=$(git rev-parse HEAD^0)
-head_name=$(git symbolic-ref HEAD 2> /dev/null)
-case "$head_name" in
-'')
-       head_name="detached HEAD"
-       ;;
-*)
-       git checkout "$orig_head" > /dev/null 2>&1 ||
-               die "could not detach HEAD"
-       ;;
-esac
-
-# Rewind the head to "$onto"; this saves our current head in ORIG_HEAD.
+# Detach HEAD and reset the tree
 echo "First, rewinding head to replay your work on top of it..."
-git-reset --hard "$onto"
+git checkout "$onto^0" >/dev/null 2>&1 ||
+       die "could not detach HEAD"
+# git reset --hard "$onto^0"
 
 # If the $onto is a proper descendant of the tip of the branch, then
 # we just fast forwarded.
@@ -374,7 +385,8 @@ fi
 
 if test -z "$do_merge"
 then
-       git format-patch -k --stdout --full-index --ignore-if-in-upstream "$upstream"..ORIG_HEAD |
+       git format-patch -k --stdout --full-index --ignore-if-in-upstream \
+               "$upstream..$orig_head" |
        git am $git_am_opt --rebasing --resolvemsg="$RESOLVEMSG" &&
        move_to_original_branch
        ret=$?
@@ -397,7 +409,7 @@ echo "$orig_head" > "$dotest/orig-head"
 echo "$head_name" > "$dotest/head-name"
 
 msgnum=0
-for cmt in `git rev-list --reverse --no-merges "$upstream"..ORIG_HEAD`
+for cmt in `git rev-list --reverse --no-merges "$upstream..$orig_head"`
 do
        msgnum=$(($msgnum + 1))
        echo "$cmt" > "$dotest/cmt.$msgnum"
index be4a20d7cd562e9b00d93fe71313aed70afe50af..9e568bf9c012b610fd8db7e4444cb7ff8c6e0a0f 100755 (executable)
@@ -168,7 +168,8 @@ sub format_2822_time {
 # Example reply to:
 #$initial_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
 
-my $repo = Git->repository();
+my $repo = eval { Git->repository() };
+my @repo = $repo ? ($repo) : ();
 my $term = eval {
        $ENV{"GIT_SEND_EMAIL_NOTTY"}
                ? new Term::ReadLine 'git-send-email', \*STDIN, \*STDOUT
@@ -271,25 +272,25 @@ sub read_config {
 
        foreach my $setting (keys %config_bool_settings) {
                my $target = $config_bool_settings{$setting}->[0];
-               $$target = $repo->config_bool("$prefix.$setting") unless (defined $$target);
+               $$target = Git::config_bool(@repo, "$prefix.$setting") unless (defined $$target);
        }
 
        foreach my $setting (keys %config_settings) {
                my $target = $config_settings{$setting};
                if (ref($target) eq "ARRAY") {
                        unless (@$target) {
-                               my @values = $repo->config("$prefix.$setting");
+                               my @values = Git::config(@repo, "$prefix.$setting");
                                @$target = @values if (@values && defined $values[0]);
                        }
                }
                else {
-                       $$target = $repo->config("$prefix.$setting") unless (defined $$target);
+                       $$target = Git::config(@repo, "$prefix.$setting") unless (defined $$target);
                }
        }
 }
 
 # read configuration from [sendemail "$identity"], fall back on [sendemail]
-$identity = $repo->config("sendemail.identity") unless (defined $identity);
+$identity = Git::config(@repo, "sendemail.identity") unless (defined $identity);
 read_config("sendemail.$identity") if (defined $identity);
 read_config("sendemail");
 
@@ -327,8 +328,9 @@ sub read_config {
        }
 }
 
-my ($repoauthor) = $repo->ident_person('author');
-my ($repocommitter) = $repo->ident_person('committer');
+my ($repoauthor, $repocommitter);
+($repoauthor) = Git::ident_person(@repo, 'author');
+($repocommitter) = Git::ident_person(@repo, 'committer');
 
 # Verify the user input
 
@@ -415,7 +417,7 @@ sub read_config {
 
 my $prompting = 0;
 if (!defined $sender) {
-       $sender = $repoauthor || $repocommitter;
+       $sender = $repoauthor || $repocommitter || '';
 
        while (1) {
                $_ = $term->readline("Who should the emails appear to be from? [$sender] ");
@@ -509,7 +511,7 @@ sub expand_aliases {
 EOT
        close(C);
 
-       my $editor = $ENV{GIT_EDITOR} || $repo->config("core.editor") || $ENV{VISUAL} || $ENV{EDITOR} || "vi";
+       my $editor = $ENV{GIT_EDITOR} || Git::config(@repo, "core.editor") || $ENV{VISUAL} || $ENV{EDITOR} || "vi";
        system('sh', '-c', '$0 $@', $editor, $compose_filename);
 
        open(C2,">",$compose_filename . ".final")
index 56ec3536e0c40190329b9867b46e36753f30efb2..ce0f00c8a4f6d5f9a2c1c3ebdbadff52106b60d0 100755 (executable)
@@ -327,7 +327,8 @@ set_name_rev () {
                cd "$1" && {
                        git describe "$2" 2>/dev/null ||
                        git describe --tags "$2" 2>/dev/null ||
-                       git describe --contains --tags "$2"
+                       git describe --contains "$2" 2>/dev/null ||
+                       git describe --all --always "$2"
                }
        ) )
        test -z "$revname" || revname=" ($revname)"
@@ -342,6 +343,7 @@ set_name_rev () {
 #
 cmd_summary() {
        summary_limit=-1
+       for_status=
 
        # parse $args after "submodule ... summary".
        while test $# -ne 0
@@ -350,6 +352,9 @@ cmd_summary() {
                --cached)
                        cached="$1"
                        ;;
+               --for-status)
+                       for_status="$1"
+                       ;;
                -n|--summary-limit)
                        if summary_limit=$(($2 + 0)) 2>/dev/null && test "$summary_limit" = "$2"
                        then
@@ -397,7 +402,8 @@ cmd_summary() {
                done
        )
 
-       test -n "$modules" &&
+       test -z "$modules" && return
+
        git diff-index $cached --raw $head -- $modules |
        grep -e '^:160000' -e '^:[0-7]* 160000' |
        cut -c2- |
@@ -499,7 +505,14 @@ cmd_summary() {
                        echo
                fi
                echo
-       done
+       done |
+       if test -n "$for_status"; then
+               echo "# Modified submodules:"
+               echo "#"
+               sed -e 's|^|# |' -e 's|^# $|#|'
+       else
+               cat
+       fi
 }
 #
 # List all submodules, prefixed with:
index 81afb5cfcd67731a6f8c76a032408a8f048cc1c4..b864b54a4440537900cab47e71ee93bd01d72d28 100755 (executable)
@@ -1120,7 +1120,7 @@ sub cmt_metadata {
 
 sub working_head_info {
        my ($head, $refs) = @_;
-       my @args = ('log', '--no-color', '--first-parent');
+       my @args = ('log', '--no-color', '--first-parent', '--pretty=medium');
        my ($fh, $ctx) = command_output_pipe(@args, $head);
        my $hash;
        my %max;
index 9cd5b0a2b111de7e252c407d1ad77e05722d8385..743f2d4442b48af3627c1117aaaf73c89da306be 100644 (file)
@@ -95,7 +95,11 @@ for gitweb (in gitweb/README).
   by default it is file named gitweb_config.perl in the same place as
   gitweb.cgi script. You can control default place for config file
   using GITWEB_CONFIG build configuration variable, and you can set it
-  using GITWEB_CONFIG environmental variable.
+  using GITWEB_CONFIG environmental variable. If this file does not
+  exist, gitweb looks for a system-wide configuration file, normally
+  /etc/gitweb.conf. You can change the default using the
+  GITWEB_CONFIG_SYSTEM build configuration variable, and override it
+  through GITWEB_CONFIG_SYSTEM environmental variable.
 
 - Gitweb config file is [fragment] of perl code. You can set variables
   using "our $variable = value"; text from "#" character until the end
index 2163071047a0f4a7620eebf2f4e18008f592c049..8dfe335f73c223fa0da8cd21db6227283adb95ba 100644 (file)
@@ -100,13 +100,20 @@ You can specify the following configuration variables when building GIT:
    is set when gitweb.cgi is executed, then the file specified in the
    environment variable will be loaded instead of the file specified
    when gitweb.cgi was created.  [Default: gitweb_config.perl]
+ * GITWEB_CONFIG_SYSTEM
+   This Perl file will be loaded using 'do' as a fallback if GITWEB_CONFIG
+   does not exist.  If the environment variable GITWEB_CONFIG_SYSTEM is set
+   when gitweb.cgi is executed, then the file specified in the environment
+   variable will be loaded instead of the file specified when gitweb.cgi was
+   created.  [Default: /etc/gitweb.conf]
 
 
 Runtime gitweb configuration
 ----------------------------
 
 You can adjust gitweb behaviour using the file specified in `GITWEB_CONFIG`
-(defaults to 'gitweb_config.perl' in the same directory as the CGI).
+(defaults to 'gitweb_config.perl' in the same directory as the CGI), and
+as a fallback `GITWEB_CONFIG_SYSTEM` (defaults to /etc/gitweb.conf).
 The most notable thing that is not configurable at compile time are the
 optional features, stored in the '%features' variable.
 
index 73d098a433f4238c43603ab03c838c1356e7ab7a..a48bebb1bc01ec6af718cf014db0155145508e8b 100755 (executable)
@@ -369,7 +369,12 @@ sub filter_snapshot_fmts {
 }
 
 our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
-do $GITWEB_CONFIG if -e $GITWEB_CONFIG;
+if (-e $GITWEB_CONFIG) {
+       do $GITWEB_CONFIG;
+} else {
+       our $GITWEB_CONFIG_SYSTEM = $ENV{'GITWEB_CONFIG_SYSTEM'} || "++GITWEB_CONFIG_SYSTEM++";
+       do $GITWEB_CONFIG_SYSTEM if -e $GITWEB_CONFIG_SYSTEM;
+}
 
 # version of the core git binary
 our $git_version = qx($GIT --version) =~ m/git version (.*)$/ ? $1 : "unknown";
@@ -5171,14 +5176,26 @@ sub git_history {
        my $refs = git_get_references();
        my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
 
+       my @commitlist = parse_commits($hash_base, 101, (100 * $page),
+                                      $file_name, "--full-history");
+       if (!@commitlist) {
+               die_error('404 Not Found', "No such file or directory on given branch");
+       }
+
        if (!defined $hash && defined $file_name) {
-               $hash = git_get_hash_by_path($hash_base, $file_name);
+               # some commits could have deleted file in question,
+               # and not have it in tree, but one of them has to have it
+               for (my $i = 0; $i <= @commitlist; $i++) {
+                       $hash = git_get_hash_by_path($commitlist[$i]{'id'}, $file_name);
+                       last if defined $hash;
+               }
        }
        if (defined $hash) {
                $ftype = git_get_type($hash);
        }
-
-       my @commitlist = parse_commits($hash_base, 101, (100 * $page), $file_name, "--full-history");
+       if (!defined $ftype) {
+               die_error(undef, "Unknown type of object");
+       }
 
        my $paging_nav = '';
        if ($page > 0) {
index 5b2963998cc497177d913b6224799531d45dbb4a..8f5436b747830cc3e91d862efc3cbcb30fab65ae 100644 (file)
@@ -249,9 +249,9 @@ void show_log(struct rev_info *opt, const char *sep)
         *    not have an empty line between entries.
         */
        extra = "";
-       if (*sep != '\n' && opt->commit_format == CMIT_FMT_ONELINE)
+       if (*sep != '\n' && opt->use_terminator)
                extra = "\n";
-       if (opt->shown_one && opt->commit_format != CMIT_FMT_ONELINE)
+       if (opt->shown_one && !opt->use_terminator)
                putchar(opt->diffopt.line_termination);
        opt->shown_one = 1;
 
@@ -317,8 +317,10 @@ void show_log(struct rev_info *opt, const char *sep)
        if (opt->show_log_size)
                printf("log size %i\n", (int)msgbuf.len);
 
-       if (msgbuf.len)
-               printf("%s%s%s", msgbuf.buf, extra, sep);
+       if (msgbuf.len) {
+               fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+               printf("%s%s", extra, sep);
+       }
        strbuf_release(&msgbuf);
 }
 
index e87cafbe4199acb39fd9113e4b5096de19a3a61c..acf3fe3a1a82cd99e7bd6e0ff9d6d3d7e344a155 100644 (file)
@@ -344,7 +344,7 @@ void usage_with_options_internal(const char * const *usagestr,
                        break;
                case OPTION_INTEGER:
                        if (opts->flags & PARSE_OPT_OPTARG)
-                               pos += fprintf(stderr, " [<n>]");
+                               pos += fprintf(stderr, "[<n>]");
                        else
                                pos += fprintf(stderr, " <n>");
                        break;
index a2812ea612b997c1a76d89075dd1263a3af4fd37..2e7f896baec00d644903af5d967b6c781ee3503a 100644 (file)
@@ -487,22 +487,20 @@ sub wc_chdir {
 (exception is thrown otherwise), in array context returns allows the
 variable to be set multiple times and returns all the values.
 
-Must be called on a repository instance.
-
 This currently wraps command('config') so it is not so fast.
 
 =cut
 
 sub config {
-       my ($self, $var) = @_;
-       $self->repo_path()
-               or throw Error::Simple("not a repository");
+       my ($self, $var) = _maybe_self(@_);
 
        try {
+               my @cmd = ('config');
+               unshift @cmd, $self if $self;
                if (wantarray) {
-                       return $self->command('config', '--get-all', $var);
+                       return command(@cmd, '--get-all', $var);
                } else {
-                       return $self->command_oneline('config', '--get', $var);
+                       return command_oneline(@cmd, '--get', $var);
                }
        } catch Git::Error::Command with {
                my $E = shift;
@@ -522,20 +520,17 @@ sub config {
 is usable as a boolean in perl (and C<undef> if it's not defined,
 of course).
 
-Must be called on a repository instance.
-
 This currently wraps command('config') so it is not so fast.
 
 =cut
 
 sub config_bool {
-       my ($self, $var) = @_;
-       $self->repo_path()
-               or throw Error::Simple("not a repository");
+       my ($self, $var) = _maybe_self(@_);
 
        try {
-               my $val = $self->command_oneline('config', '--bool', '--get',
-                                             $var);
+               my @cmd = ('config', '--bool', '--get', $var);
+               unshift @cmd, $self if $self;
+               my $val = command_oneline(@cmd);
                return undef unless defined $val;
                return $val eq 'true';
        } catch Git::Error::Command with {
@@ -557,19 +552,17 @@ sub config_bool {
 by 1024, 1048576 (1024^2), or 1073741824 (1024^3) prior to output.
 It would return C<undef> if configuration variable is not defined,
 
-Must be called on a repository instance.
-
 This currently wraps command('config') so it is not so fast.
 
 =cut
 
 sub config_int {
-       my ($self, $var) = @_;
-       $self->repo_path()
-               or throw Error::Simple("not a repository");
+       my ($self, $var) = _maybe_self(@_);
 
        try {
-               return $self->command_oneline('config', '--int', '--get', $var);
+               my @cmd = ('config', '--int', '--get', $var);
+               unshift @cmd, $self if $self;
+               return command_oneline(@cmd);
        } catch Git::Error::Command with {
                my $E = shift;
                if ($E->value() == 1) {
@@ -639,15 +632,15 @@ sub get_color {
        "$name <$email>" eq ident_person($name);
        $time_tz =~ /^\d+ [+-]\d{4}$/;
 
-Both methods must be called on a repository instance.
-
 =cut
 
 sub ident {
-       my ($self, $type) = @_;
+       my ($self, $type) = _maybe_self(@_);
        my $identstr;
        if (lc $type eq lc 'committer' or lc $type eq lc 'author') {
-               $identstr = $self->command_oneline('var', 'GIT_'.uc($type).'_IDENT');
+               my @cmd = ('var', 'GIT_'.uc($type).'_IDENT');
+               unshift @cmd, $self if $self;
+               $identstr = command_oneline(@cmd);
        } else {
                $identstr = $type;
        }
@@ -659,8 +652,8 @@ sub ident {
 }
 
 sub ident_person {
-       my ($self, @ident) = @_;
-       $#ident == 0 and @ident = $self->ident($ident[0]);
+       my ($self, @ident) = _maybe_self(@_);
+       $#ident == 0 and @ident = $self ? $self->ident($ident[0]) : ident($ident[0]);
        return "$ident[0] <$ident[1]>";
 }
 
index 16bfb86cd3ce6d6b471cdc313114563ca78837dc..687293224c3bca20da413d132e17a436e2c79990 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -4,40 +4,49 @@
 #include "diff.h"
 #include "revision.h"
 
-static struct cmt_fmt_map {
-       const char *n;
-       size_t cmp_len;
-       enum cmit_fmt v;
-} cmt_fmts[] = {
-       { "raw",        1,      CMIT_FMT_RAW },
-       { "medium",     1,      CMIT_FMT_MEDIUM },
-       { "short",      1,      CMIT_FMT_SHORT },
-       { "email",      1,      CMIT_FMT_EMAIL },
-       { "full",       5,      CMIT_FMT_FULL },
-       { "fuller",     5,      CMIT_FMT_FULLER },
-       { "oneline",    1,      CMIT_FMT_ONELINE },
-       { "format:",    7,      CMIT_FMT_USERFORMAT},
-};
-
 static char *user_format;
 
-enum cmit_fmt get_commit_format(const char *arg)
+void get_commit_format(const char *arg, struct rev_info *rev)
 {
        int i;
-
-       if (!arg || !*arg)
-               return CMIT_FMT_DEFAULT;
+       static struct cmt_fmt_map {
+               const char *n;
+               size_t cmp_len;
+               enum cmit_fmt v;
+       } cmt_fmts[] = {
+               { "raw",        1,      CMIT_FMT_RAW },
+               { "medium",     1,      CMIT_FMT_MEDIUM },
+               { "short",      1,      CMIT_FMT_SHORT },
+               { "email",      1,      CMIT_FMT_EMAIL },
+               { "full",       5,      CMIT_FMT_FULL },
+               { "fuller",     5,      CMIT_FMT_FULLER },
+               { "oneline",    1,      CMIT_FMT_ONELINE },
+       };
+
+       rev->use_terminator = 0;
+       if (!arg || !*arg) {
+               rev->commit_format = CMIT_FMT_DEFAULT;
+               return;
+       }
        if (*arg == '=')
                arg++;
-       if (!prefixcmp(arg, "format:")) {
+       if (!prefixcmp(arg, "format:") || !prefixcmp(arg, "tformat:")) {
+               const char *cp = strchr(arg, ':') + 1;
                free(user_format);
-               user_format = xstrdup(arg + 7);
-               return CMIT_FMT_USERFORMAT;
+               user_format = xstrdup(cp);
+               if (arg[0] == 't')
+                       rev->use_terminator = 1;
+               rev->commit_format = CMIT_FMT_USERFORMAT;
+               return;
        }
        for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) {
                if (!strncmp(arg, cmt_fmts[i].n, cmt_fmts[i].cmp_len) &&
-                   !strncmp(arg, cmt_fmts[i].n, strlen(arg)))
-                       return cmt_fmts[i].v;
+                   !strncmp(arg, cmt_fmts[i].n, strlen(arg))) {
+                       if (cmt_fmts[i].v == CMIT_FMT_ONELINE)
+                               rev->use_terminator = 1;
+                       rev->commit_format = cmt_fmts[i].v;
+                       return;
+               }
        }
 
        die("invalid --pretty format: %s", arg);
@@ -457,6 +466,7 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
        const struct commit *commit = c->commit;
        const char *msg = commit->buffer;
        struct commit_list *p;
+       int h1, h2;
 
        /* these are independent of the commit */
        switch (placeholder[0]) {
@@ -478,6 +488,16 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
        case 'n':               /* newline */
                strbuf_addch(sb, '\n');
                return 1;
+       case 'x':
+               /* %x00 == NUL, %x0a == LF, etc. */
+               if (0 <= (h1 = hexval_table[0xff & placeholder[1]]) &&
+                   h1 <= 16 &&
+                   0 <= (h2 = hexval_table[0xff & placeholder[2]]) &&
+                   h2 <= 16) {
+                       strbuf_addch(sb, (h1<<4)|h2);
+                       return 3;
+               } else
+                       return 0;
        }
 
        /* these depend on the commit */
index f83ae87e150ff93728da989f1d35ce0ad7c10f60..828d49001d6c8494ede35e4ebbcea4fe482802dd 100644 (file)
@@ -10,6 +10,7 @@
 static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
 
 static int deny_non_fast_forwards = 0;
+static int receive_fsck_objects;
 static int receive_unpack_limit = -1;
 static int transfer_unpack_limit = -1;
 static int unpack_limit = 100;
@@ -35,6 +36,11 @@ static int receive_pack_config(const char *var, const char *value)
                return 0;
        }
 
+       if (strcmp(var, "receive.fsckobjects") == 0) {
+               receive_fsck_objects = git_config_bool(var, value);
+               return 0;
+       }
+
        return git_default_config(var, value);
 }
 
@@ -368,11 +374,13 @@ static const char *unpack(void)
                        ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries));
 
        if (ntohl(hdr.hdr_entries) < unpack_limit) {
-               int code;
-               const char *unpacker[3];
-               unpacker[0] = "unpack-objects";
-               unpacker[1] = hdr_arg;
-               unpacker[2] = NULL;
+               int code, i = 0;
+               const char *unpacker[4];
+               unpacker[i++] = "unpack-objects";
+               if (receive_fsck_objects)
+                       unpacker[i++] = "--strict";
+               unpacker[i++] = hdr_arg;
+               unpacker[i++] = NULL;
                code = run_command_v_opt(unpacker, RUN_GIT_CMD);
                switch (code) {
                case 0:
@@ -393,8 +401,8 @@ static const char *unpack(void)
                        return "unpacker exited with error code";
                }
        } else {
-               const char *keeper[6];
-               int s, status;
+               const char *keeper[7];
+               int s, status, i = 0;
                char keep_arg[256];
                struct child_process ip;
 
@@ -402,12 +410,14 @@ static const char *unpack(void)
                if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
                        strcpy(keep_arg + s, "localhost");
 
-               keeper[0] = "index-pack";
-               keeper[1] = "--stdin";
-               keeper[2] = "--fix-thin";
-               keeper[3] = hdr_arg;
-               keeper[4] = keep_arg;
-               keeper[5] = NULL;
+               keeper[i++] = "index-pack";
+               keeper[i++] = "--stdin";
+               if (receive_fsck_objects)
+                       keeper[i++] = "--strict";
+               keeper[i++] = "--fix-thin";
+               keeper[i++] = hdr_arg;
+               keeper[i++] = keep_arg;
+               keeper[i++] = NULL;
                memset(&ip, 0, sizeof(ip));
                ip.argv = keeper;
                ip.out = -1;
index 08af7f9de124f2e06dc8edd030212ecde9c22920..06ad15627a6488f3a5e6c699828f6f721d8647ba 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -315,7 +315,7 @@ static int handle_config(const char *key, const char *value)
        }
        if (!prefixcmp(key, "url.")) {
                struct rewrite *rewrite;
-               name = key + 5;
+               name = key + 4;
                subkey = strrchr(name, '.');
                if (!subkey)
                        return 0;
@@ -409,7 +409,7 @@ static void read_config(void)
        alias_all_urls();
 }
 
-static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch)
+static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
 {
        int i;
        int st;
@@ -519,17 +519,32 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
        return rs;
 
  invalid:
+       if (verify) {
+               free(rs);
+               return NULL;
+       }
        die("Invalid refspec '%s'", refspec[i]);
 }
 
+int valid_fetch_refspec(const char *fetch_refspec_str)
+{
+       const char *fetch_refspec[] = { fetch_refspec_str };
+       struct refspec *refspec;
+
+       refspec = parse_refspec_internal(1, fetch_refspec, 1, 1);
+       if (refspec)
+               free(refspec);
+       return !!refspec;
+}
+
 struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec)
 {
-       return parse_refspec_internal(nr_refspec, refspec, 1);
+       return parse_refspec_internal(nr_refspec, refspec, 1, 0);
 }
 
 struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
 {
-       return parse_refspec_internal(nr_refspec, refspec, 0);
+       return parse_refspec_internal(nr_refspec, refspec, 0, 0);
 }
 
 static int valid_remote_nick(const char *name)
index 7e9ae792dc69bb8b07cb9b8cf4e53845595d320e..a38774bbdc5acfb5ed9360ac92e1049fa79b26e1 100644 (file)
--- a/remote.h
+++ b/remote.h
@@ -67,6 +67,7 @@ void free_refs(struct ref *ref);
  */
 void ref_remove_duplicates(struct ref *ref_map);
 
+int valid_fetch_refspec(const char *refspec);
 struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec);
 struct refspec *parse_push_refspec(int nr_refspec, const char **refspec);
 
index 196fedc9d1297617b74f058f570beb2f5168c3d6..4231ea2cce57c74a4110c9c69459a4caf67dc15c 100644 (file)
@@ -1083,6 +1083,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
                                continue;
                        }
                        if (!strcmp(arg, "--topo-order")) {
+                               revs->lifo = 1;
                                revs->topo_order = 1;
                                continue;
                        }
@@ -1198,7 +1199,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
                        }
                        if (!prefixcmp(arg, "--pretty")) {
                                revs->verbose_header = 1;
-                               revs->commit_format = get_commit_format(arg+8);
+                               get_commit_format(arg+8, revs);
                                continue;
                        }
                        if (!strcmp(arg, "--root")) {
index c8b3b948ecc1cc8b45859a6e1ea11763addfb8b5..31217f8c67307aa09c2f470ccdbdebd5c2445890 100644 (file)
@@ -64,7 +64,8 @@ struct rev_info {
 
        /* Format info */
        unsigned int    shown_one:1,
-                       abbrev_commit:1;
+                       abbrev_commit:1,
+                       use_terminator:1;
        enum date_mode date_mode;
 
        const char **ignore_packed; /* pretend objects in these are unpacked */
index b36a9012ecb3a34761027de77635741e1cd80aab..a675cbb51b5dafad22dd494784a0b4c8ec396db3 100755 (executable)
@@ -595,6 +595,64 @@ test_expect_success 'set --int' '
 
 rm .git/config
 
+cat >expect <<\EOF
+[bool]
+       true1 = true
+       true2 = true
+       false1 = false
+       false2 = false
+[int]
+       int1 = 0
+       int2 = 1
+       int3 = -1
+EOF
+
+test_expect_success 'get --bool-or-int' '
+       (
+               echo "[bool]"
+               echo true1
+               echo true2 = true
+               echo false = false
+               echo "[int]"
+               echo int1 = 0
+               echo int2 = 1
+               echo int3 = -1
+       ) >>.git/config &&
+       test $(git config --bool-or-int bool.true1) = true &&
+       test $(git config --bool-or-int bool.true2) = true &&
+       test $(git config --bool-or-int bool.false) = false &&
+       test $(git config --bool-or-int int.int1) = 0 &&
+       test $(git config --bool-or-int int.int2) = 1 &&
+       test $(git config --bool-or-int int.int3) = -1
+
+'
+
+rm .git/config
+cat >expect <<\EOF
+[bool]
+       true1 = true
+       false1 = false
+       true2 = true
+       false2 = false
+[int]
+       int1 = 0
+       int2 = 1
+       int3 = -1
+EOF
+
+test_expect_success 'set --bool-or-int' '
+       git config --bool-or-int bool.true1 true &&
+       git config --bool-or-int bool.false1 false &&
+       git config --bool-or-int bool.true2 yes &&
+       git config --bool-or-int bool.false2 no &&
+       git config --bool-or-int int.int1 0 &&
+       git config --bool-or-int int.int2 1 &&
+       git config --bool-or-int int.int3 -1 &&
+       test_cmp expect .git/config
+'
+
+rm .git/config
+
 git config quote.leading " test"
 git config quote.ending "test "
 git config quote.semicolon "test;test"
diff --git a/t/t3408-rebase-multi-line.sh b/t/t3408-rebase-multi-line.sh
new file mode 100755 (executable)
index 0000000..e12cd57
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+test_description='rebasing a commit with multi-line first paragraph.'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+
+       >file &&
+       git add file &&
+       test_tick &&
+       git commit -m initial &&
+
+       echo hello >file &&
+       test_tick &&
+       git commit -a -m "A sample commit log message that has a long
+summary that spills over multiple lines.
+
+But otherwise with a sane description."
+
+       git branch side &&
+
+       git reset --hard HEAD^ &&
+       >elif &&
+       git add elif &&
+       test_tick &&
+       git commit -m second
+
+'
+
+test_expect_success rebase '
+
+       git checkout side &&
+       git rebase master &&
+       git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
+       git cat-file commit side@{1} | sed -e "1,/^$/d" >expect &&
+       test_cmp expect actual
+
+'
+
+test_done
index 77c90f6fa002ce00c3ffb30d0b79adaff46b3caa..f15be93e7709acbb517bb85020d4d6b94a50f725 100755 (executable)
@@ -66,4 +66,23 @@ test_expect_success 'revert works (commit)' '
        grep "unchanged *+3/-0 file" output
 '
 
+test_expect_success 'patch does not affect mode' '
+       git reset --hard &&
+       echo content >>file &&
+       chmod +x file &&
+       printf "n\\ny\\n" | git add -p &&
+       git show :file | grep content &&
+       git diff file | grep "new mode"
+'
+
+test_expect_success 'stage mode but not hunk' '
+       git reset --hard &&
+       echo content >>file &&
+       chmod +x file &&
+       printf "y\\nn\\n" | git add -p &&
+       git diff --cached file | grep "new mode" &&
+       git diff          file | grep "+content"
+'
+
+
 test_done
index dca2067b2d0bcd4423d843561b9275be50fe0da3..fa62b6aa21f5d8f8774b7f2af3a4cd60b8c0d761 100755 (executable)
@@ -109,9 +109,10 @@ test_expect_success \
     'diff -r a c/prefix/a'
 
 test_expect_success \
-    'create an archive with a substfiles' \
+    'create archives with substfiles' \
     'echo "substfile?" export-subst >a/.gitattributes &&
      git archive HEAD >f.tar &&
+     git archive --prefix=prefix/ HEAD >g.tar &&
      rm a/.gitattributes'
 
 test_expect_success \
@@ -126,6 +127,18 @@ test_expect_success \
       diff a/substfile2 f/a/substfile2
 '
 
+test_expect_success \
+    'extract substfiles from archive with prefix' \
+    '(mkdir g && cd g && $TAR xf -) <g.tar'
+
+test_expect_success \
+     'validate substfile contents from archive with prefix' \
+     'git log --max-count=1 "--pretty=format:A${SUBSTFORMAT}O" HEAD \
+      >g/prefix/a/substfile1.expected &&
+      diff g/prefix/a/substfile1.expected g/prefix/a/substfile1 &&
+      diff a/substfile2 g/prefix/a/substfile2
+'
+
 test_expect_success \
     'git archive --format=zip' \
     'git archive --format=zip HEAD >d.zip'
index c955fe44f5b962ef305e49c21bc3fb0e5b58d462..983a39398f17dc2b261771e780e8c010f038a12a 100755 (executable)
@@ -274,4 +274,99 @@ test_expect_success \
      packname_4=$(git pack-objects test-4 <obj-list) &&
      test 3 = $(ls test-4-*.pack | wc -l)'
 
+test_expect_success 'unpacking with --strict' '
+
+       git config --unset pack.packsizelimit &&
+       for j in a b c d e f g
+       do
+               for i in 0 1 2 3 4 5 6 7 8 9
+               do
+                       o=$(echo $j$i | git hash-object -w --stdin) &&
+                       echo "100644 $o 0 $j$i"
+               done
+       done >LIST &&
+       rm -f .git/index &&
+       git update-index --index-info <LIST &&
+       LIST=$(git write-tree) &&
+       rm -f .git/index &&
+       head -n 10 LIST | git update-index --index-info &&
+       LI=$(git write-tree) &&
+       rm -f .git/index &&
+       tail -n 10 LIST | git update-index --index-info &&
+       ST=$(git write-tree) &&
+       PACK5=$( git rev-list --objects "$LIST" "$LI" "$ST" | \
+               git pack-objects test-5 ) &&
+       PACK6=$( (
+                       echo "$LIST"
+                       echo "$LI"
+                       echo "$ST"
+                ) | git pack-objects test-6 ) &&
+       test_create_repo test-5 &&
+       (
+               cd test-5 &&
+               git unpack-objects --strict <../test-5-$PACK5.pack &&
+               git ls-tree -r $LIST &&
+               git ls-tree -r $LI &&
+               git ls-tree -r $ST
+       ) &&
+       test_create_repo test-6 &&
+       (
+               # tree-only into empty repo -- many unreachables
+               cd test-6 &&
+               test_must_fail git unpack-objects --strict <../test-6-$PACK6.pack
+       ) &&
+       (
+               # already populated -- no unreachables
+               cd test-5 &&
+               git unpack-objects --strict <../test-6-$PACK6.pack
+       )
+'
+
+test_expect_success 'index-pack with --strict' '
+
+       for j in a b c d e f g
+       do
+               for i in 0 1 2 3 4 5 6 7 8 9
+               do
+                       o=$(echo $j$i | git hash-object -w --stdin) &&
+                       echo "100644 $o 0 $j$i"
+               done
+       done >LIST &&
+       rm -f .git/index &&
+       git update-index --index-info <LIST &&
+       LIST=$(git write-tree) &&
+       rm -f .git/index &&
+       head -n 10 LIST | git update-index --index-info &&
+       LI=$(git write-tree) &&
+       rm -f .git/index &&
+       tail -n 10 LIST | git update-index --index-info &&
+       ST=$(git write-tree) &&
+       PACK5=$( git rev-list --objects "$LIST" "$LI" "$ST" | \
+               git pack-objects test-5 ) &&
+       PACK6=$( (
+                       echo "$LIST"
+                       echo "$LI"
+                       echo "$ST"
+                ) | git pack-objects test-6 ) &&
+       test_create_repo test-7 &&
+       (
+               cd test-7 &&
+               git index-pack --strict --stdin <../test-5-$PACK5.pack &&
+               git ls-tree -r $LIST &&
+               git ls-tree -r $LI &&
+               git ls-tree -r $ST
+       ) &&
+       test_create_repo test-8 &&
+       (
+               # tree-only into empty repo -- many unreachables
+               cd test-8 &&
+               test_must_fail git index-pack --strict --stdin <../test-6-$PACK6.pack
+       ) &&
+       (
+               # already populated -- no unreachables
+               cd test-7 &&
+               git index-pack --strict --stdin <../test-6-$PACK6.pack
+       )
+'
+
 test_done
index 0a7fea865d2be6e1a74e2016f336af22956de414..af2d077792c108a9125c73d1e4194f2532cb5156 100755 (executable)
@@ -253,4 +253,10 @@ test_expect_success '"remote show" does not show symbolic refs' '
 
 '
 
+test_expect_success 'reject adding remote with an invalid name' '
+
+       ! git remote add some:url desired-name
+
+'
+
 test_done
index 793ffc6600202431193887a12981105c099d40df..6d7e7385483bda6223d8d222980bf33b2679f711 100755 (executable)
@@ -103,9 +103,9 @@ test_expect_success 'fetch with wildcard' '
 test_expect_success 'fetch with insteadOf' '
        mk_empty &&
        (
-               TRASH=$(pwd) &&
+               TRASH=$(pwd)/ &&
                cd testrepo &&
-               git config url./$TRASH/.insteadOf trash/
+               git config url.$TRASH.insteadOf trash/
                git config remote.up.url trash/. &&
                git config remote.up.fetch "refs/heads/*:refs/remotes/origin/*" &&
                git fetch up &&
@@ -145,8 +145,8 @@ test_expect_success 'push with wildcard' '
 
 test_expect_success 'push with insteadOf' '
        mk_empty &&
-       TRASH=$(pwd) &&
-       git config url./$TRASH/.insteadOf trash/ &&
+       TRASH=$(pwd)/ &&
+       git config url.$TRASH.insteadOf trash/ &&
        git push trash/testrepo refs/heads/master:refs/remotes/origin/master &&
        (
                cd testrepo &&
index f471c1526f34fa87227ac23b458299063b408ff1..5e3e5445c730140ad6c2fa9cc5bda4a7029e7fbf 100755 (executable)
@@ -71,6 +71,24 @@ test_expect_success 'bisect start with one bad and good' '
        git bisect next
 '
 
+test_expect_success 'bisect fails if given any junk instead of revs' '
+       git bisect reset &&
+       test_must_fail git bisect start foo $HASH1 -- &&
+       test_must_fail git bisect start $HASH4 $HASH1 bar -- &&
+       test -z "$(git for-each-ref "refs/bisect/*")" &&
+       test_must_fail ls .git/BISECT_* &&
+       git bisect start &&
+       test_must_fail git bisect good foo $HASH1 &&
+       test_must_fail git bisect good $HASH1 bar &&
+       test_must_fail git bisect bad frotz &&
+       test_must_fail git bisect bad $HASH3 $HASH4 &&
+       test_must_fail git bisect skip bar $HASH3 &&
+       test_must_fail git bisect skip $HASH1 foo &&
+       test -z "$(git for-each-ref "refs/bisect/*")" &&
+       git bisect good $HASH1 &&
+       git bisect bad $HASH4
+'
+
 test_expect_success 'bisect reset: back in the master branch' '
        git bisect reset &&
        echo "* master" > branch.expect &&
index afccfc9973ba864167387b1e1caf6fe8b12f68f9..a50492f7c065d034cb344eac965d51a82cb5a599 100755 (executable)
@@ -75,8 +75,8 @@ test_expect_success 'git-clean src/ src/' '
 
 test_expect_success 'git-clean with prefix' '
 
-       mkdir -p build docs &&
-       touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
+       mkdir -p build docs src/test &&
+       touch a.out src/part3.c docs/manual.txt obj.o build/lib.so src/test/1.c &&
        (cd src/ && git-clean) &&
        test -f Makefile &&
        test -f README &&
@@ -84,6 +84,7 @@ test_expect_success 'git-clean with prefix' '
        test -f src/part2.c &&
        test -f a.out &&
        test ! -f src/part3.c &&
+       test -f src/test/1.c &&
        test -f docs/manual.txt &&
        test -f obj.o &&
        test -f build/lib.so
index 0f3c42ab35891d1dd671649ff38074a1d83e2a5b..bf12dbdeef6e307850a91eb6be5ebe537b2de0c8 100755 (executable)
@@ -30,7 +30,7 @@ commit_file () {
 }
 
 test_create_repo sm1 &&
-add_file . foo
+add_file . foo >/dev/null
 
 head1=$(add_file sm1 foo1 foo2)
 
@@ -192,4 +192,17 @@ test_expect_success 'given commit' "
 EOF
 "
 
+test_expect_success '--for-status' "
+    git submodule summary --for-status HEAD^ >actual &&
+    test_cmp actual - <<EOF
+# Modified submodules:
+#
+# * sm1 $head6...0000000:
+#
+# * sm2 0000000...$head7 (2):
+#   > Add foo9
+#
+EOF
+"
+
 test_done
index cd08516e6de6b5c4b39ffee14302d76c99229825..e4bfcaece0c3ac4ea4b33521e84bd7fc1c19422e 100755 (executable)
@@ -149,4 +149,138 @@ test_expect_success 'status of partial commit excluding new file in index' '
        test_cmp expect output
 '
 
+test_expect_success 'setup status submodule summary' '
+       test_create_repo sm && (
+               cd sm &&
+               >foo &&
+               git add foo &&
+               git commit -m "Add foo"
+       ) &&
+       git add sm
+'
+
+cat >expect <<EOF
+# On branch master
+# Changes to be committed:
+#   (use "git reset HEAD <file>..." to unstage)
+#
+#      new file:   dir2/added
+#      new file:   sm
+#
+# Changed but not updated:
+#   (use "git add <file>..." to update what will be committed)
+#
+#      modified:   dir1/modified
+#
+# Untracked files:
+#   (use "git add <file>..." to include in what will be committed)
+#
+#      dir1/untracked
+#      dir2/modified
+#      dir2/untracked
+#      expect
+#      output
+#      untracked
+EOF
+test_expect_success 'status submodule summary is disabled by default' '
+       git status >output &&
+       test_cmp expect output
+'
+
+head=$(cd sm && git rev-parse --short=7 --verify HEAD)
+
+cat >expect <<EOF
+# On branch master
+# Changes to be committed:
+#   (use "git reset HEAD <file>..." to unstage)
+#
+#      new file:   dir2/added
+#      new file:   sm
+#
+# Changed but not updated:
+#   (use "git add <file>..." to update what will be committed)
+#
+#      modified:   dir1/modified
+#
+# Modified submodules:
+#
+# * sm 0000000...$head (1):
+#   > Add foo
+#
+# Untracked files:
+#   (use "git add <file>..." to include in what will be committed)
+#
+#      dir1/untracked
+#      dir2/modified
+#      dir2/untracked
+#      expect
+#      output
+#      untracked
+EOF
+test_expect_success 'status submodule summary' '
+       git config status.submodulesummary 10 &&
+       git status >output &&
+       test_cmp expect output
+'
+
+
+cat >expect <<EOF
+# On branch master
+# Changed but not updated:
+#   (use "git add <file>..." to update what will be committed)
+#
+#      modified:   dir1/modified
+#
+# Untracked files:
+#   (use "git add <file>..." to include in what will be committed)
+#
+#      dir1/untracked
+#      dir2/modified
+#      dir2/untracked
+#      expect
+#      output
+#      untracked
+no changes added to commit (use "git add" and/or "git commit -a")
+EOF
+test_expect_success 'status submodule summary (clean submodule)' '
+       git commit -m "commit submodule" &&
+       git config status.submodulesummary 10 &&
+       test_must_fail git status >output &&
+       test_cmp expect output
+'
+
+cat >expect <<EOF
+# On branch master
+# Changes to be committed:
+#   (use "git reset HEAD^1 <file>..." to unstage)
+#
+#      new file:   dir2/added
+#      new file:   sm
+#
+# Changed but not updated:
+#   (use "git add <file>..." to update what will be committed)
+#
+#      modified:   dir1/modified
+#
+# Modified submodules:
+#
+# * sm 0000000...$head (1):
+#   > Add foo
+#
+# Untracked files:
+#   (use "git add <file>..." to include in what will be committed)
+#
+#      dir1/untracked
+#      dir2/modified
+#      dir2/untracked
+#      expect
+#      output
+#      untracked
+EOF
+test_expect_success 'status submodule summary (--amend)' '
+       git config status.submodulesummary 10 &&
+       git status --amend >output &&
+       test_cmp expect output
+'
+
 test_done
index 796cd7dba0cdc64e6b9e68e81663e9a70327d8e5..061a2596d3b63e7d737d735c4a6cb097bfcf387f 100755 (executable)
@@ -483,6 +483,22 @@ test_expect_success \
        'gitweb_run "p=.git;a=history;f=file"'
 test_debug 'cat gitweb.log'
 
+test_expect_success \
+       'logs: history (implicit HEAD, non-existent file)' \
+       'gitweb_run "p=.git;a=history;f=non-existent"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'logs: history (implicit HEAD, deleted file)' \
+       'git checkout master &&
+        echo "to be deleted" > deleted_file &&
+        git add deleted_file &&
+        git commit -m "Add file to be deleted" &&
+        git rm deleted_file &&
+        git commit -m "Delete file" &&
+        gitweb_run "p=.git;a=history;f=deleted_file"'
+test_debug 'cat gitweb.log'
+
 # ----------------------------------------------------------------------
 # feed generation
 
diff --git a/var.c b/var.c
index 0de0efa2aa3b216a0bc846135a54ed0dd0549f8b..c20ac919bdbe73c8cd7657d468d2dfbccf6d3aa2 100644 (file)
--- a/var.c
+++ b/var.c
@@ -51,11 +51,12 @@ static int show_config(const char *var, const char *value)
 int main(int argc, char **argv)
 {
        const char *val;
+       int nongit;
        if (argc != 2) {
                usage(var_usage);
        }
 
-       setup_git_directory();
+       setup_git_directory_gently(&nongit);
        val = NULL;
 
        if (strcmp(argv[1], "-l") == 0) {
index b3fd57b79df3513d271c23caf3ab46b3ba405e40..532b4ea2c1960f18e41a5167a60f6de1b481606b 100644 (file)
@@ -8,9 +8,11 @@
 #include "revision.h"
 #include "diffcore.h"
 #include "quote.h"
+#include "run-command.h"
 
 int wt_status_relative_paths = 1;
 int wt_status_use_color = -1;
+int wt_status_submodule_summary;
 static char wt_status_colors[][COLOR_MAXLEN] = {
        "",         /* WT_STATUS_HEADER: normal */
        "\033[32m", /* WT_STATUS_UPDATED: green */
@@ -220,6 +222,36 @@ static void wt_status_print_changed(struct wt_status *s)
        run_diff_files(&rev, 0);
 }
 
+static void wt_status_print_submodule_summary(struct wt_status *s)
+{
+       struct child_process sm_summary;
+       char summary_limit[64];
+       char index[PATH_MAX];
+       const char *env[] = { index, NULL };
+       const char *argv[] = {
+               "submodule",
+               "summary",
+               "--cached",
+               "--for-status",
+               "--summary-limit",
+               summary_limit,
+               s->amend ? "HEAD^" : "HEAD",
+               NULL
+       };
+
+       sprintf(summary_limit, "%d", wt_status_submodule_summary);
+       snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", s->index_file);
+
+       memset(&sm_summary, 0, sizeof(sm_summary));
+       sm_summary.argv = argv;
+       sm_summary.env = env;
+       sm_summary.git_cmd = 1;
+       sm_summary.no_stdin = 1;
+       fflush(s->fp);
+       sm_summary.out = dup(fileno(s->fp));    /* run_command closes it */
+       run_command(&sm_summary);
+}
+
 static void wt_status_print_untracked(struct wt_status *s)
 {
        struct dir_struct dir;
@@ -308,6 +340,8 @@ void wt_status_print(struct wt_status *s)
        }
 
        wt_status_print_changed(s);
+       if (wt_status_submodule_summary)
+               wt_status_print_submodule_summary(s);
        wt_status_print_untracked(s);
 
        if (s->verbose && !s->is_initial)
@@ -330,6 +364,13 @@ void wt_status_print(struct wt_status *s)
 
 int git_status_config(const char *k, const char *v)
 {
+       if (!strcmp(k, "status.submodulesummary")) {
+               int is_bool;
+               wt_status_submodule_summary = git_config_bool_or_int(k, v, &is_bool);
+               if (is_bool && wt_status_submodule_summary)
+                       wt_status_submodule_summary = -1;
+               return 0;
+       }
        if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) {
                wt_status_use_color = git_config_colorbool(k, v, -1);
                return 0;