Merge branch 'lt/approxidate'
authorJunio C Hamano <gitster@pobox.com>
Tue, 1 Sep 2009 05:11:36 +0000 (22:11 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 1 Sep 2009 05:11:36 +0000 (22:11 -0700)
* lt/approxidate:
fix approxidate parsing of relative months and years
tests: add date printing and parsing tests
refactor test-date interface
Add date formatting and parsing functions relative to a given time
Further 'approxidate' improvements
Improve on 'approxidate'

Conflicts:
date.c

90 files changed:
Documentation/RelNotes-1.6.4.2.txt [new file with mode: 0644]
Documentation/RelNotes-1.6.5.txt
Documentation/git-archive.txt
Documentation/git-branch.txt
Documentation/git-checkout.txt
Documentation/git-clean.txt
Documentation/git-clone.txt
Documentation/git-commit.txt
Documentation/git-gc.txt
Documentation/git-instaweb.txt
Documentation/git-log.txt
Documentation/git-mv.txt
Documentation/git-submodule.txt
Documentation/git-tag.txt
Documentation/git-verify-pack.txt
Documentation/git-write-tree.txt
Documentation/git.txt
Makefile
abspath.c
arm/sha1.c [deleted file]
arm/sha1.h [deleted file]
arm/sha1_arm.S [deleted file]
bisect.c
block-sha1/sha1.c
block-sha1/sha1.h
builtin-add.c
builtin-branch.c
builtin-checkout.c
builtin-clean.c
builtin-clone.c
builtin-commit.c
builtin-log.c
builtin-mv.c
builtin-read-tree.c
builtin-reset.c
builtin-tag.c
builtin-unpack-objects.c
builtin-update-server-info.c [new file with mode: 0644]
builtin-verify-pack.c
builtin.h
cache.h
commit.c
compat/bswap.h [new file with mode: 0644]
configure.ac
contrib/fast-import/git-p4
diff-lib.c
entry.c
git-bisect.sh
git-compat-util.h
git-instaweb.sh
git-stash.sh
git-submodule.sh
git.c
gitweb/INSTALL
gitweb/gitweb.perl
graph.c
http.c
log-tree.c
log-tree.h
mozilla-sha1/sha1.c [deleted file]
mozilla-sha1/sha1.h [deleted file]
pretty.c
read-cache.c
revision.c
revision.h
t/gitweb-lib.sh [new file with mode: 0644]
t/t1009-read-tree-new-index.sh [new file with mode: 0755]
t/t2000-checkout-cache-clash.sh
t/t2015-checkout-unborn.sh [new file with mode: 0755]
t/t4013-diff-various.sh
t/t4013/diff.log_--decorate=full_--all [new file with mode: 0644]
t/t4039-diff-assume-unchanged.sh [new file with mode: 0755]
t/t5500-fetch-pack.sh
t/t5531-deep-submodule-push.sh [new file with mode: 0644]
t/t6015-rev-list-show-all-parents.sh [new file with mode: 0755]
t/t6016-rev-list-graph-simplify-history.sh [new file with mode: 0755]
t/t6030-bisect-porcelain.sh
t/t7060-wtstatus.sh [new file with mode: 0755]
t/t7102-reset.sh
t/t7401-submodule-summary.sh
t/t7407-submodule-foreach.sh [new file with mode: 0755]
t/t8005/iso8859-5.txt [deleted file]
t/t9500-gitweb-standalone-no-errors.sh
t/t9501-gitweb-standalone-http-status.sh [new file with mode: 0644]
t/test-lib.sh
transport.c
update-server-info.c [deleted file]
wt-status.c
wt-status.h
xdiff/xutils.c
diff --git a/Documentation/RelNotes-1.6.4.2.txt b/Documentation/RelNotes-1.6.4.2.txt
new file mode 100644 (file)
index 0000000..c11ec01
--- /dev/null
@@ -0,0 +1,32 @@
+GIT v1.6.4.2 Release Notes
+==========================
+
+Fixes since v1.6.4.1
+--------------------
+
+* --date=relative output between 1 and 5 years ago rounded the number of
+    years when saying X years Y months ago, instead of rounding it down.
+
+* "git add -p" did not handle changes in executable bits correctly
+  (a regression around 1.6.3).
+
+* "git apply" did not honor GNU diff's convention to mark the creation/deletion
+  event with UNIX epoch timestamp on missing side.
+
+* "git checkout" incorrectly removed files in a directory pointed by a
+  symbolic link during a branch switch that replaces a directory with
+  a symbolic link.
+
+* "git clean -d -f" happily descended into a subdirectory that is managed by a
+  separate git repository.  It now requires two -f options for safety.
+
+* "git fetch/push" over http transports had two rather grave bugs.
+
+* "git format-patch --cover-letter" did not prepare the cover letter file
+  for use with non-ASCII strings when there are the series contributors with
+  non-ASCII names.
+
+* "git pull origin branch" and "git fetch origin && git merge origin/branch"
+  left different merge messages in the resulting commit.
+
+Other minor documentation updates are included.
index 856047d16fd8d9936a6e5b954dc5bd084301b386..84a84519d47784d8cf6375e30d12d9b83f41672b 100644 (file)
@@ -31,14 +31,68 @@ Updates since v1.6.4
 
 (subsystems)
 
+ * various updates to git-svn and gitweb.
+
 (portability)
 
+ * more improvements on mingw port.
+
 (performance)
 
+ * On major platforms, the system can be compiled to use with Linus's
+   block-sha1 implementation of the SHA-1 hash algorithm, which
+   outperforms the default fallback implementation we borrowed from
+   Mozzilla.
+
 (usability, bells and whistles)
 
+ * refs/replace/ hierarchy is designed to be usable as a replacement
+   of the "grafts" mechanism, with the added advantage that it can be
+   transferred across repositories.
+
+ * "git am" learned to optionally ignore whitespace differences.
+
+ * "git am" handles input e-mail files that has CRLF line endings sensibly.
+
+ * "git commit --dry-run $args" is a new recommended way to ask "what would
+   happen if I try to commit with these arguments."
+
+ * "git cvsimport" now supports password-protected pserver access.
+
+ * "git fast-export" learned --no-data option that can be useful when
+   reordering commits and trees without touching the contents of
+   blobs.
+
+ * "git init" learned to mkdir/chdir into a directory when given an
+   extra argument (i.e. "git init this").
+
+ * "git instaweb" optionally can use mongoose as the web server.
+
+ * "git log --decorate" can optionally be told with --decorate=full to
+   give the reference name in full.
+
+ * "git push" can be told to be --quiet.
+
+ * informational output from "git reset" that lists the locally modified
+   paths is made consistent with that of "git checkout $another_branch".
+
+ * "git status" gives more descriptive output for unmerged paths.
+
+ * "git submodule" learned to give submodule name to scripts run with
+   "foreach" subcommand.
+
+ * various subcommands to "git submodule" learned --recursive option.
+
+ * "git submodule summary" learned --files option to compare the work
+   tree vs the commit bound at submodule path, instead of comparing
+   the index.
+
 (developers)
 
+ * With GIT_TEST_OPTS="--root=/p/a/t/h", tests can be run outside the
+   source directory; using tmpfs may give faster turnaround.
+
+
 Fixes since v1.6.4
 ------------------
 
@@ -48,4 +102,8 @@ Fixes since v1.6.4
 # Here are fixes that this release has, but have not been backported to
 # v1.6.4.X series.
 
-
+--
+exec >/var/tmp/1
+O=v1.6.4.1-266-g235db15
+echo O=$(git describe master)
+git shortlog --no-merges $O..master --not maint
index bc132c87e1a5b9f42ea1f2bbd4e3c46f67fc3852..92444ddf10081ee5faccd28491b47ef1cb45deee 100644 (file)
@@ -9,7 +9,7 @@ git-archive - Create an archive of files from a named tree
 SYNOPSIS
 --------
 [verse]
-'git archive' --format=<fmt> [--list] [--prefix=<prefix>/] [<extra>]
+'git archive' [--format=<fmt>] [--list] [--prefix=<prefix>/] [<extra>]
              [--output=<file>] [--worktree-attributes]
              [--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish>
              [path...]
index ae201deb7af44c61e793ab408e916c5b6520800d..aad71dc59a7c385be4f24ee9b981cd998fdd186f 100644 (file)
@@ -76,6 +76,7 @@ OPTIONS
        based sha1 expressions such as "<branchname>@\{yesterday}".
 
 -f::
+--force::
        Reset <branchname> to <startpoint> if <branchname> exists
        already. Without `-f` 'git-branch' refuses to change an existing branch.
 
@@ -209,6 +210,12 @@ but different purposes:
 - `--no-merged` is used to find branches which are candidates for merging
   into HEAD, since those branches are not fully contained by HEAD.
 
+SEE ALSO
+--------
+linkgit:git-check-ref-format[1],
+linkgit:git-fetch[1],
+linkgit:git-remote[1].
+
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org> and Junio C Hamano <gitster@pobox.com>
index ad4b31e89218e857001fce69f32acbe85fc7539c..b1314b561435029bb6fa468629cf71d9e3cad08a 100644 (file)
@@ -45,9 +45,11 @@ file can be discarded to recreate the original conflicted merge result.
 OPTIONS
 -------
 -q::
+--quiet::
        Quiet, suppress feedback messages.
 
 -f::
+--force::
        When switching branches, proceed even if the index or the
        working tree differs from HEAD.  This is used to throw away
        local changes.
index ae8938b2de9a5930ab18a220a6e8dd90ee6db3b1..9d291bdd266b49fe01b017dfce8e73dd288ad785 100644 (file)
@@ -32,6 +32,7 @@ OPTIONS
        if you really want to remove such a directory.
 
 -f::
+--force::
        If the git configuration specifies clean.requireForce as true,
        'git-clean' will refuse to run unless given -f or -n.
 
index 2c63a0fbaee0e246538607c8e2f983eb6eafa8e5..88ea272ee5a1994edfbc93347d5841228de46f17 100644 (file)
@@ -12,7 +12,7 @@ SYNOPSIS
 'git clone' [--template=<template_directory>]
          [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror]
          [-o <name>] [-u <upload-pack>] [--reference <repository>]
-         [--depth <depth>] [--] <repository> [<directory>]
+         [--depth <depth>] [--recursive] [--] <repository> [<directory>]
 
 DESCRIPTION
 -----------
@@ -147,6 +147,14 @@ objects from the source repository into a pack in the cloned repository.
        with a long history, and would want to send in fixes
        as patches.
 
+--recursive::
+       After the clone is created, initialize all submodules within,
+       using their default settings. This is equivalent to running
+       'git submodule update --init --recursive' immediately after
+       the clone is finished. This option is ignored if the cloned
+       repository does not have a worktree/checkout (i.e. if any of
+       `--no-checkout`/`-n`, `--bare`, or `--mirror` is given)
+
 <repository>::
        The (possibly remote) repository to clone from.  See the
        <<URLS,URLS>> section below for more information on specifying
index b5d81be7ecd60daa1a1d476441ca58e6b732d9ef..64f94cfe1293b627a17ff552c7983526425d1637 100644 (file)
@@ -8,8 +8,8 @@ git-commit - Record changes to the repository
 SYNOPSIS
 --------
 [verse]
-'git commit' [-a | --interactive] [-s] [-v] [-u<mode>] [--amend]
-          [(-c | -C) <commit>] [-F <file> | -m <msg>]
+'git commit' [-a | --interactive] [-s] [-v] [-u<mode>] [--amend] [--dry-run]
+          [(-c | -C) <commit>] [-F <file> | -m <msg>] [--dry-run]
           [--allow-empty] [--no-verify] [-e] [--author=<author>]
           [--cleanup=<mode>] [--] [[-i | -o ]<file>...]
 
@@ -42,10 +42,9 @@ The content to be added can be specified in several ways:
    by one which files should be part of the commit, before finalizing the
    operation.  Currently, this is done by invoking 'git-add --interactive'.
 
-The 'git-status' command can be used to obtain a
+The `--dry-run` option can be used to obtain a
 summary of what is included by any of the above for the next
-commit by giving the same set of parameters you would give to
-this command.
+commit by giving the same set of parameters (options and paths).
 
 If you make a commit and then find a mistake immediately after
 that, you can recover from it with 'git-reset'.
@@ -70,6 +69,12 @@ OPTIONS
        Like '-C', but with '-c' the editor is invoked, so that
        the user can further edit the commit message.
 
+--dry-run::
+       Do not actually make a commit, but show the list of paths
+       with updates in the index, paths with changes in the work tree,
+       and paths that are untracked, similar to the one that is given
+       in the commit log editor.
+
 -F <file>::
 --file=<file>::
        Take the commit message from the given file.  Use '-' to
@@ -198,6 +203,11 @@ specified.
 --quiet::
        Suppress commit summary message.
 
+--dry-run::
+       Do not create a commit, but show a list of paths that are
+       to be committed, paths with local changes that will be left
+       uncommitted and paths that are untracked.
+
 \--::
        Do not interpret any more arguments as options.
 
index b292e9843aa9da86cd44bd07d3ce35053be32177..dcac8c8e2970c23454f206321292583945ede8c5 100644 (file)
@@ -61,7 +61,7 @@ automatic consolidation of packs.
 
 --prune=<date>::
        Prune loose objects older than date (default is 2 weeks ago,
-       overrideable by the config variable `gc.pruneExpire`).  This
+       overridable by the config variable `gc.pruneExpire`).  This
        option is on by default.
 
 --no-prune::
index 22da21a54f625c434216945889127ec283d3d09f..0771f254436c9024b935ef745c3bcd384bc18465 100644 (file)
@@ -29,7 +29,7 @@ OPTIONS
        The HTTP daemon command-line that will be executed.
        Command-line options may be specified here, and the
        configuration file will be added at the end of the command-line.
-       Currently lighttpd, apache2 and webrick are supported.
+       Currently apache2, lighttpd, mongoose and webrick are supported.
        (Default: lighttpd)
 
 -m::
index 34cf4e5811d1a6f46fcbd333a2ff48c200eadff8..3d79de11ec36d0212610a4bec68789bdeec6c1fe 100644 (file)
@@ -37,8 +37,12 @@ include::diff-options.txt[]
        and <until>, see "SPECIFYING REVISIONS" section in
        linkgit:git-rev-parse[1].
 
---decorate::
-       Print out the ref names of any commits that are shown.
+--decorate[=short|full]::
+       Print out the ref names of any commits that are shown. If 'short' is
+       specified, the ref name prefixes 'refs/heads/', 'refs/tags/' and
+       'refs/remotes/' will not be printed. If 'full' is specified, the
+       full ref name (including prefix) will be printed. The default option
+       is 'short'.
 
 --source::
        Print out the ref name given on the command line by which each
index 9c5660275b326661bf7dc9a5162e5177b8a62b0f..bdcb58526ec2e838949e079891a420802df477db 100644 (file)
@@ -28,6 +28,7 @@ committed.
 OPTIONS
 -------
 -f::
+--force::
        Force renaming or moving of a file even if the target exists
 -k::
         Skip move or rename actions which would lead to an error
index 7dd73ae14eb38fd5bd291c2251f64768d198ebe5..5ccdd18c89381e81fc616facb22bd7fee6faf964 100644 (file)
@@ -11,12 +11,12 @@ SYNOPSIS
 [verse]
 'git submodule' [--quiet] add [-b branch]
              [--reference <repository>] [--] <repository> <path>
-'git submodule' [--quiet] status [--cached] [--] [<path>...]
+'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]
 'git submodule' [--quiet] init [--] [<path>...]
 'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--rebase]
-             [--reference <repository>] [--merge] [--] [<path>...]
-'git submodule' [--quiet] summary [--cached] [--summary-limit <n>] [commit] [--] [<path>...]
-'git submodule' [--quiet] foreach <command>
+             [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
+'git submodule' [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
+'git submodule' [--quiet] foreach [--recursive] <command>
 'git submodule' [--quiet] sync [--] [<path>...]
 
 
@@ -100,6 +100,9 @@ status::
        initialized and `+` if the currently checked out submodule commit
        does not match the SHA-1 found in the index of the containing
        repository. This command is the default command for 'git-submodule'.
++
+If '--recursive' is specified, this command will recurse into nested
+submodules, and show their status as well.
 
 init::
        Initialize the submodules, i.e. register each submodule name
@@ -122,21 +125,31 @@ update::
 If the submodule is not yet initialized, and you just want to use the
 setting as stored in .gitmodules, you can automatically initialize the
 submodule with the --init option.
++
+If '--recursive' is specified, this command will recurse into the
+registered submodules, and update any nested submodules within.
 
 summary::
        Show commit summary between the given commit (defaults to HEAD) and
        working tree/index. For a submodule in question, a series of commits
        in the submodule between the given super project commit and the
-       index or working tree (switched by --cached) are shown.
+       index or working tree (switched by --cached) are shown. If the option
+       --files is given, show the series of commits in the submodule between
+       the index of the super project and the working tree of the submodule
+       (this option doesn't allow to use the --cached option or to provide an
+       explicit commit).
 
 foreach::
        Evaluates an arbitrary shell command in each checked out submodule.
-       The command has access to the variables $path and $sha1:
+       The command has access to the variables $name, $path and $sha1:
+       $name is the name of the relevant submodule section in .gitmodules,
        $path is the name of the submodule directory relative to the
        superproject, and $sha1 is the commit as recorded in the superproject.
        Any submodules defined in the superproject but not checked out are
        ignored by this command. Unless given --quiet, foreach prints the name
        of each submodule before evaluating the command.
+       If --recursive is given, submodules are traversed recursively (i.e.
+       the given shell command is evaluated in nested submodules as well).
        A non-zero return from the command in any submodule causes
        the processing to terminate. This can be overridden by adding '|| :'
        to the end of the command.
@@ -169,6 +182,11 @@ OPTIONS
        commands typically use the commit found in the submodule HEAD, but
        with this option, the commit stored in the index is used instead.
 
+--files::
+       This option is only valid for the summary command. This command
+       compares the commit in the index with that in the submodule HEAD
+       when this option is used.
+
 -n::
 --summary-limit::
        This option is only valid for the summary command.
@@ -209,6 +227,12 @@ OPTIONS
 *NOTE*: Do *not* use this option unless you have read the note
 for linkgit:git-clone[1]'s --reference and --shared options carefully.
 
+--recursive::
+       This option is only valid for foreach, update and status commands.
+       Traverse submodules recursively. The operation is performed not
+       only in the submodules of the current repo, but also
+       in any nested submodules inside those submodules (and so on).
+
 <path>...::
        Paths to submodule(s). When specified this will restrict the command
        to only operate on the submodules found at the specified paths.
index 1118ce22dcfcbaf190bd7abc60c2b33c213acd06..299b04f726b2e7662fb7db64169726eec82a5c14 100644 (file)
@@ -10,17 +10,15 @@ SYNOPSIS
 --------
 [verse]
 'git tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]
-       <name> [<commit> | <object>]
-'git tag' -d <name>...
+       <tagname> [<commit> | <object>]
+'git tag' -d <tagname>...
 'git tag' [-n[<num>]] -l [--contains <commit>] [<pattern>]
-'git tag' -v <name>...
+'git tag' -v <tagname>...
 
 DESCRIPTION
 -----------
 
-Adds a 'tag' reference in `.git/refs/tags/`.  The tag <name> must pass
-linkgit:git-check-ref-format[1] which basicly means that control characters,
-space, ~, ^, :, ?, *, [ and \ are prohibited.
+Adds a tag reference in `.git/refs/tags/`.
 
 Unless `-f` is given, the tag must not yet exist in
 `.git/refs/tags/` directory.
@@ -53,6 +51,7 @@ OPTIONS
        Make a GPG-signed tag, using the given key
 
 -f::
+--force::
        Replace an existing tag with the given name (instead of failing)
 
 -d::
@@ -88,6 +87,12 @@ OPTIONS
        Implies `-a` if none of `-a`, `-s`, or `-u <key-id>`
        is given.
 
+<tagname>::
+       The name of the tag to create, delete, or describe.
+       The new tag name must pass all checks defined by
+       linkgit:git-check-ref-format[1].  Some of these checks
+       may restrict the characters allowed in a tag name.
+
 CONFIGURATION
 -------------
 By default, 'git-tag' in sign-with-default mode (-s) will use your
@@ -252,6 +257,10 @@ $ GIT_COMMITTER_DATE="2006-10-02 10:31" git tag -s v1.0.1
 ------------
 
 
+SEE ALSO
+--------
+linkgit:git-check-ref-format[1].
+
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org>,
index d791a80819b39b5c3b07ace9d30f16c63f56fd2e..97f7f9165eca2311e4806e9cab8ef18c8c94f7d5 100644 (file)
@@ -25,7 +25,13 @@ OPTIONS
 -v::
 --verbose::
        After verifying the pack, show list of objects contained
-       in the pack.
+       in the pack and a histogram of delta chain length.
+
+-s::
+--stat-only::
+       Do not verify the pack contents; only show the histogram of delta
+       chain length.  With `--verbose`, list of objects is also shown.
+
 \--::
        Do not interpret any more arguments as options.
 
index 26d3850e7317c22dcf0999e0c4a6afe9a5ea2e03..c8899d528adfe37459b9301e16faab90e7a7e63d 100644 (file)
@@ -12,7 +12,8 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Creates a tree object using the current index.
+Creates a tree object using the current index. The name of the new
+tree object is printed to standard output.
 
 The index must be in a fully merged state.
 
index a9bacfbef416ce405fa7ee292728c36cdb87478c..ad44cac71d6e5940bf4739bcafb9acf2d23bc9b0 100644 (file)
@@ -43,9 +43,10 @@ unreleased) version of git, that is available from 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v1.6.4.1/git.html[documentation for release 1.6.4.1]
+* link:v1.6.4.2/git.html[documentation for release 1.6.4.2]
 
 * release notes for
+  link:RelNotes-1.6.4.2.txt[1.6.4.2],
   link:RelNotes-1.6.4.1.txt[1.6.4.1],
   link:RelNotes-1.6.4.txt[1.6.4].
 
index 66eedeff428986e2d5850ac84c98cd0ab7a44081..a614347568b16e7e2526580e7971f22e630ad976 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@ all::
 # when attempting to read from an fopen'ed directory.
 #
 # Define NO_OPENSSL environment variable if you do not have OpenSSL.
-# This also implies MOZILLA_SHA1.
+# This also implies BLK_SHA1.
 #
 # Define NO_CURL if you do not have libcurl installed.  git-http-pull and
 # git-http-push are not built, and you cannot use http:// and https://
@@ -91,14 +91,6 @@ all::
 # Define PPC_SHA1 environment variable when running make to make use of
 # a bundled SHA1 routine optimized for PowerPC.
 #
-# Define ARM_SHA1 environment variable when running make to make use of
-# a bundled SHA1 routine optimized for ARM.
-#
-# Define MOZILLA_SHA1 environment variable when running make to make use of
-# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast
-# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default
-# choice) has very fast version optimized for i586.
-#
 # Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin).
 #
 # Define NEEDS_LIBICONV if linking with libc is not enough (Darwin).
@@ -365,7 +357,6 @@ PROGRAMS += git-patch-id$X
 PROGRAMS += git-shell$X
 PROGRAMS += git-show-index$X
 PROGRAMS += git-unpack-file$X
-PROGRAMS += git-update-server-info$X
 PROGRAMS += git-upload-pack$X
 PROGRAMS += git-var$X
 
@@ -644,6 +635,7 @@ BUILTIN_OBJS += builtin-tar-tree.o
 BUILTIN_OBJS += builtin-unpack-objects.o
 BUILTIN_OBJS += builtin-update-index.o
 BUILTIN_OBJS += builtin-update-ref.o
+BUILTIN_OBJS += builtin-update-server-info.o
 BUILTIN_OBJS += builtin-upload-archive.o
 BUILTIN_OBJS += builtin-verify-pack.o
 BUILTIN_OBJS += builtin-verify-tag.o
@@ -757,9 +749,6 @@ ifeq ($(uname_S),SunOS)
                NO_C99_FORMAT = YesPlease
                NO_STRTOUMAX = YesPlease
        endif
-       ifdef NO_IPV6
-               NEEDS_RESOLV = YesPlease
-       endif
        INSTALL = /usr/ucb/install
        TAR = gtar
        BASIC_CFLAGS += -D__EXTENSIONS__ -D__sun__ -DHAVE_ALLOCA_H
@@ -928,10 +917,6 @@ else
        NO_PTHREADS = YesPlease
 endif
 endif
-ifneq (,$(findstring arm,$(uname_M)))
-       ARM_SHA1 = YesPlease
-       NO_MKSTEMPS = YesPlease
-endif
 
 -include config.mak.autogen
 -include config.mak
@@ -1024,7 +1009,7 @@ ifndef NO_OPENSSL
        endif
 else
        BASIC_CFLAGS += -DNO_OPENSSL
-       MOZILLA_SHA1 = 1
+       BLK_SHA1 = 1
        OPENSSL_LIBSSL =
 endif
 ifdef NEEDS_SSL_WITH_CRYPTO
@@ -1180,21 +1165,11 @@ else
 ifdef PPC_SHA1
        SHA1_HEADER = "ppc/sha1.h"
        LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o
-else
-ifdef ARM_SHA1
-       SHA1_HEADER = "arm/sha1.h"
-       LIB_OBJS += arm/sha1.o arm/sha1_arm.o
-else
-ifdef MOZILLA_SHA1
-       SHA1_HEADER = "mozilla-sha1/sha1.h"
-       LIB_OBJS += mozilla-sha1/sha1.o
 else
        SHA1_HEADER = <openssl/sha.h>
        EXTLIBS += $(LIB_4_CRYPTO)
 endif
 endif
-endif
-endif
 ifdef NO_PERL_MAKEMAKER
        export NO_PERL_MAKEMAKER
 endif
index 4bee0ba1ec6fcf49e88b874f0a415f4220117c0a..b88122cbe73ec0c438e2d375fdebd51e5febf9ae 100644 (file)
--- a/abspath.c
+++ b/abspath.c
@@ -18,7 +18,7 @@ const char *make_absolute_path(const char *path)
 {
        static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
        char cwd[1024] = "";
-       int buf_index = 1, len;
+       int buf_index = 1;
 
        int depth = MAXDEPTH;
        char *last_elem = NULL;
@@ -50,7 +50,7 @@ const char *make_absolute_path(const char *path)
                        die_errno ("Could not get current working directory");
 
                if (last_elem) {
-                       int len = strlen(buf);
+                       size_t len = strlen(buf);
                        if (len + strlen(last_elem) + 2 > PATH_MAX)
                                die ("Too long path name: '%s/%s'",
                                                buf, last_elem);
@@ -61,7 +61,7 @@ const char *make_absolute_path(const char *path)
                }
 
                if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
-                       len = readlink(buf, next_buf, PATH_MAX);
+                       ssize_t len = readlink(buf, next_buf, PATH_MAX);
                        if (len < 0)
                                die_errno ("Invalid symlink '%s'", buf);
                        if (PATH_MAX <= len)
diff --git a/arm/sha1.c b/arm/sha1.c
deleted file mode 100644 (file)
index c61ad4a..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * SHA-1 implementation optimized for ARM
- *
- * Copyright:   (C) 2005 by Nicolas Pitre <nico@cam.org>
- * Created:     September 17, 2005
- */
-
-#include <string.h>
-#include "sha1.h"
-
-extern void arm_sha_transform(uint32_t *hash, const unsigned char *data, uint32_t *W);
-
-void arm_SHA1_Init(arm_SHA_CTX *c)
-{
-       c->len = 0;
-       c->hash[0] = 0x67452301;
-       c->hash[1] = 0xefcdab89;
-       c->hash[2] = 0x98badcfe;
-       c->hash[3] = 0x10325476;
-       c->hash[4] = 0xc3d2e1f0;
-}
-
-void arm_SHA1_Update(arm_SHA_CTX *c, const void *p, unsigned long n)
-{
-       uint32_t workspace[80];
-       unsigned int partial;
-       unsigned long done;
-
-       partial = c->len & 0x3f;
-       c->len += n;
-       if ((partial + n) >= 64) {
-               if (partial) {
-                       done = 64 - partial;
-                       memcpy(c->buffer + partial, p, done);
-                       arm_sha_transform(c->hash, c->buffer, workspace);
-                       partial = 0;
-               } else
-                       done = 0;
-               while (n >= done + 64) {
-                       arm_sha_transform(c->hash, p + done, workspace);
-                       done += 64;
-               }
-       } else
-               done = 0;
-       if (n - done)
-               memcpy(c->buffer + partial, p + done, n - done);
-}
-
-void arm_SHA1_Final(unsigned char *hash, arm_SHA_CTX *c)
-{
-       uint64_t bitlen;
-       uint32_t bitlen_hi, bitlen_lo;
-       unsigned int i, offset, padlen;
-       unsigned char bits[8];
-       static const unsigned char padding[64] = { 0x80, };
-
-       bitlen = c->len << 3;
-       offset = c->len & 0x3f;
-       padlen = ((offset < 56) ? 56 : (64 + 56)) - offset;
-       arm_SHA1_Update(c, padding, padlen);
-
-       bitlen_hi = bitlen >> 32;
-       bitlen_lo = bitlen & 0xffffffff;
-       bits[0] = bitlen_hi >> 24;
-       bits[1] = bitlen_hi >> 16;
-       bits[2] = bitlen_hi >> 8;
-       bits[3] = bitlen_hi;
-       bits[4] = bitlen_lo >> 24;
-       bits[5] = bitlen_lo >> 16;
-       bits[6] = bitlen_lo >> 8;
-       bits[7] = bitlen_lo;
-       arm_SHA1_Update(c, bits, 8);
-
-       for (i = 0; i < 5; i++) {
-               uint32_t v = c->hash[i];
-               hash[0] = v >> 24;
-               hash[1] = v >> 16;
-               hash[2] = v >> 8;
-               hash[3] = v;
-               hash += 4;
-       }
-}
diff --git a/arm/sha1.h b/arm/sha1.h
deleted file mode 100644 (file)
index b61b618..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * SHA-1 implementation optimized for ARM
- *
- * Copyright:  (C) 2005 by Nicolas Pitre <nico@cam.org>
- * Created:    September 17, 2005
- */
-
-#include <stdint.h>
-
-typedef struct {
-       uint64_t len;
-       uint32_t hash[5];
-       unsigned char buffer[64];
-} arm_SHA_CTX;
-
-void arm_SHA1_Init(arm_SHA_CTX *c);
-void arm_SHA1_Update(arm_SHA_CTX *c, const void *p, unsigned long n);
-void arm_SHA1_Final(unsigned char *hash, arm_SHA_CTX *c);
-
-#define git_SHA_CTX    arm_SHA_CTX
-#define git_SHA1_Init  arm_SHA1_Init
-#define git_SHA1_Update        arm_SHA1_Update
-#define git_SHA1_Final arm_SHA1_Final
diff --git a/arm/sha1_arm.S b/arm/sha1_arm.S
deleted file mode 100644 (file)
index 41e9263..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- *  SHA transform optimized for ARM
- *
- *  Copyright: (C) 2005 by Nicolas Pitre <nico@cam.org>
- *  Created:   September 17, 2005
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- */
-
-       .text
-       .globl  arm_sha_transform
-
-/*
- * void sha_transform(uint32_t *hash, const unsigned char *data, uint32_t *W);
- *
- * note: the "data" pointer may be unaligned.
- */
-
-arm_sha_transform:
-
-       stmfd   sp!, {r4 - r8, lr}
-
-       @ for (i = 0; i < 16; i++)
-       @         W[i] = ntohl(((uint32_t *)data)[i]);
-
-#ifdef __ARMEB__
-       mov     r4, r0
-       mov     r0, r2
-       mov     r2, #64
-       bl      memcpy
-       mov     r2, r0
-       mov     r0, r4
-#else
-       mov     r3, r2
-       mov     lr, #16
-1:     ldrb    r4, [r1], #1
-       ldrb    r5, [r1], #1
-       ldrb    r6, [r1], #1
-       ldrb    r7, [r1], #1
-       subs    lr, lr, #1
-       orr     r5, r5, r4, lsl #8
-       orr     r6, r6, r5, lsl #8
-       orr     r7, r7, r6, lsl #8
-       str     r7, [r3], #4
-       bne     1b
-#endif
-
-       @ for (i = 0; i < 64; i++)
-       @         W[i+16] = ror(W[i+13] ^ W[i+8] ^ W[i+2] ^ W[i], 31);
-
-       sub     r3, r2, #4
-       mov     lr, #64
-2:     ldr     r4, [r3, #4]!
-       subs    lr, lr, #1
-       ldr     r5, [r3, #8]
-       ldr     r6, [r3, #32]
-       ldr     r7, [r3, #52]
-       eor     r4, r4, r5
-       eor     r4, r4, r6
-       eor     r4, r4, r7
-       mov     r4, r4, ror #31
-       str     r4, [r3, #64]
-       bne     2b
-
-       /*
-        * The SHA functions are:
-        *
-        * f1(B,C,D) = (D ^ (B & (C ^ D)))
-        * f2(B,C,D) = (B ^ C ^ D)
-        * f3(B,C,D) = ((B & C) | (D & (B | C)))
-        *
-        * Then the sub-blocks are processed as follows:
-        *
-        * A' = ror(A, 27) + f(B,C,D) + E + K + *W++
-        * B' = A
-        * C' = ror(B, 2)
-        * D' = C
-        * E' = D
-        *
-        * We therefore unroll each loop 5 times to avoid register shuffling.
-        * Also the ror for C (and also D and E which are successivelyderived
-        * from it) is applied in place to cut on an additional mov insn for
-        * each round.
-        */
-
-       .macro  sha_f1, A, B, C, D, E
-       ldr     r3, [r2], #4
-       eor     ip, \C, \D
-       add     \E, r1, \E, ror #2
-       and     ip, \B, ip, ror #2
-       add     \E, \E, \A, ror #27
-       eor     ip, ip, \D, ror #2
-       add     \E, \E, r3
-       add     \E, \E, ip
-       .endm
-
-       .macro  sha_f2, A, B, C, D, E
-       ldr     r3, [r2], #4
-       add     \E, r1, \E, ror #2
-       eor     ip, \B, \C, ror #2
-       add     \E, \E, \A, ror #27
-       eor     ip, ip, \D, ror #2
-       add     \E, \E, r3
-       add     \E, \E, ip
-       .endm
-
-       .macro  sha_f3, A, B, C, D, E
-       ldr     r3, [r2], #4
-       add     \E, r1, \E, ror #2
-       orr     ip, \B, \C, ror #2
-       add     \E, \E, \A, ror #27
-       and     ip, ip, \D, ror #2
-       add     \E, \E, r3
-       and     r3, \B, \C, ror #2
-       orr     ip, ip, r3
-       add     \E, \E, ip
-       .endm
-
-       ldmia   r0, {r4 - r8}
-
-       mov     lr, #4
-       ldr     r1, .L_sha_K + 0
-
-       /* adjust initial values */
-       mov     r6, r6, ror #30
-       mov     r7, r7, ror #30
-       mov     r8, r8, ror #30
-
-3:     subs    lr, lr, #1
-       sha_f1  r4, r5, r6, r7, r8
-       sha_f1  r8, r4, r5, r6, r7
-       sha_f1  r7, r8, r4, r5, r6
-       sha_f1  r6, r7, r8, r4, r5
-       sha_f1  r5, r6, r7, r8, r4
-       bne     3b
-
-       ldr     r1, .L_sha_K + 4
-       mov     lr, #4
-
-4:     subs    lr, lr, #1
-       sha_f2  r4, r5, r6, r7, r8
-       sha_f2  r8, r4, r5, r6, r7
-       sha_f2  r7, r8, r4, r5, r6
-       sha_f2  r6, r7, r8, r4, r5
-       sha_f2  r5, r6, r7, r8, r4
-       bne     4b
-
-       ldr     r1, .L_sha_K + 8
-       mov     lr, #4
-
-5:     subs    lr, lr, #1
-       sha_f3  r4, r5, r6, r7, r8
-       sha_f3  r8, r4, r5, r6, r7
-       sha_f3  r7, r8, r4, r5, r6
-       sha_f3  r6, r7, r8, r4, r5
-       sha_f3  r5, r6, r7, r8, r4
-       bne     5b
-
-       ldr     r1, .L_sha_K + 12
-       mov     lr, #4
-
-6:     subs    lr, lr, #1
-       sha_f2  r4, r5, r6, r7, r8
-       sha_f2  r8, r4, r5, r6, r7
-       sha_f2  r7, r8, r4, r5, r6
-       sha_f2  r6, r7, r8, r4, r5
-       sha_f2  r5, r6, r7, r8, r4
-       bne     6b
-
-       ldmia   r0, {r1, r2, r3, ip, lr}
-       add     r4, r1, r4
-       add     r5, r2, r5
-       add     r6, r3, r6, ror #2
-       add     r7, ip, r7, ror #2
-       add     r8, lr, r8, ror #2
-       stmia   r0, {r4 - r8}
-
-       ldmfd   sp!, {r4 - r8, pc}
-
-.L_sha_K:
-       .word   0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6
index 7f20acb4b9e391bd383597ec554ec58b70979fe5..dc18db8af96b093d7cb16eb88d3f738f98dc30f6 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -991,7 +991,7 @@ int bisect_next_all(const char *prefix)
 
        if (!hashcmp(bisect_rev, current_bad_sha1)) {
                exit_if_skipped_commits(tried, current_bad_sha1);
-               printf("%s is first bad commit\n", bisect_rev_hex);
+               printf("%s is the first bad commit\n", bisect_rev_hex);
                show_diff_tree(prefix, revs.commits->item);
                /* This means the bisection process succeeded. */
                exit(10);
index 464cb258aaa11786d3615a55c0ae8dff95150667..d8934757a5e5e259f26c4a09f7ea5d10615df0c1 100644 (file)
@@ -1,15 +1,17 @@
 /*
- * Based on the Mozilla SHA1 (see mozilla-sha1/sha1.c),
- * optimized to do word accesses rather than byte accesses,
+ * SHA1 routine optimized to do word accesses rather than byte accesses,
  * and to avoid unnecessary copies into the context array.
+ *
+ * This was initially based on the Mozilla SHA1 implementation, although
+ * none of the original Mozilla code remains.
  */
 
-#include <string.h>
-#include <arpa/inet.h>
+/* this is only to get definitions for memcpy(), ntohl() and htonl() */
+#include "../git-compat-util.h"
 
 #include "sha1.h"
 
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
 
 /*
  * Force usage of rol or ror by selecting the one with the smaller constant.
@@ -54,7 +56,7 @@
 
 #if defined(__i386__) || defined(__x86_64__)
   #define setW(x, val) (*(volatile unsigned int *)&W(x) = (val))
-#elif defined(__arm__)
+#elif defined(__GNUC__) && defined(__arm__)
   #define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while (0)
 #else
   #define setW(x, val) (W(x) = (val))
index c1ae74d3dab1686a886d145fc0fb9bf4c9b669c9..b864df623e3b89ad678a888dce4b0d4c997f1ac3 100644 (file)
@@ -1,13 +1,15 @@
 /*
- * Based on the Mozilla SHA1 (see mozilla-sha1/sha1.h),
- * optimized to do word accesses rather than byte accesses,
+ * SHA1 routine optimized to do word accesses rather than byte accesses,
  * and to avoid unnecessary copies into the context array.
+ *
+ * This was initially based on the Mozilla SHA1 implementation, although
+ * none of the original Mozilla code remains.
  */
 
 typedef struct {
+       unsigned long long size;
        unsigned int H[5];
        unsigned int W[16];
-       unsigned long long size;
 } blk_SHA_CTX;
 
 void blk_SHA1_Init(blk_SHA_CTX *ctx);
index 581a2a17480cc0ffa47a942ff58da4499aeac41d..006fd08769dcf01c20b0c23dd7cf6c4aae931c68 100644 (file)
@@ -105,8 +105,8 @@ static void refresh(int verbose, const char **pathspec)
        for (specs = 0; pathspec[specs];  specs++)
                /* nothing */;
        seen = xcalloc(specs, 1);
-       refresh_index(&the_index, verbose ? REFRESH_SAY_CHANGED : REFRESH_QUIET,
-                     pathspec, seen);
+       refresh_index(&the_index, verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET,
+                     pathspec, seen, "Unstaged changes after refreshing the index:");
        for (i = 0; i < specs; i++) {
                if (!seen[i])
                        die("pathspec '%s' did not match any files", pathspec[i]);
index 1a03d5f356009de12364c320577e24853bec7959..9f57992062314a3d8d168b5cfb6b3c6737605033 100644 (file)
@@ -586,7 +586,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                OPT_BIT('m', NULL, &rename, "move/rename a branch and its reflog", 1),
                OPT_BIT('M', NULL, &rename, "move/rename a branch, even if target exists", 2),
                OPT_BOOLEAN('l', NULL, &reflog, "create the branch's reflog"),
-               OPT_BOOLEAN('f', NULL, &force_create, "force creation (when already exists)"),
+               OPT_BOOLEAN('f', "force", &force_create, "force creation (when already exists)"),
                {
                        OPTION_CALLBACK, 0, "no-merged", &merge_filter_ref,
                        "commit", "print only not merged branches",
index 8a9a474218c128b7878647045ba471df9902636a..36e2116ea2020049aec660b0b10628152618c9cc 100644 (file)
@@ -402,7 +402,9 @@ static int merge_working_tree(struct checkout_opts *opts,
                topts.dir = xcalloc(1, sizeof(*topts.dir));
                topts.dir->flags |= DIR_SHOW_IGNORED;
                topts.dir->exclude_per_dir = ".gitignore";
-               tree = parse_tree_indirect(old->commit->object.sha1);
+               tree = parse_tree_indirect(old->commit ?
+                                          old->commit->object.sha1 :
+                                          (unsigned char *)EMPTY_TREE_SHA1_BIN);
                init_tree_desc(&trees[0], tree->buffer, tree->size);
                tree = parse_tree_indirect(new->commit->object.sha1);
                init_tree_desc(&trees[1], tree->buffer, tree->size);
@@ -541,14 +543,6 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
                parse_commit(new->commit);
        }
 
-       if (!old.commit && !opts->force) {
-               if (!opts->quiet) {
-                       warning("You appear to be on a branch yet to be born.");
-                       warning("Forcing checkout of %s.", new->name);
-               }
-               opts->force = 1;
-       }
-
        ret = merge_working_tree(opts, &old, new);
        if (ret)
                return ret;
@@ -590,7 +584,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                            2),
                OPT_SET_INT('3', "theirs", &opts.writeout_stage, "stage",
                            3),
-               OPT_BOOLEAN('f', NULL, &opts.force, "force"),
+               OPT_BOOLEAN('f', "force", &opts.force, "force"),
                OPT_BOOLEAN('m', "merge", &opts.merge, "merge"),
                OPT_STRING(0, "conflict", &conflict_style, "style",
                           "conflict style (merge or diff3)"),
index 05c763cbec61cd41bde3b424c22563c155105fd0..28cdcd0274dd5891c7ad3dc3804cb0acead883f2 100644 (file)
@@ -41,7 +41,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
        struct option options[] = {
                OPT__QUIET(&quiet),
                OPT__DRY_RUN(&show_only),
-               OPT_BOOLEAN('f', NULL, &force, "force"),
+               OPT_BOOLEAN('f', "force", &force, "force"),
                OPT_BOOLEAN('d', NULL, &remove_directories,
                                "remove whole directories"),
                OPT_BOOLEAN('x', NULL, &ignored, "remove ignored files, too"),
index 32dea74d78381ca1dffdac7f88e45a89a9825104..0d2b4a8200ec10b2f6972cc3b7ddbb7a5b833b54 100644 (file)
@@ -38,7 +38,7 @@ static const char * const builtin_clone_usage[] = {
 };
 
 static int option_quiet, option_no_checkout, option_bare, option_mirror;
-static int option_local, option_no_hardlinks, option_shared;
+static int option_local, option_no_hardlinks, option_shared, option_recursive;
 static char *option_template, *option_reference, *option_depth;
 static char *option_origin = NULL;
 static char *option_upload_pack = "git-upload-pack";
@@ -59,6 +59,8 @@ static struct option builtin_clone_options[] = {
                    "don't use local hardlinks, always copy"),
        OPT_BOOLEAN('s', "shared", &option_shared,
                    "setup as shared repository"),
+       OPT_BOOLEAN(0, "recursive", &option_recursive,
+                   "setup as shared repository"),
        OPT_STRING(0, "template", &option_template, "path",
                   "path the template repository"),
        OPT_STRING(0, "reference", &option_reference, "repo",
@@ -73,6 +75,10 @@ static struct option builtin_clone_options[] = {
        OPT_END()
 };
 
+static const char *argv_submodule[] = {
+       "submodule", "update", "--init", "--recursive", NULL
+};
+
 static char *get_repo_path(const char *repo, int *is_bundle)
 {
        static char *suffix[] = { "/.git", ".git", "" };
@@ -608,6 +614,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 
                err |= run_hook(NULL, "post-checkout", sha1_to_hex(null_sha1),
                                sha1_to_hex(remote_head->old_sha1), "1", NULL);
+
+               if (!err && option_recursive)
+                       err = run_command_v_opt(argv_submodule, RUN_GIT_CMD);
        }
 
        strbuf_release(&reflog_msg);
index 4bcce06fbffdf10ec701dfbc0b6b90a11513f89e..200ffdaad4226ae2021c86ae4b7a2f8ccefb3600 100644 (file)
@@ -51,7 +51,7 @@ static const char *template_file;
 static char *edit_message, *use_message;
 static char *author_name, *author_email, *author_date;
 static int all, edit_flag, also, interactive, only, amend, signoff;
-static int quiet, verbose, no_verify, allow_empty;
+static int quiet, verbose, no_verify, allow_empty, dry_run;
 static char *untracked_files_arg;
 /*
  * The default commit message cleanup mode will remove the lines
@@ -103,6 +103,7 @@ static struct option builtin_commit_options[] = {
        OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"),
        OPT_BOOLEAN('o', "only", &only, "commit only specified files"),
        OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"),
+       OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"),
        OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
        { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
        OPT_BOOLEAN(0, "allow-empty", &allow_empty, "ok to record an empty change"),
@@ -217,12 +218,15 @@ static void create_base_index(void)
                exit(128); /* We've already reported the error, finish dying */
 }
 
-static char *prepare_index(int argc, const char **argv, const char *prefix)
+static char *prepare_index(int argc, const char **argv, const char *prefix, int is_status)
 {
        int fd;
        struct string_list partial;
        const char **pathspec = NULL;
+       int refresh_flags = REFRESH_QUIET;
 
+       if (is_status)
+               refresh_flags |= REFRESH_UNMERGED;
        if (interactive) {
                if (interactive_add(argc, argv, prefix) != 0)
                        die("interactive add failed");
@@ -253,7 +257,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
        if (all || (also && pathspec && *pathspec)) {
                int fd = hold_locked_index(&index_lock, 1);
                add_files_to_cache(also ? prefix : NULL, pathspec, 0);
-               refresh_cache(REFRESH_QUIET);
+               refresh_cache(refresh_flags);
                if (write_cache(fd, active_cache, active_nr) ||
                    close_lock_file(&index_lock))
                        die("unable to write new_index file");
@@ -272,7 +276,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
         */
        if (!pathspec || !*pathspec) {
                fd = hold_locked_index(&index_lock, 1);
-               refresh_cache(REFRESH_QUIET);
+               refresh_cache(refresh_flags);
                if (write_cache(fd, active_cache, active_nr) ||
                    commit_locked_index(&index_lock))
                        die("unable to write new_index file");
@@ -339,27 +343,24 @@ static char *prepare_index(int argc, const char **argv, const char *prefix)
        return false_lock.filename;
 }
 
-static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn)
+static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn,
+                     struct wt_status *s)
 {
-       struct wt_status s;
-
-       wt_status_prepare(&s);
-       if (wt_status_relative_paths)
-               s.prefix = prefix;
+       if (s->relative_paths)
+               s->prefix = prefix;
 
        if (amend) {
-               s.amend = 1;
-               s.reference = "HEAD^1";
+               s->amend = 1;
+               s->reference = "HEAD^1";
        }
-       s.verbose = verbose;
-       s.untracked = (show_untracked_files == SHOW_ALL_UNTRACKED_FILES);
-       s.index_file = index_file;
-       s.fp = fp;
-       s.nowarn = nowarn;
+       s->verbose = verbose;
+       s->index_file = index_file;
+       s->fp = fp;
+       s->nowarn = nowarn;
 
-       wt_status_print(&s);
+       wt_status_print(s);
 
-       return s.commitable;
+       return s->commitable;
 }
 
 static int is_a_merge(const unsigned char *sha1)
@@ -413,7 +414,8 @@ static void determine_author_info(void)
        author_date = date;
 }
 
-static int prepare_to_commit(const char *index_file, const char *prefix)
+static int prepare_to_commit(const char *index_file, const char *prefix,
+                            struct wt_status *s)
 {
        struct stat statbuf;
        int commitable, saved_color_setting;
@@ -555,10 +557,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
                if (ident_shown)
                        fprintf(fp, "#\n");
 
-               saved_color_setting = wt_status_use_color;
-               wt_status_use_color = 0;
-               commitable = run_status(fp, index_file, prefix, 1);
-               wt_status_use_color = saved_color_setting;
+               saved_color_setting = s->use_color;
+               s->use_color = 0;
+               commitable = run_status(fp, index_file, prefix, 1, s);
+               s->use_color = saved_color_setting;
        } else {
                unsigned char sha1[20];
                const char *parent = "HEAD";
@@ -579,7 +581,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix)
 
        if (!commitable && !in_merge && !allow_empty &&
            !(amend && is_a_merge(head_sha1))) {
-               run_status(stdout, index_file, prefix, 0);
+               run_status(stdout, index_file, prefix, 0, s);
                return 0;
        }
 
@@ -691,7 +693,8 @@ static const char *find_author_by_nickname(const char *name)
 
 static int parse_and_validate_options(int argc, const char *argv[],
                                      const char * const usage[],
-                                     const char *prefix)
+                                     const char *prefix,
+                                     struct wt_status *s)
 {
        int f = 0;
 
@@ -794,11 +797,11 @@ static int parse_and_validate_options(int argc, const char *argv[],
        if (!untracked_files_arg)
                ; /* default already initialized */
        else if (!strcmp(untracked_files_arg, "no"))
-               show_untracked_files = SHOW_NO_UNTRACKED_FILES;
+               s->show_untracked_files = SHOW_NO_UNTRACKED_FILES;
        else if (!strcmp(untracked_files_arg, "normal"))
-               show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
+               s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
        else if (!strcmp(untracked_files_arg, "all"))
-               show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
+               s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
        else
                die("Invalid untracked files mode '%s'", untracked_files_arg);
 
@@ -810,28 +813,93 @@ static int parse_and_validate_options(int argc, const char *argv[],
        return argc;
 }
 
-int cmd_status(int argc, const char **argv, const char *prefix)
+static int dry_run_commit(int argc, const char **argv, const char *prefix,
+                         struct wt_status *s)
 {
-       const char *index_file;
        int commitable;
+       const char *index_file;
 
-       git_config(git_status_config, NULL);
+       index_file = prepare_index(argc, argv, prefix, 1);
+       commitable = run_status(stdout, index_file, prefix, 0, s);
+       rollback_index_files();
 
-       if (wt_status_use_color == -1)
-               wt_status_use_color = git_use_color_default;
+       return commitable ? 0 : 1;
+}
 
-       if (diff_use_color_default == -1)
-               diff_use_color_default = git_use_color_default;
+static int parse_status_slot(const char *var, int offset)
+{
+       if (!strcasecmp(var+offset, "header"))
+               return WT_STATUS_HEADER;
+       if (!strcasecmp(var+offset, "updated")
+               || !strcasecmp(var+offset, "added"))
+               return WT_STATUS_UPDATED;
+       if (!strcasecmp(var+offset, "changed"))
+               return WT_STATUS_CHANGED;
+       if (!strcasecmp(var+offset, "untracked"))
+               return WT_STATUS_UNTRACKED;
+       if (!strcasecmp(var+offset, "nobranch"))
+               return WT_STATUS_NOBRANCH;
+       if (!strcasecmp(var+offset, "unmerged"))
+               return WT_STATUS_UNMERGED;
+       die("bad config variable '%s'", var);
+}
 
-       argc = parse_and_validate_options(argc, argv, builtin_status_usage, prefix);
+static int git_status_config(const char *k, const char *v, void *cb)
+{
+       struct wt_status *s = cb;
 
-       index_file = prepare_index(argc, argv, prefix);
+       if (!strcmp(k, "status.submodulesummary")) {
+               int is_bool;
+               s->submodule_summary = git_config_bool_or_int(k, v, &is_bool);
+               if (is_bool && s->submodule_summary)
+                       s->submodule_summary = -1;
+               return 0;
+       }
+       if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) {
+               s->use_color = git_config_colorbool(k, v, -1);
+               return 0;
+       }
+       if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) {
+               int slot = parse_status_slot(k, 13);
+               if (!v)
+                       return config_error_nonbool(k);
+               color_parse(v, k, s->color_palette[slot]);
+               return 0;
+       }
+       if (!strcmp(k, "status.relativepaths")) {
+               s->relative_paths = git_config_bool(k, v);
+               return 0;
+       }
+       if (!strcmp(k, "status.showuntrackedfiles")) {
+               if (!v)
+                       return config_error_nonbool(k);
+               else if (!strcmp(v, "no"))
+                       s->show_untracked_files = SHOW_NO_UNTRACKED_FILES;
+               else if (!strcmp(v, "normal"))
+                       s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
+               else if (!strcmp(v, "all"))
+                       s->show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
+               else
+                       return error("Invalid untracked files mode '%s'", v);
+               return 0;
+       }
+       return git_diff_ui_config(k, v, NULL);
+}
 
-       commitable = run_status(stdout, index_file, prefix, 0);
+int cmd_status(int argc, const char **argv, const char *prefix)
+{
+       struct wt_status s;
 
-       rollback_index_files();
+       wt_status_prepare(&s);
+       git_config(git_status_config, &s);
+       if (s.use_color == -1)
+               s.use_color = git_use_color_default;
+       if (diff_use_color_default == -1)
+               diff_use_color_default = git_use_color_default;
 
-       return commitable ? 0 : 1;
+       argc = parse_and_validate_options(argc, argv, builtin_status_usage,
+                                         prefix, &s);
+       return dry_run_commit(argc, argv, prefix, &s);
 }
 
 static void print_summary(const char *prefix, const unsigned char *sha1)
@@ -883,10 +951,12 @@ static void print_summary(const char *prefix, const unsigned char *sha1)
 
 static int git_commit_config(const char *k, const char *v, void *cb)
 {
+       struct wt_status *s = cb;
+
        if (!strcmp(k, "commit.template"))
                return git_config_string(&template_file, k, v);
 
-       return git_status_config(k, v, cb);
+       return git_status_config(k, v, s);
 }
 
 int cmd_commit(int argc, const char **argv, const char *prefix)
@@ -899,19 +969,26 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        struct commit_list *parents = NULL, **pptr = &parents;
        struct stat statbuf;
        int allow_fast_forward = 1;
+       struct wt_status s;
 
-       git_config(git_commit_config, NULL);
-
-       if (wt_status_use_color == -1)
-               wt_status_use_color = git_use_color_default;
+       wt_status_prepare(&s);
+       git_config(git_commit_config, &s);
 
-       argc = parse_and_validate_options(argc, argv, builtin_commit_usage, prefix);
+       if (s.use_color == -1)
+               s.use_color = git_use_color_default;
 
-       index_file = prepare_index(argc, argv, prefix);
+       argc = parse_and_validate_options(argc, argv, builtin_commit_usage,
+                                         prefix, &s);
+       if (dry_run) {
+               if (diff_use_color_default == -1)
+                       diff_use_color_default = git_use_color_default;
+               return dry_run_commit(argc, argv, prefix, &s);
+       }
+       index_file = prepare_index(argc, argv, prefix, 0);
 
        /* Set up everything for writing the commit object.  This includes
           running hooks, writing the trees, and interacting with the user.  */
-       if (!prepare_to_commit(index_file, prefix)) {
+       if (!prepare_to_commit(index_file, prefix, &s)) {
                rollback_index_files();
                return 1;
        }
index 82236c531bb3c70875285467cbd775fec27c939e..25e21ed41534c8c3067c2e0d5afe4284faa2881a 100644 (file)
@@ -35,6 +35,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
                      struct rev_info *rev)
 {
        int i;
+       int decoration_style = 0;
 
        rev->abbrev = DEFAULT_ABBREV;
        rev->commit_format = CMIT_FMT_DEFAULT;
@@ -61,8 +62,15 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
                if (!strcmp(arg, "--decorate")) {
-                       load_ref_decorations();
-                       rev->show_decorations = 1;
+                       decoration_style = DECORATE_SHORT_REFS;
+               } else if (!prefixcmp(arg, "--decorate=")) {
+                       const char *v = skip_prefix(arg, "--decorate=");
+                       if (!strcmp(v, "full"))
+                               decoration_style = DECORATE_FULL_REFS;
+                       else if (!strcmp(v, "short"))
+                               decoration_style = DECORATE_SHORT_REFS;
+                       else
+                               die("invalid --decorate option: %s", arg);
                } else if (!strcmp(arg, "--source")) {
                        rev->show_source = 1;
                } else if (!strcmp(arg, "-h")) {
@@ -70,6 +78,10 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
                } else
                        die("unrecognized argument: %s", arg);
        }
+       if (decoration_style) {
+               rev->show_decorations = 1;
+               load_ref_decorations(decoration_style);
+       }
 }
 
 /*
index b592c367b2cc016a50db6d49948e9efbbf0e8f2f..1b20028c67dec2f9954cb107620bd863b4b3a264 100644 (file)
@@ -53,7 +53,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
        int verbose = 0, show_only = 0, force = 0, ignore_errors = 0;
        struct option builtin_mv_options[] = {
                OPT__DRY_RUN(&show_only),
-               OPT_BOOLEAN('f', NULL, &force, "force move/rename even if target exists"),
+               OPT_BOOLEAN('f', "force", &force, "force move/rename even if target exists"),
                OPT_BOOLEAN('k', NULL, &ignore_errors, "skip move/rename errors"),
                OPT_END(),
        };
index 9c2d634d6d04c3ce08e1352adcba31b527fc08b1..14c836b1693317d5d834606e5613d7ceacb3189c 100644 (file)
@@ -113,13 +113,15 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
        argc = parse_options(argc, argv, unused_prefix, read_tree_options,
                             read_tree_usage, 0);
 
-       if (read_cache_unmerged() && (opts.prefix || opts.merge))
-               die("You need to resolve your current index first");
-
        prefix_set = opts.prefix ? 1 : 0;
        if (1 < opts.merge + opts.reset + prefix_set)
                die("Which one? -m, --reset, or --prefix?");
-       stage = opts.merge = (opts.reset || opts.merge || prefix_set);
+
+       if (opts.reset || opts.merge || opts.prefix) {
+               if (read_cache_unmerged() && (opts.prefix || opts.merge))
+                       die("You need to resolve your current index first");
+               stage = opts.merge = 1;
+       }
 
        for (i = 0; i < argc; i++) {
                const char *arg = argv[i];
index 5fa1789d0c2b90ef9ee83d091b67292f2ff0db26..0fc0b0743f946dcfbab0257f9c69963a779ed38d 100644 (file)
@@ -108,7 +108,8 @@ static int update_index_refresh(int fd, struct lock_file *index_lock, int flags)
        if (read_cache() < 0)
                return error("Could not read index");
 
-       result = refresh_cache(flags) ? 1 : 0;
+       result = refresh_index(&the_index, (flags), NULL, NULL,
+                              "Unstaged changes after reset:") ? 1 : 0;
        if (write_cache(fd, active_cache, active_nr) ||
                        commit_locked_index(index_lock))
                return error ("Could not refresh index");
@@ -261,7 +262,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
                        die("Cannot do %s reset with paths.",
                                        reset_type_names[reset_type]);
                return read_from_tree(prefix, argv + i, sha1,
-                               quiet ? REFRESH_QUIET : REFRESH_SAY_CHANGED);
+                               quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN);
        }
        if (reset_type == NONE)
                reset_type = MIXED; /* by default */
@@ -302,7 +303,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
                break;
        case MIXED: /* Report what has not been updated. */
                update_index_refresh(0, NULL,
-                               quiet ? REFRESH_QUIET : REFRESH_SAY_CHANGED);
+                               quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN);
                break;
        }
 
index a51a6d1ea21412f151238e48984bc13110fcbc6c..c4790185ebb9979a6772cf7159d16c2a1deeeaf3 100644 (file)
@@ -390,7 +390,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
                OPT_BOOLEAN('s', NULL, &sign, "annotated and GPG-signed tag"),
                OPT_STRING('u', NULL, &keyid, "key-id",
                                        "use another key to sign the tag"),
-               OPT_BOOLEAN('f', NULL, &force, "replace the tag if exists"),
+               OPT_BOOLEAN('f', "force", &force, "replace the tag if exists"),
 
                OPT_GROUP("Tag listing options"),
                {
index 968fda7219807de9985c06eccd0812da04a149ae..685566e0b5e458c510fdf989744d63dda29e28f0 100644 (file)
@@ -181,10 +181,10 @@ static void write_cached_object(struct object *obj)
 static int check_object(struct object *obj, int type, void *data)
 {
        if (!obj)
-               return 0;
+               return 1;
 
        if (obj->flags & FLAG_WRITTEN)
-               return 1;
+               return 0;
 
        if (type != OBJ_ANY && obj->type != type)
                die("object type mismatch");
@@ -195,22 +195,24 @@ static int check_object(struct object *obj, int type, void *data)
                if (type != obj->type || type <= 0)
                        die("object of unexpected type");
                obj->flags |= FLAG_WRITTEN;
-               return 1;
+               return 0;
        }
 
        if (fsck_object(obj, 1, fsck_error_function))
                die("Error in object");
-       if (!fsck_walk(obj, check_object, NULL))
+       if (fsck_walk(obj, check_object, NULL))
                die("Error on reachable objects of %s", sha1_to_hex(obj->sha1));
        write_cached_object(obj);
-       return 1;
+       return 0;
 }
 
 static void write_rest(void)
 {
        unsigned i;
-       for (i = 0; i < nr_objects; i++)
-               check_object(obj_list[i].obj, OBJ_ANY, NULL);
+       for (i = 0; i < nr_objects; i++) {
+               if (obj_list[i].obj)
+                       check_object(obj_list[i].obj, OBJ_ANY, NULL);
+       }
 }
 
 static void added_object(unsigned nr, enum object_type type,
diff --git a/builtin-update-server-info.c b/builtin-update-server-info.c
new file mode 100644 (file)
index 0000000..2b3fddc
--- /dev/null
@@ -0,0 +1,25 @@
+#include "cache.h"
+#include "builtin.h"
+#include "parse-options.h"
+
+static const char * const update_server_info_usage[] = {
+       "git update-server-info [--force]",
+       NULL
+};
+
+int cmd_update_server_info(int argc, const char **argv, const char *prefix)
+{
+       int force = 0;
+       struct option options[] = {
+               OPT_BOOLEAN('f', "force", &force,
+                       "update the info files from scratch"),
+               OPT_END()
+       };
+
+       argc = parse_options(argc, argv, prefix, options,
+                            update_server_info_usage, 0);
+       if (argc > 0)
+               usage_with_options(update_server_info_usage, options);
+
+       return !!update_server_info(force);
+}
index b5bd28e9598ab63696f241511f3a9cc032dbed60..b6079ae6cb03c7f3112c6eebc8c9a012d690a125 100644 (file)
@@ -6,10 +6,14 @@
 
 #define MAX_CHAIN 50
 
-static void show_pack_info(struct packed_git *p)
+#define VERIFY_PACK_VERBOSE 01
+#define VERIFY_PACK_STAT_ONLY 02
+
+static void show_pack_info(struct packed_git *p, unsigned int flags)
 {
        uint32_t nr_objects, i;
        int cnt;
+       int stat_only = flags & VERIFY_PACK_STAT_ONLY;
        unsigned long chain_histogram[MAX_CHAIN+1], baseobjects;
 
        nr_objects = p->num_objects;
@@ -32,16 +36,19 @@ static void show_pack_info(struct packed_git *p)
                type = packed_object_info_detail(p, offset, &size, &store_size,
                                                 &delta_chain_length,
                                                 base_sha1);
-               printf("%s ", sha1_to_hex(sha1));
+               if (!stat_only)
+                       printf("%s ", sha1_to_hex(sha1));
                if (!delta_chain_length) {
-                       printf("%-6s %lu %lu %"PRIuMAX"\n",
-                              type, size, store_size, (uintmax_t)offset);
+                       if (!stat_only)
+                               printf("%-6s %lu %lu %"PRIuMAX"\n",
+                                      type, size, store_size, (uintmax_t)offset);
                        baseobjects++;
                }
                else {
-                       printf("%-6s %lu %lu %"PRIuMAX" %u %s\n",
-                              type, size, store_size, (uintmax_t)offset,
-                              delta_chain_length, sha1_to_hex(base_sha1));
+                       if (!stat_only)
+                               printf("%-6s %lu %lu %"PRIuMAX" %u %s\n",
+                                      type, size, store_size, (uintmax_t)offset,
+                                      delta_chain_length, sha1_to_hex(base_sha1));
                        if (delta_chain_length <= MAX_CHAIN)
                                chain_histogram[delta_chain_length]++;
                        else
@@ -66,10 +73,12 @@ static void show_pack_info(struct packed_git *p)
                       chain_histogram[0] > 1 ? "s" : "");
 }
 
-static int verify_one_pack(const char *path, int verbose)
+static int verify_one_pack(const char *path, unsigned int flags)
 {
        char arg[PATH_MAX];
        int len;
+       int verbose = flags & VERIFY_PACK_VERBOSE;
+       int stat_only = flags & VERIFY_PACK_STAT_ONLY;
        struct packed_git *pack;
        int err;
 
@@ -105,14 +114,19 @@ static int verify_one_pack(const char *path, int verbose)
                return error("packfile %s not found.", arg);
 
        install_packed_git(pack);
-       err = verify_pack(pack);
 
-       if (verbose) {
+       if (!stat_only)
+               err = verify_pack(pack);
+       else
+               err = open_pack_index(pack);
+
+       if (verbose || stat_only) {
                if (err)
                        printf("%s: bad\n", pack->pack_name);
                else {
-                       show_pack_info(pack);
-                       printf("%s: ok\n", pack->pack_name);
+                       show_pack_info(pack, flags);
+                       if (!stat_only)
+                               printf("%s: ok\n", pack->pack_name);
                }
        }
 
@@ -120,17 +134,20 @@ static int verify_one_pack(const char *path, int verbose)
 }
 
 static const char * const verify_pack_usage[] = {
-       "git verify-pack [-v|--verbose] <pack>...",
+       "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>...",
        NULL
 };
 
 int cmd_verify_pack(int argc, const char **argv, const char *prefix)
 {
        int err = 0;
-       int verbose = 0;
+       unsigned int flags = 0;
        int i;
        const struct option verify_pack_options[] = {
-               OPT__VERBOSE(&verbose),
+               OPT_BIT('v', "verbose", &flags, "verbose",
+                       VERIFY_PACK_VERBOSE),
+               OPT_BIT('s', "stat-only", &flags, "show statistics only",
+                       VERIFY_PACK_STAT_ONLY),
                OPT_END()
        };
 
@@ -140,7 +157,7 @@ int cmd_verify_pack(int argc, const char **argv, const char *prefix)
        if (argc < 1)
                usage_with_options(verify_pack_usage, verify_pack_options);
        for (i = 0; i < argc; i++) {
-               if (verify_one_pack(argv[i], verbose))
+               if (verify_one_pack(argv[i], flags))
                        err = 1;
                discard_revindex();
        }
index 51e4ba7f360338e5cd666c01c2f3b8c31e9b5a3e..a2174dc855ad89e486c57ae1c3a458cb1572edbb 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -102,6 +102,7 @@ extern int cmd_tar_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_unpack_objects(int argc, const char **argv, const char *prefix);
 extern int cmd_update_index(int argc, const char **argv, const char *prefix);
 extern int cmd_update_ref(int argc, const char **argv, const char *prefix);
+extern int cmd_update_server_info(int argc, const char **argv, const char *prefix);
 extern int cmd_upload_archive(int argc, const char **argv, const char *prefix);
 extern int cmd_upload_tar(int argc, const char **argv, const char *prefix);
 extern int cmd_verify_tag(int argc, const char **argv, const char *prefix);
diff --git a/cache.h b/cache.h
index cd5aa89ca90c6405a9f4872d139b053880cff06b..5fad24ce219be746ad582d8432464753975f34fe 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -330,7 +330,7 @@ static inline void remove_name_hash(struct cache_entry *ce)
 #define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))
 #define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags))
 #define add_file_to_cache(path, flags) add_file_to_index(&the_index, (path), (flags))
-#define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL)
+#define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL, NULL)
 #define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options))
 #define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
 #define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase))
@@ -469,15 +469,15 @@ extern int index_path(unsigned char *sha1, const char *path, struct stat *st, in
 extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
 
 /* "careful lstat()" */
-extern int check_path(const char *path, int len, struct stat *st);
+extern int check_path(const char *path, int len, struct stat *st, int skiplen);
 
 #define REFRESH_REALLY         0x0001  /* ignore_valid */
 #define REFRESH_UNMERGED       0x0002  /* allow unmerged */
 #define REFRESH_QUIET          0x0004  /* be quiet about it */
 #define REFRESH_IGNORE_MISSING 0x0008  /* ignore non-existent */
 #define REFRESH_IGNORE_SUBMODULES      0x0010  /* ignore submodules */
-#define REFRESH_SAY_CHANGED    0x0020  /* say "changed" not "needs update" */
-extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen);
+#define REFRESH_IN_PORCELAIN   0x0020  /* user friendly output, not "needs update" */
+extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen, char *header_msg);
 
 struct lock_file {
        struct lock_file *next;
index e2bcbe814936989e7a86018e46ed6ca86f4c1f10..a6c6f70a9237385d163ea12ef28e5087e9f80411 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -564,13 +564,13 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co
        while (interesting(list)) {
                struct commit *commit;
                struct commit_list *parents;
-               struct commit_list *n;
+               struct commit_list *next;
                int flags;
 
                commit = list->item;
-               n = list->next;
+               next = list->next;
                free(list);
-               list = n;
+               list = next;
 
                flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
                if (flags == (PARENT1 | PARENT2)) {
@@ -598,11 +598,11 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co
        free_commit_list(list);
        list = result; result = NULL;
        while (list) {
-               struct commit_list *n = list->next;
+               struct commit_list *next = list->next;
                if (!(list->item->object.flags & STALE))
                        insert_by_date(list->item, &result);
                free(list);
-               list = n;
+               list = next;
        }
        return result;
 }
diff --git a/compat/bswap.h b/compat/bswap.h
new file mode 100644 (file)
index 0000000..7246a12
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Let's make sure we always have a sane definition for ntohl()/htonl().
+ * Some libraries define those as a function call, just to perform byte
+ * shifting, bringing significant overhead to what should be a simple
+ * operation.
+ */
+
+/*
+ * Default version that the compiler ought to optimize properly with
+ * constant values.
+ */
+static inline unsigned int default_swab32(unsigned int val)
+{
+       return (((val & 0xff000000) >> 24) |
+               ((val & 0x00ff0000) >>  8) |
+               ((val & 0x0000ff00) <<  8) |
+               ((val & 0x000000ff) << 24));
+}
+
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+
+#define bswap32(x) ({ \
+       unsigned int __res; \
+       if (__builtin_constant_p(x)) { \
+               __res = default_swab32(x); \
+       } else { \
+               __asm__("bswap %0" : "=r" (__res) : "0" (x)); \
+       } \
+       __res; })
+
+#undef ntohl
+#undef htonl
+#define ntohl(x) bswap32(x)
+#define htonl(x) bswap32(x)
+
+#endif
index 3f1922d0bf66abdbcad03dfd9981ca5293a4b860..b09b8e446fbd52c55e6966c611b55ac1baa81f32 100644 (file)
@@ -156,19 +156,11 @@ AC_MSG_NOTICE([CHECKS for site configuration])
 # tests.  These tests take up a significant amount of the total test time
 # but are not needed unless you plan to talk to SVN repos.
 #
-# Define MOZILLA_SHA1 environment variable when running make to make use of
-# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast
-# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default
-# choice) has very fast version optimized for i586.
-#
 # Define PPC_SHA1 environment variable when running make to make use of
 # a bundled SHA1 routine optimized for PowerPC.
 #
-# Define ARM_SHA1 environment variable when running make to make use of
-# a bundled SHA1 routine optimized for ARM.
-#
 # Define NO_OPENSSL environment variable if you do not have OpenSSL.
-# This also implies MOZILLA_SHA1.
+# This also implies BLK_SHA1.
 #
 # Define OPENSSLDIR=/foo/bar if your openssl header and library files are in
 # /foo/bar/include and /foo/bar/lib directories.
index 342529db309821f461e8f77d05bc5e01c76802ec..38438f3c4a548f8d45d66c9c207acd67bd598454 100755 (executable)
@@ -201,7 +201,7 @@ def isModeExec(mode):
 def isModeExecChanged(src_mode, dst_mode):
     return isModeExec(src_mode) != isModeExec(dst_mode)
 
-def p4CmdList(cmd, stdin=None, stdin_mode='w+b'):
+def p4CmdList(cmd, stdin=None, stdin_mode='w+b', cb=None):
     cmd = p4_build_cmd("-G %s" % (cmd))
     if verbose:
         sys.stderr.write("Opening pipe: %s\n" % cmd)
@@ -224,7 +224,10 @@ def p4CmdList(cmd, stdin=None, stdin_mode='w+b'):
     try:
         while True:
             entry = marshal.load(p4.stdout)
-            result.append(entry)
+           if cb is not None:
+               cb(entry)
+           else:
+               result.append(entry)
     except EOFError:
         pass
     exitCode = p4.wait()
@@ -950,10 +953,84 @@ class P4Sync(Command):
 
         return branches
 
-    ## Should move this out, doesn't use SELF.
-    def readP4Files(self, files):
+    # output one file from the P4 stream
+    # - helper for streamP4Files
+
+    def streamOneP4File(self, file, contents):
+       if file["type"] == "apple":
+           print "\nfile %s is a strange apple file that forks. Ignoring" % \
+               file['depotFile']
+           return
+
+        relPath = self.stripRepoPath(file['depotFile'], self.branchPrefixes)
+        if verbose:
+            sys.stderr.write("%s\n" % relPath)
+
+        mode = "644"
+        if isP4Exec(file["type"]):
+            mode = "755"
+        elif file["type"] == "symlink":
+            mode = "120000"
+            # p4 print on a symlink contains "target\n", so strip it off
+            last = contents.pop()
+            last = last[:-1]
+            contents.append(last)
+
+        if self.isWindows and file["type"].endswith("text"):
+            mangled = []
+            for data in contents:
+                data = data.replace("\r\n", "\n")
+                mangled.append(data)
+            contents = mangled
+
+        if file['type'] in ('text+ko', 'unicode+ko', 'binary+ko'):
+            contents = map(lambda text: re.sub(r'(?i)\$(Id|Header):[^$]*\$',r'$\1$', text), contents)
+        elif file['type'] in ('text+k', 'ktext', 'kxtext', 'unicode+k', 'binary+k'):
+            contents = map(lambda text: re.sub(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$\n]*\$',r'$\1$', text), contents)
+
+        self.gitStream.write("M %s inline %s\n" % (mode, relPath))
+
+        # total length...
+        length = 0
+        for d in contents:
+            length = length + len(d)
+
+        self.gitStream.write("data %d\n" % length)
+        for d in contents:
+            self.gitStream.write(d)
+        self.gitStream.write("\n")
+
+    def streamOneP4Deletion(self, file):
+        relPath = self.stripRepoPath(file['path'], self.branchPrefixes)
+        if verbose:
+            sys.stderr.write("delete %s\n" % relPath)
+        self.gitStream.write("D %s\n" % relPath)
+
+    # handle another chunk of streaming data
+    def streamP4FilesCb(self, marshalled):
+
+       if marshalled.has_key('depotFile') and self.stream_have_file_info:
+           # start of a new file - output the old one first
+           self.streamOneP4File(self.stream_file, self.stream_contents)
+           self.stream_file = {}
+           self.stream_contents = []
+           self.stream_have_file_info = False
+
+       # pick up the new file information... for the
+       # 'data' field we need to append to our array
+       for k in marshalled.keys():
+           if k == 'data':
+               self.stream_contents.append(marshalled['data'])
+           else:
+               self.stream_file[k] = marshalled[k]
+
+       self.stream_have_file_info = True
+
+    # Stream directly from "p4 files" into "git fast-import"
+    def streamP4Files(self, files):
         filesForCommit = []
         filesToRead = []
+        filesToDelete = []
 
         for f in files:
             includeFile = True
@@ -967,50 +1044,35 @@ class P4Sync(Command):
                 filesForCommit.append(f)
                 if f['action'] not in ('delete', 'purge'):
                     filesToRead.append(f)
+                else:
+                    filesToDelete.append(f)
 
-        filedata = []
-        if len(filesToRead) > 0:
-            filedata = p4CmdList('-x - print',
-                                 stdin='\n'.join(['%s#%s' % (f['path'], f['rev'])
-                                                  for f in filesToRead]),
-                                 stdin_mode='w+')
-
-            if "p4ExitCode" in filedata[0]:
-                die("Problems executing p4. Error: [%d]."
-                    % (filedata[0]['p4ExitCode']));
-
-        j = 0;
-        contents = {}
-        while j < len(filedata):
-            stat = filedata[j]
-            j += 1
-            text = ''
-            while j < len(filedata) and filedata[j]['code'] in ('text', 'unicode', 'binary'):
-                text += filedata[j]['data']
-                del filedata[j]['data']
-                j += 1
-
-            if not stat.has_key('depotFile'):
-                sys.stderr.write("p4 print fails with: %s\n" % repr(stat))
-                continue
+        # deleted files...
+        for f in filesToDelete:
+            self.streamOneP4Deletion(f)
 
-            if stat['type'] in ('text+ko', 'unicode+ko', 'binary+ko'):
-                text = re.sub(r'(?i)\$(Id|Header):[^$]*\$',r'$\1$', text)
-            elif stat['type'] in ('text+k', 'ktext', 'kxtext', 'unicode+k', 'binary+k'):
-                text = re.sub(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$\n]*\$',r'$\1$', text)
+        if len(filesToRead) > 0:
+            self.stream_file = {}
+            self.stream_contents = []
+            self.stream_have_file_info = False
 
-            contents[stat['depotFile']] = text
+           # curry self argument
+           def streamP4FilesCbSelf(entry):
+               self.streamP4FilesCb(entry)
 
-        for f in filesForCommit:
-            path = f['path']
-            if contents.has_key(path):
-                f['data'] = contents[path]
+           p4CmdList("-x - print",
+               '\n'.join(['%s#%s' % (f['path'], f['rev'])
+                                                  for f in filesToRead]),
+               cb=streamP4FilesCbSelf)
 
-        return filesForCommit
+            # do the last chunk
+            if self.stream_file.has_key('depotFile'):
+                self.streamOneP4File(self.stream_file, self.stream_contents)
 
     def commit(self, details, files, branch, branchPrefixes, parent = ""):
         epoch = details["time"]
         author = details["user"]
+       self.branchPrefixes = branchPrefixes
 
         if self.verbose:
             print "commit into %s" % branch
@@ -1023,7 +1085,6 @@ class P4Sync(Command):
                 new_files.append (f)
             else:
                 sys.stderr.write("Ignoring file outside of prefix: %s\n" % path)
-        files = self.readP4Files(new_files)
 
         self.gitStream.write("commit %s\n" % branch)
 #        gitStream.write("mark :%s\n" % details["change"])
@@ -1051,33 +1112,7 @@ class P4Sync(Command):
                 print "parent %s" % parent
             self.gitStream.write("from %s\n" % parent)
 
-        for file in files:
-            if file["type"] == "apple":
-                print "\nfile %s is a strange apple file that forks. Ignoring!" % file['path']
-                continue
-
-            relPath = self.stripRepoPath(file['path'], branchPrefixes)
-            if file["action"] in ("delete", "purge"):
-                self.gitStream.write("D %s\n" % relPath)
-            else:
-                data = file['data']
-
-                mode = "644"
-                if isP4Exec(file["type"]):
-                    mode = "755"
-                elif file["type"] == "symlink":
-                    mode = "120000"
-                    # p4 print on a symlink contains "target\n", so strip it off
-                    data = data[:-1]
-
-                if self.isWindows and file["type"].endswith("text"):
-                    data = data.replace("\r\n", "\n")
-
-                self.gitStream.write("M %s inline %s\n" % (mode, relPath))
-                self.gitStream.write("data %s\n" % len(data))
-                self.gitStream.write(data)
-                self.gitStream.write("\n")
-
+        self.streamP4Files(new_files)
         self.gitStream.write("\n")
 
         change = int(details["change"])
index ad2a4cde74e0c2ec6367a7128aa0732f131f6bdf..0c74ef5cbe9ae0b43d8eaeb3249e4f83c695920b 100644 (file)
@@ -162,7 +162,8 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
                if (ce_uptodate(ce))
                        continue;
 
-               changed = check_removed(ce, &st);
+               /* If CE_VALID is set, don't look at workdir for file removal */
+               changed = (ce->ce_flags & CE_VALID) ? 0 : check_removed(ce, &st);
                if (changed) {
                        if (changed < 0) {
                                perror(ce->name);
@@ -308,22 +309,6 @@ static int show_modified(struct rev_info *revs,
        return 0;
 }
 
-/*
- * This turns all merge entries into "stage 3". That guarantees that
- * when we read in the new tree (into "stage 1"), we won't lose sight
- * of the fact that we had unmerged entries.
- */
-static void mark_merge_entries(void)
-{
-       int i;
-       for (i = 0; i < active_nr; i++) {
-               struct cache_entry *ce = active_cache[i];
-               if (!ce_stage(ce))
-                       continue;
-               ce->ce_flags |= CE_STAGEMASK;
-       }
-}
-
 /*
  * This gets a mix of an existing index and a tree, one pathname entry
  * at a time. The index entry may be a single stage-0 one, but it could
@@ -337,6 +322,8 @@ static void do_oneway_diff(struct unpack_trees_options *o,
        struct rev_info *revs = o->unpack_data;
        int match_missing, cached;
 
+       /* if the entry is not checked out, don't examine work tree */
+       cached = o->index_only || (idx && (idx->ce_flags & CE_VALID));
        /*
         * Backward compatibility wart - "diff-index -m" does
         * not mean "do not ignore merges", but "match_missing".
@@ -344,12 +331,11 @@ static void do_oneway_diff(struct unpack_trees_options *o,
         * But with the revision flag parsing, that's found in
         * "!revs->ignore_merges".
         */
-       cached = o->index_only;
        match_missing = !revs->ignore_merges;
 
        if (cached && idx && ce_stage(idx)) {
-               if (tree)
-                       diff_unmerge(&revs->diffopt, idx->name, idx->ce_mode, idx->sha1);
+               diff_unmerge(&revs->diffopt, idx->name, idx->ce_mode,
+                            idx->sha1);
                return;
        }
 
@@ -435,8 +421,6 @@ int run_diff_index(struct rev_info *revs, int cached)
        struct unpack_trees_options opts;
        struct tree_desc t;
 
-       mark_merge_entries();
-
        ent = revs->pending.objects[0].item;
        tree_name = revs->pending.objects[0].name;
        tree = parse_tree_indirect(ent->sha1);
diff --git a/entry.c b/entry.c
index f276cf3b88ea40cb4e6d03c623ce27cb0204c63e..06d24f14c6ba9401637aebfb11659ae747796c06 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -177,11 +177,15 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
 
 /*
  * This is like 'lstat()', except it refuses to follow symlinks
- * in the path.
+ * in the path, after skipping "skiplen".
  */
-int check_path(const char *path, int len, struct stat *st)
+int check_path(const char *path, int len, struct stat *st, int skiplen)
 {
-       if (has_symlink_leading_path(path, len)) {
+       const char *slash = path + len;
+
+       while (path < slash && *slash != '/')
+               slash--;
+       if (!has_dirs_only_path(path, slash - path, skiplen)) {
                errno = ENOENT;
                return -1;
        }
@@ -201,7 +205,7 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
        strcpy(path + len, ce->name);
        len += ce_namelen(ce);
 
-       if (!check_path(path, len, &st)) {
+       if (!check_path(path, len, &st, state->base_dir_len)) {
                unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID);
                if (!changed)
                        return 0;
index 8969553658bb5f4f2191f370062af9af33989d88..6f6f03966f5905c799a1a67df58e11b0a5f7564c 100755 (executable)
@@ -405,7 +405,7 @@ bisect_run () {
          exit $res
       fi
 
-      if grep "is first bad commit" "$GIT_DIR/BISECT_RUN" > /dev/null; then
+      if grep "is the first bad commit" "$GIT_DIR/BISECT_RUN" > /dev/null; then
          echo "bisect run success"
          exit 0;
       fi
index 71b5acb6fa2a0de36325cb8c2c6d56b458dfc7e5..e5e9f39c5678e97c69fe5314a964858ed5412163 100644 (file)
@@ -174,6 +174,8 @@ extern char *gitbasename(char *);
 #endif
 #endif
 
+#include "compat/bswap.h"
+
 /* General helper functions */
 extern void usage(const char *err) NORETURN;
 extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
index 5f5cac75eaa6fbf2ca68cfa01de2b21afa352cd0..d96eddbe56783d61304941a134361797c82480e7 100755 (executable)
@@ -77,11 +77,30 @@ start_httpd () {
        resolve_full_httpd
 
        # don't quote $full_httpd, there can be arguments to it (-f)
-       $full_httpd "$fqgitdir/gitweb/httpd.conf"
-       if test $? != 0; then
-               echo "Could not execute http daemon $httpd."
-               exit 1
-       fi
+       case "$httpd" in
+       *mongoose*)
+               #The mongoose server doesn't have a daemon mode so we'll have to fork it
+               $full_httpd "$fqgitdir/gitweb/httpd.conf" &
+               #Save the pid before doing anything else (we'll print it later)
+               pid=$!
+
+               if test $? != 0; then
+                       echo "Could not execute http daemon $httpd."
+                       exit 1
+               fi
+
+               cat > "$fqgitdir/pid" <<EOF
+$pid
+EOF
+               ;;
+       *)
+               $full_httpd "$fqgitdir/gitweb/httpd.conf"
+               if test $? != 0; then
+                       echo "Could not execute http daemon $httpd."
+                       exit 1
+               fi
+               ;;
+       esac
 }
 
 stop_httpd () {
@@ -308,6 +327,31 @@ EOF
        fi
 }
 
+mongoose_conf() {
+       cat > "$conf" <<EOF
+# Mongoose web server configuration file.
+# Lines starting with '#' and empty lines are ignored.
+# For detailed description of every option, visit
+# http://code.google.com/p/mongoose/wiki/MongooseManual
+
+root           $fqgitdir/gitweb
+ports          $port
+index_files    gitweb.cgi
+#ssl_cert      $fqgitdir/gitweb/ssl_cert.pem
+error_log      $fqgitdir/gitweb/error.log
+access_log     $fqgitdir/gitweb/access.log
+
+#cgi setup
+cgi_env                PATH=/usr/local/bin:/usr/bin:/bin,GIT_DIR=$GIT_DIR,GIT_EXEC_PATH=$GIT_EXEC_PATH
+cgi_interp     $PERL
+cgi_ext                cgi,pl
+
+# mimetype mapping
+mime_types     .gz=application/x-gzip,.tar.gz=application/x-tgz,.tgz=application/x-tgz,.tar=application/x-tar,.zip=application/zip,.gif=image/gif,.jpg=image/jpeg,.jpeg=image/jpeg,.png=image/png,.css=text/css,.html=text/html,.htm=text/html,.js=text/javascript,.c=text/plain,.cpp=text/plain,.log=text/plain,.conf=text/plain,.text=text/plain,.txt=text/plain,.dtd=text/xml,.bz2=application/x-bzip,.tbz=application/x-bzip-compressed-tar,.tar.bz2=application/x-bzip-compressed-tar
+EOF
+}
+
+
 script='
 s#^(my|our) \$projectroot =.*#$1 \$projectroot = "'$(dirname "$fqgitdir")'";#;
 s#(my|our) \$gitbin =.*#$1 \$gitbin = "'$GIT_EXEC_PATH'";#;
@@ -344,6 +388,9 @@ case "$httpd" in
 webrick)
        webrick_conf
        ;;
+*mongoose*)
+       mongoose_conf
+       ;;
 *)
        echo "Unknown httpd specified: $httpd"
        exit 1
index 03e589f764ba0570559fdb23a9a11cc2a0f24044..d61c9d03bc216cc2f1ab004fe3ffba42ef121a68 100755 (executable)
@@ -162,10 +162,6 @@ show_stash () {
 }
 
 apply_stash () {
-       git update-index -q --refresh &&
-       git diff-files --quiet --ignore-submodules ||
-               die 'Cannot apply to a dirty working tree, please stage your changes'
-
        unstash_index=
 
        while test $# != 0
@@ -184,18 +180,27 @@ apply_stash () {
                shift
        done
 
-       # current index state
-       c_tree=$(git write-tree) ||
-               die 'Cannot apply a stash in the middle of a merge'
+       if test $# = 0
+       then
+               have_stash || die 'Nothing to apply'
+       fi
 
        # stash records the work tree, and is a merge between the
        # base commit (first parent) and the index tree (second parent).
-       s=$(git rev-parse --verify --default $ref_stash "$@") &&
-       w_tree=$(git rev-parse --verify "$s:") &&
-       b_tree=$(git rev-parse --verify "$s^1:") &&
-       i_tree=$(git rev-parse --verify "$s^2:") ||
+       s=$(git rev-parse --quiet --verify --default $ref_stash "$@") &&
+       w_tree=$(git rev-parse --quiet --verify "$s:") &&
+       b_tree=$(git rev-parse --quiet --verify "$s^1:") &&
+       i_tree=$(git rev-parse --quiet --verify "$s^2:") ||
                die "$*: no valid stashed state found"
 
+       git update-index -q --refresh &&
+       git diff-files --quiet --ignore-submodules ||
+               die 'Cannot apply to a dirty working tree, please stage your changes'
+
+       # current index state
+       c_tree=$(git write-tree) ||
+               die 'Cannot apply a stash in the middle of a merge'
+
        unstashed_index_tree=
        if test -n "$unstash_index" && test "$b_tree" != "$i_tree" &&
                        test "$c_tree" != "$i_tree"
index ebed711da41a7ac3c4caa7ae9b7f73e0c75f4fe7..bfbd36b6f45097feaec92f107690224fc81c09c6 100755 (executable)
@@ -4,9 +4,14 @@
 #
 # Copyright (c) 2007 Lars Hjemli
 
-USAGE="[--quiet] [--cached] \
-[add [-b branch] <repo> <path>]|[status|init|update [-i|--init] [-N|--no-fetch] [--rebase|--merge]|summary [-n|--summary-limit <n>] [<commit>]] \
-[--] [<path>...]|[foreach <command>]|[sync [--] [<path>...]]"
+dashless=$(basename "$0" | sed -e 's/-/ /')
+USAGE="[--quiet] add [-b branch] [--reference <repository>] [--] <repository> <path>
+   or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
+   or: $dashless [--quiet] init [--] [<path>...]
+   or: $dashless [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
+   or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
+   or: $dashless [--quiet] foreach [--recursive] <command>
+   or: $dashless [--quiet] sync [--] [<path>...]"
 OPTIONS_SPEC=
 . git-sh-setup
 . git-parse-remote
@@ -16,8 +21,10 @@ command=
 branch=
 reference=
 cached=
+files=
 nofetch=
 update=
+prefix=
 
 # Resolve relative url by appending to parent's url
 resolve_relative_url ()
@@ -237,13 +244,43 @@ cmd_add()
 #
 cmd_foreach()
 {
+       # parse $args after "submodule ... foreach".
+       while test $# -ne 0
+       do
+               case "$1" in
+               -q|--quiet)
+                       GIT_QUIET=1
+                       ;;
+               --recursive)
+                       recursive=1
+                       ;;
+               -*)
+                       usage
+                       ;;
+               *)
+                       break
+                       ;;
+               esac
+               shift
+       done
+
        module_list |
        while read mode sha1 stage path
        do
                if test -e "$path"/.git
                then
-                       say "Entering '$path'"
-                       (cd "$path" && eval "$@") ||
+                       say "Entering '$prefix$path'"
+                       name=$(module_name "$path")
+                       (
+                               prefix="$prefix$path/"
+                               unset GIT_DIR
+                               cd "$path" &&
+                               eval "$@" &&
+                               if test -n "$recursive"
+                               then
+                                       cmd_foreach "--recursive" "$@"
+                               fi
+                       ) ||
                        die "Stopping at '$path'; script returned non-zero status."
                fi
        done
@@ -316,6 +353,7 @@ cmd_init()
 cmd_update()
 {
        # parse $args after "submodule ... update".
+       orig_args="$@"
        while test $# -ne 0
        do
                case "$1" in
@@ -348,6 +386,10 @@ cmd_update()
                        shift
                        update="merge"
                        ;;
+               --recursive)
+                       shift
+                       recursive=1
+                       ;;
                --)
                        shift
                        break
@@ -434,6 +476,12 @@ cmd_update()
                        die "Unable to $action '$sha1' in submodule path '$path'"
                        say "Submodule path '$path': $msg '$sha1'"
                fi
+
+               if test -n "$recursive"
+               then
+                       (unset GIT_DIR; cd "$path" && cmd_update $orig_args) ||
+                       die "Failed to recurse into submodule path '$path'"
+               fi
        done
 }
 
@@ -460,6 +508,7 @@ set_name_rev () {
 cmd_summary() {
        summary_limit=-1
        for_status=
+       diff_cmd=diff-index
 
        # parse $args after "submodule ... summary".
        while test $# -ne 0
@@ -468,6 +517,9 @@ cmd_summary() {
                --cached)
                        cached="$1"
                        ;;
+               --files)
+                       files="$1"
+                       ;;
                --for-status)
                        for_status="$1"
                        ;;
@@ -504,9 +556,17 @@ cmd_summary() {
                head=HEAD
        fi
 
+       if [ -n "$files" ]
+       then
+               test -n "$cached" &&
+               die "--cached cannot be used with --files"
+               diff_cmd=diff-files
+               head=
+       fi
+
        cd_to_toplevel
        # Get modified modules cared by user
-       modules=$(git diff-index $cached --raw $head -- "$@" |
+       modules=$(git $diff_cmd $cached --raw $head -- "$@" |
                egrep '^:([0-7]* )?160000' |
                while read mod_src mod_dst sha1_src sha1_dst status name
                do
@@ -520,7 +580,7 @@ cmd_summary() {
 
        test -z "$modules" && return
 
-       git diff-index $cached --raw $head -- $modules |
+       git $diff_cmd $cached --raw $head -- $modules |
        egrep '^:([0-7]* )?160000' |
        cut -c2- |
        while read mod_src mod_dst sha1_src sha1_dst status name
@@ -643,6 +703,7 @@ cmd_summary() {
 cmd_status()
 {
        # parse $args after "submodule ... status".
+       orig_args="$@"
        while test $# -ne 0
        do
                case "$1" in
@@ -652,6 +713,9 @@ cmd_status()
                --cached)
                        cached=1
                        ;;
+               --recursive)
+                       recursive=1
+                       ;;
                --)
                        shift
                        break
@@ -671,22 +735,34 @@ cmd_status()
        do
                name=$(module_name "$path") || exit
                url=$(git config submodule."$name".url)
+               displaypath="$prefix$path"
                if test -z "$url" || ! test -d "$path"/.git -o -f "$path"/.git
                then
-                       say "-$sha1 $path"
+                       say "-$sha1 $displaypath"
                        continue;
                fi
                set_name_rev "$path" "$sha1"
                if git diff-files --quiet -- "$path"
                then
-                       say " $sha1 $path$revname"
+                       say " $sha1 $displaypath$revname"
                else
                        if test -z "$cached"
                        then
                                sha1=$(unset GIT_DIR; cd "$path" && git rev-parse --verify HEAD)
                                set_name_rev "$path" "$sha1"
                        fi
-                       say "+$sha1 $path$revname"
+                       say "+$sha1 $displaypath$revname"
+               fi
+
+               if test -n "$recursive"
+               then
+                       (
+                               prefix="$displaypath/"
+                               unset GIT_DIR
+                               cd "$path" &&
+                               cmd_status $orig_args
+                       ) ||
+                       die "Failed to recurse into submodule path '$path'"
                fi
        done
 }
diff --git a/git.c b/git.c
index 5da6c65697dfd198e27b5b693566158bf772ab88..0b22595548a44c5eaa35dc671dda4d29e0773e96 100644 (file)
--- a/git.c
+++ b/git.c
@@ -359,6 +359,7 @@ static void handle_internal_command(int argc, const char **argv)
                { "unpack-objects", cmd_unpack_objects, RUN_SETUP },
                { "update-index", cmd_update_index, RUN_SETUP },
                { "update-ref", cmd_update_ref, RUN_SETUP },
+               { "update-server-info", cmd_update_server_info, RUN_SETUP },
                { "upload-archive", cmd_upload_archive },
                { "verify-tag", cmd_verify_tag, RUN_SETUP },
                { "version", cmd_version },
index 18c9ce35e8fc6566663ad76dd04bd1aa70035c25..b76a0cffff783ba580294560f0ee53131776136b 100644 (file)
@@ -123,6 +123,15 @@ GITWEB_CONFIG file:
        $feature{'snapshot'}{'default'} = ['zip', 'tgz'];
        $feature{'snapshot'}{'override'} = 1;
 
+If you allow overriding for the snapshot feature, you can specify which
+snapshot formats are globally disabled. You can also add any command line
+options you want (such as setting the compression level). For instance,
+you can disable Zip compressed snapshots and set GZip to run at level 6 by
+adding the following lines to your $GITWEB_CONFIG:
+
+       $known_snapshot_formats{'zip'}{'disabled'} = 1;
+       $known_snapshot_formats{'tgz'}{'compressor'} = ['gzip','-6'];
+
 
 Gitweb repositories
 -------------------
index be7358fdebfc29cd1ef52bbf2eb1f7cffb6e0daa..24b219310a73f6ff8412b9236e7e5a95a7860e2f 100755 (executable)
@@ -160,7 +160,8 @@ BEGIN
        #       'suffix' => filename suffix,
        #       'format' => --format for git-archive,
        #       'compressor' => [compressor command and arguments]
-       #                       (array reference, optional)}
+       #                       (array reference, optional)
+       #       'disabled' => boolean (optional)}
        #
        'tgz' => {
                'display' => 'tar.gz',
@@ -176,6 +177,14 @@ BEGIN
                'format' => 'tar',
                'compressor' => ['bzip2']},
 
+       'txz' => {
+               'display' => 'tar.xz',
+               'type' => 'application/x-xz',
+               'suffix' => '.tar.xz',
+               'format' => 'tar',
+               'compressor' => ['xz'],
+               'disabled' => 1},
+
        'zip' => {
                'display' => 'zip',
                'type' => 'application/x-zip',
@@ -188,6 +197,7 @@ BEGIN
 our %known_snapshot_format_aliases = (
        'gzip'  => 'tgz',
        'bzip2' => 'tbz2',
+       'xz'    => 'txz',
 
        # backward compatibility: legacy gitweb config support
        'x-gzip' => undef, 'gz' => undef,
@@ -405,7 +415,7 @@ sub gitweb_get_feature {
                @{$feature{$name}{'default'}});
        if (!$override) { return @defaults; }
        if (!defined $sub) {
-               warn "feature $name is not overrideable";
+               warn "feature $name is not overridable";
                return @defaults;
        }
        return $sub->(@defaults);
@@ -494,7 +504,8 @@ sub filter_snapshot_fmts {
                exists $known_snapshot_format_aliases{$_} ?
                       $known_snapshot_format_aliases{$_} : $_} @fmts;
        @fmts = grep {
-               exists $known_snapshot_formats{$_} } @fmts;
+               exists $known_snapshot_formats{$_} &&
+               !$known_snapshot_formats{$_}{'disabled'}} @fmts;
 }
 
 our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
@@ -1513,10 +1524,10 @@ sub format_subject_html {
                $long =~ s/[[:cntrl:]]/?/g;
                return $cgi->a({-href => $href, -class => "list subject",
                                -title => to_utf8($long)},
-                      esc_html($short) . $extra);
+                      esc_html($short)) . $extra;
        } else {
                return $cgi->a({-href => $href, -class => "list subject"},
-                      esc_html($long)  . $extra);
+                      esc_html($long)) . $extra;
        }
 }
 
@@ -5179,6 +5190,8 @@ sub git_snapshot {
                die_error(400, "Invalid snapshot format parameter");
        } elsif (!exists($known_snapshot_formats{$format})) {
                die_error(400, "Unknown snapshot format");
+       } elsif ($known_snapshot_formats{$format}{'disabled'}) {
+               die_error(403, "Snapshot format not allowed");
        } elsif (!grep($_ eq $format, @snapshot_fmts)) {
                die_error(403, "Unsupported snapshot format");
        }
diff --git a/graph.c b/graph.c
index f3226ec94a5b59372096698e216af60169d565f6..6746d422a98ed010489d4ce74b26a8a4600b183e 100644 (file)
--- a/graph.c
+++ b/graph.c
@@ -291,9 +291,10 @@ static int graph_is_interesting(struct git_graph *graph, struct commit *commit)
        }
 
        /*
-        * Uninteresting and pruned commits won't be printed
+        * Otherwise, use get_commit_action() to see if this commit is
+        * interesting
         */
-       return (commit->object.flags & (UNINTERESTING | TREESAME)) ? 0 : 1;
+       return get_commit_action(graph->revs, commit) == commit_show;
 }
 
 static struct commit_list *next_interesting_parent(struct git_graph *graph,
diff --git a/http.c b/http.c
index eb0c6698013e717eda5b6005fb48666191238aab..5926c5b3f7bbc781d77e2348db2990bcb51460e6 100644 (file)
--- a/http.c
+++ b/http.c
@@ -1289,5 +1289,10 @@ void release_http_object_request(struct http_object_request *freq)
                free(freq->url);
                freq->url = NULL;
        }
-       freq->slot = NULL;
+       if (freq->slot != NULL) {
+               freq->slot->callback_func = NULL;
+               freq->slot->callback_data = NULL;
+               release_active_slot(freq->slot);
+               freq->slot = NULL;
+       }
 }
index a3b4c0692c6a46a0642cf1cb42e60eee59110d60..1c9eefee33b38a44f34d21c47bc1f16af1443a6c 100644 (file)
@@ -25,7 +25,8 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in
        struct object *obj = parse_object(sha1);
        if (!obj)
                return 0;
-       refname = prettify_refname(refname);
+       if (!cb_data || *(int *)cb_data == DECORATE_SHORT_REFS)
+               refname = prettify_refname(refname);
        add_name_decoration("", refname, obj);
        while (obj->type == OBJ_TAG) {
                obj = ((struct tag *)obj)->tagged;
@@ -36,12 +37,12 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in
        return 0;
 }
 
-void load_ref_decorations(void)
+void load_ref_decorations(int flags)
 {
        static int loaded;
        if (!loaded) {
                loaded = 1;
-               for_each_ref(add_ref_decoration, NULL);
+               for_each_ref(add_ref_decoration, &flags);
        }
 }
 
index 20b5caf1aa45aa0ba076ec60320d252c42abfb64..3f7b40027b7203985f018e43ab72a6cfc233e8d7 100644 (file)
@@ -17,7 +17,7 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
                             const char **subject_p,
                             const char **extra_headers_p,
                             int *need_8bit_cte_p);
-void load_ref_decorations(void);
+void load_ref_decorations(int flags);
 
 #define FORMAT_PATCH_NAME_MAX 64
 void get_patch_filename(struct commit *commit, int nr, const char *suffix,
diff --git a/mozilla-sha1/sha1.c b/mozilla-sha1/sha1.c
deleted file mode 100644 (file)
index 95a4ebf..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is SHA 180-1 Reference Implementation (Compact version)
- *
- * The Initial Developer of the Original Code is Paul Kocher of
- * Cryptography Research.  Portions created by Paul Kocher are
- * Copyright (C) 1995-9 by Cryptography Research, Inc.  All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- *     Paul Kocher
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above.  If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL.  If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
-
-#include "sha1.h"
-
-static void shaHashBlock(moz_SHA_CTX *ctx);
-
-void moz_SHA1_Init(moz_SHA_CTX *ctx) {
-  int i;
-
-  ctx->lenW = 0;
-  ctx->sizeHi = ctx->sizeLo = 0;
-
-  /* Initialize H with the magic constants (see FIPS180 for constants)
-   */
-  ctx->H[0] = 0x67452301;
-  ctx->H[1] = 0xefcdab89;
-  ctx->H[2] = 0x98badcfe;
-  ctx->H[3] = 0x10325476;
-  ctx->H[4] = 0xc3d2e1f0;
-
-  for (i = 0; i < 80; i++)
-    ctx->W[i] = 0;
-}
-
-
-void moz_SHA1_Update(moz_SHA_CTX *ctx, const void *_dataIn, int len) {
-  const unsigned char *dataIn = _dataIn;
-  int i;
-
-  /* Read the data into W and process blocks as they get full
-   */
-  for (i = 0; i < len; i++) {
-    ctx->W[ctx->lenW / 4] <<= 8;
-    ctx->W[ctx->lenW / 4] |= (unsigned int)dataIn[i];
-    if ((++ctx->lenW) % 64 == 0) {
-      shaHashBlock(ctx);
-      ctx->lenW = 0;
-    }
-    ctx->sizeLo += 8;
-    ctx->sizeHi += (ctx->sizeLo < 8);
-  }
-}
-
-
-void moz_SHA1_Final(unsigned char hashout[20], moz_SHA_CTX *ctx) {
-  unsigned char pad0x80 = 0x80;
-  unsigned char pad0x00 = 0x00;
-  unsigned char padlen[8];
-  int i;
-
-  /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length
-   */
-  padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255);
-  padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255);
-  padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255);
-  padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255);
-  padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255);
-  padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255);
-  padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255);
-  padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255);
-  moz_SHA1_Update(ctx, &pad0x80, 1);
-  while (ctx->lenW != 56)
-    moz_SHA1_Update(ctx, &pad0x00, 1);
-  moz_SHA1_Update(ctx, padlen, 8);
-
-  /* Output hash
-   */
-  for (i = 0; i < 20; i++) {
-    hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24);
-    ctx->H[i / 4] <<= 8;
-  }
-
-  /*
-   *  Re-initialize the context (also zeroizes contents)
-   */
-  moz_SHA1_Init(ctx);
-}
-
-
-#define SHA_ROT(X,n) (((X) << (n)) | ((X) >> (32-(n))))
-
-static void shaHashBlock(moz_SHA_CTX *ctx) {
-  int t;
-  unsigned int A,B,C,D,E,TEMP;
-
-  for (t = 16; t <= 79; t++)
-    ctx->W[t] =
-      SHA_ROT(ctx->W[t-3] ^ ctx->W[t-8] ^ ctx->W[t-14] ^ ctx->W[t-16], 1);
-
-  A = ctx->H[0];
-  B = ctx->H[1];
-  C = ctx->H[2];
-  D = ctx->H[3];
-  E = ctx->H[4];
-
-  for (t = 0; t <= 19; t++) {
-    TEMP = SHA_ROT(A,5) + (((C^D)&B)^D)     + E + ctx->W[t] + 0x5a827999;
-    E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP;
-  }
-  for (t = 20; t <= 39; t++) {
-    TEMP = SHA_ROT(A,5) + (B^C^D)           + E + ctx->W[t] + 0x6ed9eba1;
-    E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP;
-  }
-  for (t = 40; t <= 59; t++) {
-    TEMP = SHA_ROT(A,5) + ((B&C)|(D&(B|C))) + E + ctx->W[t] + 0x8f1bbcdc;
-    E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP;
-  }
-  for (t = 60; t <= 79; t++) {
-    TEMP = SHA_ROT(A,5) + (B^C^D)           + E + ctx->W[t] + 0xca62c1d6;
-    E = D; D = C; C = SHA_ROT(B, 30); B = A; A = TEMP;
-  }
-
-  ctx->H[0] += A;
-  ctx->H[1] += B;
-  ctx->H[2] += C;
-  ctx->H[3] += D;
-  ctx->H[4] += E;
-}
diff --git a/mozilla-sha1/sha1.h b/mozilla-sha1/sha1.h
deleted file mode 100644 (file)
index aa48a46..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is SHA 180-1 Header File
- *
- * The Initial Developer of the Original Code is Paul Kocher of
- * Cryptography Research.  Portions created by Paul Kocher are
- * Copyright (C) 1995-9 by Cryptography Research, Inc.  All
- * Rights Reserved.
- *
- * Contributor(s):
- *
- *     Paul Kocher
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable
- * instead of those above.  If you wish to allow use of your
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL.  If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
-
-typedef struct {
-  unsigned int H[5];
-  unsigned int W[80];
-  int lenW;
-  unsigned int sizeHi,sizeLo;
-} moz_SHA_CTX;
-
-void moz_SHA1_Init(moz_SHA_CTX *ctx);
-void moz_SHA1_Update(moz_SHA_CTX *ctx, const void *dataIn, int len);
-void moz_SHA1_Final(unsigned char hashout[20], moz_SHA_CTX *ctx);
-
-#define git_SHA_CTX    moz_SHA_CTX
-#define git_SHA1_Init  moz_SHA1_Init
-#define git_SHA1_Update        moz_SHA1_Update
-#define git_SHA1_Final moz_SHA1_Final
index 3b2ecdd20e6f5bdca61ee5e605deac7b8239c70d..f5983f8baa98b69338707b4220e64012ef4e5d11 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -583,7 +583,7 @@ static void format_decoration(struct strbuf *sb, const struct commit *commit)
        struct name_decoration *d;
        const char *prefix = " (";
 
-       load_ref_decorations();
+       load_ref_decorations(DECORATE_SHORT_REFS);
        d = lookup_decoration(&name_decoration, &commit->object);
        while (d) {
                strbuf_addstr(sb, prefix);
index 4e3e272ee409de66de2059a8be475fddcaa4dc28..1bbaf1cffba3058667787fc4a267b87e21a6cad3 100644 (file)
@@ -1065,7 +1065,18 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
        return updated;
 }
 
-int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec, char *seen)
+static void show_file(const char * fmt, const char * name, int in_porcelain,
+                     int * first, char *header_msg)
+{
+       if (in_porcelain && *first && header_msg) {
+               printf("%s\n", header_msg);
+               *first=0;
+       }
+       printf(fmt, name);
+}
+
+int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec,
+                 char *seen, char *header_msg)
 {
        int i;
        int has_errors = 0;
@@ -1074,11 +1085,14 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
        int quiet = (flags & REFRESH_QUIET) != 0;
        int not_new = (flags & REFRESH_IGNORE_MISSING) != 0;
        int ignore_submodules = (flags & REFRESH_IGNORE_SUBMODULES) != 0;
+       int first = 1;
+       int in_porcelain = (flags & REFRESH_IN_PORCELAIN);
        unsigned int options = really ? CE_MATCH_IGNORE_VALID : 0;
-       const char *needs_update_message;
+       const char *needs_update_fmt;
+       const char *needs_merge_fmt;
 
-       needs_update_message = ((flags & REFRESH_SAY_CHANGED)
-                               ? "locally modified" : "needs update");
+       needs_update_fmt = (in_porcelain ? "M\t%s\n" : "%s: needs update\n");
+       needs_merge_fmt = (in_porcelain ? "U\t%s\n" : "%s: needs merge\n");
        for (i = 0; i < istate->cache_nr; i++) {
                struct cache_entry *ce, *new;
                int cache_errno = 0;
@@ -1094,7 +1108,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
                        i--;
                        if (allow_unmerged)
                                continue;
-                       printf("%s: needs merge\n", ce->name);
+                       show_file(needs_merge_fmt, ce->name, in_porcelain, &first, header_msg);
                        has_errors = 1;
                        continue;
                }
@@ -1117,7 +1131,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
                        }
                        if (quiet)
                                continue;
-                       printf("%s: %s\n", ce->name, needs_update_message);
+                       show_file(needs_update_fmt, ce->name, in_porcelain, &first, header_msg);
                        has_errors = 1;
                        continue;
                }
index 9f5dac5f1d8a8a654a2ab77e8e26fb134c7e36fa..35eca4a36185b1c5c40245748d0004fdaf0f6c00 100644 (file)
@@ -1052,7 +1052,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                revs->simplify_by_decoration = 1;
                revs->limited = 1;
                revs->prune = 1;
-               load_ref_decorations();
+               load_ref_decorations(DECORATE_SHORT_REFS);
        } else if (!strcmp(arg, "--date-order")) {
                revs->lifo = 0;
                revs->topo_order = 1;
@@ -1664,7 +1664,7 @@ static inline int want_ancestry(struct rev_info *revs)
        return (revs->rewrite_parents || revs->children.name);
 }
 
-enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit)
+enum commit_action get_commit_action(struct rev_info *revs, struct commit *commit)
 {
        if (commit->object.flags & SHOWN)
                return commit_ignore;
@@ -1692,12 +1692,23 @@ enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit)
                        if (!commit->parents || !commit->parents->next)
                                return commit_ignore;
                }
-               if (want_ancestry(revs) && rewrite_parents(revs, commit) < 0)
-                       return commit_error;
        }
        return commit_show;
 }
 
+enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit)
+{
+       enum commit_action action = get_commit_action(revs, commit);
+
+       if (action == commit_show &&
+           !revs->show_all &&
+           revs->prune && revs->dense && want_ancestry(revs)) {
+               if (rewrite_parents(revs, commit) < 0)
+                       return commit_error;
+       }
+       return action;
+}
+
 static struct commit *get_revision_1(struct rev_info *revs)
 {
        if (!revs->commits)
index fb74492714b9276d02992dbe1101efff2cbdb5e6..9d0dddbcbc981c60fd1348cdf257c67fb9ee5f84 100644 (file)
@@ -15,6 +15,9 @@
 #define SYMMETRIC_LEFT (1u<<8)
 #define ALL_REV_FLAGS  ((1u<<9)-1)
 
+#define DECORATE_SHORT_REFS    1
+#define DECORATE_FULL_REFS     2
+
 struct rev_info;
 struct log_info;
 
@@ -165,6 +168,7 @@ enum commit_action {
        commit_error
 };
 
+extern enum commit_action get_commit_action(struct rev_info *revs, struct commit *commit);
 extern enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit);
 
 #endif
diff --git a/t/gitweb-lib.sh b/t/gitweb-lib.sh
new file mode 100644 (file)
index 0000000..8452532
--- /dev/null
@@ -0,0 +1,73 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Jakub Narebski
+#
+
+gitweb_init () {
+       safe_pwd="$(perl -MPOSIX=getcwd -e 'print quotemeta(getcwd)')"
+       cat >gitweb_config.perl <<EOF
+#!/usr/bin/perl
+
+# gitweb configuration for tests
+
+our \$version = 'current';
+our \$GIT = 'git';
+our \$projectroot = "$safe_pwd";
+our \$project_maxdepth = 8;
+our \$home_link_str = 'projects';
+our \$site_name = '[localhost]';
+our \$site_header = '';
+our \$site_footer = '';
+our \$home_text = 'indextext.html';
+our @stylesheets = ('file:///$TEST_DIRECTORY/../gitweb/gitweb.css');
+our \$logo = 'file:///$TEST_DIRECTORY/../gitweb/git-logo.png';
+our \$favicon = 'file:///$TEST_DIRECTORY/../gitweb/git-favicon.png';
+our \$projects_list = '';
+our \$export_ok = '';
+our \$strict_export = '';
+
+EOF
+
+       cat >.git/description <<EOF
+$0 test repository
+EOF
+}
+
+gitweb_run () {
+       GATEWAY_INTERFACE='CGI/1.1'
+       HTTP_ACCEPT='*/*'
+       REQUEST_METHOD='GET'
+       SCRIPT_NAME="$TEST_DIRECTORY/../gitweb/gitweb.perl"
+       QUERY_STRING=""$1""
+       PATH_INFO=""$2""
+       export GATEWAY_INTERFACE HTTP_ACCEPT REQUEST_METHOD \
+               SCRIPT_NAME QUERY_STRING PATH_INFO
+
+       GITWEB_CONFIG=$(pwd)/gitweb_config.perl
+       export GITWEB_CONFIG
+
+       # some of git commands write to STDERR on error, but this is not
+       # written to web server logs, so we are not interested in that:
+       # we are interested only in properly formatted errors/warnings
+       rm -f gitweb.log &&
+       perl -- "$SCRIPT_NAME" \
+               >gitweb.output 2>gitweb.log &&
+       if grep '^[[]' gitweb.log >/dev/null 2>&1; then false; else true; fi
+
+       # gitweb.log is left for debugging
+       # gitweb.output is used to parse http output
+}
+
+. ./test-lib.sh
+
+if ! test_have_prereq PERL; then
+       say 'skipping gitweb tests, perl not available'
+       test_done
+fi
+
+perl -MEncode -e 'decode_utf8("", Encode::FB_CROAK)' >/dev/null 2>&1 || {
+    say 'skipping gitweb tests, perl version is too old'
+    test_done
+}
+
+gitweb_init
diff --git a/t/t1009-read-tree-new-index.sh b/t/t1009-read-tree-new-index.sh
new file mode 100755 (executable)
index 0000000..59b3aa4
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+test_description='test read-tree into a fresh index file'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+       echo one >a &&
+       git add a &&
+       git commit -m initial
+'
+
+test_expect_success 'non-existent index file' '
+       rm -f new-index &&
+       GIT_INDEX_FILE=new-index git read-tree master
+'
+
+test_expect_success 'empty index file' '
+       rm -f new-index &&
+       > new-index &&
+       GIT_INDEX_FILE=new-index git read-tree master
+'
+
+test_done
+
index f7e1a735ec8699616280a086f59dc50c078bfaa7..de3edb5d571ea83263f5133e751704ab0ba580c8 100755 (executable)
@@ -48,4 +48,13 @@ test_expect_success \
     'git checkout-index conflicting paths.' \
     'test -f path0 && test -d path1 && test -f path1/file1'
 
+test_expect_success SYMLINKS 'checkout-index -f twice with --prefix' '
+       mkdir -p tar/get &&
+       ln -s tar/get there &&
+       echo first &&
+       git checkout-index -a -f --prefix=there/ &&
+       echo second &&
+       git checkout-index -a -f --prefix=there/
+'
+
 test_done
diff --git a/t/t2015-checkout-unborn.sh b/t/t2015-checkout-unborn.sh
new file mode 100755 (executable)
index 0000000..c551d39
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+test_description='checkout from unborn branch protects contents'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       mkdir parent &&
+       (cd parent &&
+        git init &&
+        echo content >file &&
+        git add file &&
+        git commit -m base
+       ) &&
+       git fetch parent master:origin
+'
+
+test_expect_success 'checkout from unborn preserves untracked files' '
+       echo precious >expect &&
+       echo precious >file &&
+       test_must_fail git checkout -b new origin &&
+       test_cmp expect file
+'
+
+test_expect_success 'checkout from unborn preserves index contents' '
+       echo precious >expect &&
+       echo precious >file &&
+       git add file &&
+       test_must_fail git checkout -b new origin &&
+       test_cmp expect file &&
+       git show :file >file &&
+       test_cmp expect file
+'
+
+test_expect_success 'checkout from unborn merges identical index contents' '
+       echo content >file &&
+       git add file &&
+       git checkout -b new origin
+'
+
+test_done
index 8b33321f8c44dc7f8a08fa144bca4f10444ceaa1..8e3694ed5b80a87602d6533f0aa28307bd7b3d1b 100755 (executable)
@@ -207,6 +207,7 @@ log --root --cc --patch-with-stat --summary master
 log -SF master
 log -SF -p master
 log --decorate --all
+log --decorate=full --all
 
 rev-list --parents HEAD
 rev-list --children HEAD
diff --git a/t/t4013/diff.log_--decorate=full_--all b/t/t4013/diff.log_--decorate=full_--all
new file mode 100644 (file)
index 0000000..903d9d9
--- /dev/null
@@ -0,0 +1,34 @@
+$ git log --decorate=full --all
+commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (refs/heads/master)
+Merge: 9a6d494 c7a2ab9
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:04:00 2006 +0000
+
+    Merge branch 'side'
+
+commit c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a (refs/heads/side)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:03:00 2006 +0000
+
+    Side
+
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+commit 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:01:00 2006 +0000
+
+    Second
+    
+    This is the second commit.
+
+commit 444ac553ac7612cc88969031b02b3767fb8a353a (refs/heads/initial)
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:00:00 2006 +0000
+
+    Initial
+$
diff --git a/t/t4039-diff-assume-unchanged.sh b/t/t4039-diff-assume-unchanged.sh
new file mode 100755 (executable)
index 0000000..9d9498b
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+test_description='diff with assume-unchanged entries'
+
+. ./test-lib.sh
+
+# external diff has been tested in t4020-diff-external.sh
+
+test_expect_success 'setup' '
+       echo zero > zero &&
+       git add zero &&
+       git commit -m zero &&
+       echo one > one &&
+       echo two > two &&
+       git add one two &&
+       git commit -m onetwo &&
+       git update-index --assume-unchanged one &&
+       echo borked >> one &&
+       test "$(git ls-files -v one)" = "h one"
+'
+
+test_expect_success 'diff-index does not examine assume-unchanged entries' '
+       git diff-index HEAD^ -- one | grep -q 5626abf0f72e58d7a153368ba57db4c673c0e171
+'
+
+test_expect_success 'diff-files does not examine assume-unchanged entries' '
+       rm one &&
+       test -z "$(git diff-files -- one)"
+'
+
+test_done
index a8c2ca2a78dd54f69230cb443eff1d6e82336f0a..18376d66081759c6a4959a2d8bc47ca441364660 100755 (executable)
@@ -139,6 +139,36 @@ test_expect_success 'fsck in shallow repo' '
        )
 '
 
+test_expect_success 'simple fetch in shallow repo' '
+       (
+               cd shallow &&
+               git fetch
+       )
+'
+
+test_expect_success 'no changes expected' '
+       (
+               cd shallow &&
+               git count-objects -v
+       ) > count.shallow.2 &&
+       cmp count.shallow count.shallow.2
+'
+
+test_expect_success 'fetch same depth in shallow repo' '
+       (
+               cd shallow &&
+               git fetch --depth=2
+       )
+'
+
+test_expect_success 'no changes expected' '
+       (
+               cd shallow &&
+               git count-objects -v
+       ) > count.shallow.3 &&
+       cmp count.shallow count.shallow.3
+'
+
 test_expect_success 'add two more' '
        add B66 $B65 &&
        add B67 $B66
@@ -201,4 +231,21 @@ test_expect_success 'pull in shallow repo with missing merge base' '
        )
 '
 
+test_expect_success 'additional simple shallow deepenings' '
+       (
+               cd shallow &&
+               git fetch --depth=8 &&
+               git fetch --depth=10 &&
+               git fetch --depth=11
+       )
+'
+
+test_expect_success 'clone shallow object count' '
+       (
+               cd shallow &&
+               git count-objects -v
+       ) > count.shallow &&
+       grep "^count: 52" count.shallow
+'
+
 test_done
diff --git a/t/t5531-deep-submodule-push.sh b/t/t5531-deep-submodule-push.sh
new file mode 100644 (file)
index 0000000..65d8d47
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+test_description='unpack-objects'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+       mkdir pub.git &&
+       GIT_DIR=pub.git git init --bare
+       GIT_DIR=pub.git git config receive.fsckobjects true &&
+       mkdir work &&
+       (
+               cd work &&
+               git init &&
+               mkdir -p gar/bage &&
+               (
+                       cd gar/bage &&
+                       git init &&
+                       >junk &&
+                       git add junk &&
+                       git commit -m "Initial junk"
+               ) &&
+               git add gar/bage &&
+               git commit -m "Initial superproject"
+       )
+'
+
+test_expect_success push '
+       (
+               cd work &&
+               git push ../pub.git master
+       )
+'
+
+test_done
diff --git a/t/t6015-rev-list-show-all-parents.sh b/t/t6015-rev-list-show-all-parents.sh
new file mode 100755 (executable)
index 0000000..8b146fb
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+test_description='--show-all --parents does not rewrite TREESAME commits'
+
+. ./test-lib.sh
+
+test_expect_success 'set up --show-all --parents test' '
+       test_commit one foo.txt &&
+       commit1=`git rev-list -1 HEAD` &&
+       test_commit two bar.txt &&
+       commit2=`git rev-list -1 HEAD` &&
+       test_commit three foo.txt &&
+       commit3=`git rev-list -1 HEAD`
+       '
+
+test_expect_success '--parents rewrites TREESAME parents correctly' '
+       echo $commit3 $commit1 > expected &&
+       echo $commit1 >> expected &&
+       git rev-list --parents HEAD -- foo.txt > actual &&
+       test_cmp expected actual
+       '
+
+test_expect_success '--parents --show-all does not rewrites TREESAME parents' '
+       echo $commit3 $commit2 > expected &&
+       echo $commit2 $commit1 >> expected &&
+       echo $commit1 >> expected &&
+       git rev-list --parents --show-all HEAD -- foo.txt > actual &&
+       test_cmp expected actual
+       '
+
+test_done
diff --git a/t/t6016-rev-list-graph-simplify-history.sh b/t/t6016-rev-list-graph-simplify-history.sh
new file mode 100755 (executable)
index 0000000..27fd52b
--- /dev/null
@@ -0,0 +1,276 @@
+#!/bin/sh
+
+# There's more than one "correct" way to represent the history graphically.
+# These tests depend on the current behavior of the graphing code.  If the
+# graphing code is ever changed to draw the output differently, these tests
+# cases will need to be updated to know about the new layout.
+
+test_description='--graph and simplified history'
+
+. ./test-lib.sh
+
+test_expect_success 'set up rev-list --graph test' '
+       # 3 commits on branch A
+       test_commit A1 foo.txt &&
+       test_commit A2 bar.txt &&
+       test_commit A3 bar.txt &&
+       git branch -m master A &&
+
+       # 2 commits on branch B, started from A1
+       git checkout -b B A1 &&
+       test_commit B1 foo.txt &&
+       test_commit B2 abc.txt &&
+
+       # 2 commits on branch C, started from A2
+       git checkout -b C A2 &&
+       test_commit C1 xyz.txt &&
+       test_commit C2 xyz.txt &&
+
+       # Octopus merge B and C into branch A
+       git checkout A &&
+       git merge B C &&
+       git tag A4
+
+       test_commit A5 bar.txt &&
+
+       # More commits on C, then merge C into A
+       git checkout C &&
+       test_commit C3 foo.txt &&
+       test_commit C4 bar.txt &&
+       git checkout A &&
+       git merge -s ours C &&
+       git tag A6
+
+       test_commit A7 bar.txt &&
+
+       # Store commit names in variables for later use
+       A1=$(git rev-parse --verify A1) &&
+       A2=$(git rev-parse --verify A2) &&
+       A3=$(git rev-parse --verify A3) &&
+       A4=$(git rev-parse --verify A4) &&
+       A5=$(git rev-parse --verify A5) &&
+       A6=$(git rev-parse --verify A6) &&
+       A7=$(git rev-parse --verify A7) &&
+       B1=$(git rev-parse --verify B1) &&
+       B2=$(git rev-parse --verify B2) &&
+       C1=$(git rev-parse --verify C1) &&
+       C2=$(git rev-parse --verify C2) &&
+       C3=$(git rev-parse --verify C3) &&
+       C4=$(git rev-parse --verify C4)
+       '
+
+test_expect_success '--graph --all' '
+       rm -f expected &&
+       echo "* $A7" >> expected &&
+       echo "*   $A6" >> expected &&
+       echo "|\\  " >> expected &&
+       echo "| * $C4" >> expected &&
+       echo "| * $C3" >> expected &&
+       echo "* | $A5" >> expected &&
+       echo "| |     " >> expected &&
+       echo "|  \\    " >> expected &&
+       echo "*-. \\   $A4" >> expected &&
+       echo "|\\ \\ \\  " >> expected &&
+       echo "| | |/  " >> expected &&
+       echo "| | * $C2" >> expected &&
+       echo "| | * $C1" >> expected &&
+       echo "| * | $B2" >> expected &&
+       echo "| * | $B1" >> expected &&
+       echo "* | | $A3" >> expected &&
+       echo "| |/  " >> expected &&
+       echo "|/|   " >> expected &&
+       echo "* | $A2" >> expected &&
+       echo "|/  " >> expected &&
+       echo "* $A1" >> expected &&
+       git rev-list --graph --all > actual &&
+       test_cmp expected actual
+       '
+
+# Make sure the graph_is_interesting() code still realizes
+# that undecorated merges are interesting, even with --simplify-by-decoration
+test_expect_success '--graph --simplify-by-decoration' '
+       rm -f expected &&
+       git tag -d A4
+       echo "* $A7" >> expected &&
+       echo "*   $A6" >> expected &&
+       echo "|\\  " >> expected &&
+       echo "| * $C4" >> expected &&
+       echo "| * $C3" >> expected &&
+       echo "* | $A5" >> expected &&
+       echo "| |     " >> expected &&
+       echo "|  \\    " >> expected &&
+       echo "*-. \\   $A4" >> expected &&
+       echo "|\\ \\ \\  " >> expected &&
+       echo "| | |/  " >> expected &&
+       echo "| | * $C2" >> expected &&
+       echo "| | * $C1" >> expected &&
+       echo "| * | $B2" >> expected &&
+       echo "| * | $B1" >> expected &&
+       echo "* | | $A3" >> expected &&
+       echo "| |/  " >> expected &&
+       echo "|/|   " >> expected &&
+       echo "* | $A2" >> expected &&
+       echo "|/  " >> expected &&
+       echo "* $A1" >> expected &&
+       git rev-list --graph --all --simplify-by-decoration > actual &&
+       test_cmp expected actual
+       '
+
+# Get rid of all decorations on branch B, and graph with it simplified away
+test_expect_success '--graph --simplify-by-decoration prune branch B' '
+       rm -f expected &&
+       git tag -d B2
+       git tag -d B1
+       git branch -d B
+       echo "* $A7" >> expected &&
+       echo "*   $A6" >> expected &&
+       echo "|\\  " >> expected &&
+       echo "| * $C4" >> expected &&
+       echo "| * $C3" >> expected &&
+       echo "* | $A5" >> expected &&
+       echo "* |   $A4" >> expected &&
+       echo "|\\ \\  " >> expected &&
+       echo "| |/  " >> expected &&
+       echo "| * $C2" >> expected &&
+       echo "| * $C1" >> expected &&
+       echo "* | $A3" >> expected &&
+       echo "|/  " >> expected &&
+       echo "* $A2" >> expected &&
+       echo "* $A1" >> expected &&
+       git rev-list --graph --simplify-by-decoration --all > actual &&
+       test_cmp expected actual
+       '
+
+test_expect_success '--graph --full-history -- bar.txt' '
+       rm -f expected &&
+       git tag -d B2
+       git tag -d B1
+       git branch -d B
+       echo "* $A7" >> expected &&
+       echo "*   $A6" >> expected &&
+       echo "|\\  " >> expected &&
+       echo "| * $C4" >> expected &&
+       echo "* | $A5" >> expected &&
+       echo "* |   $A4" >> expected &&
+       echo "|\\ \\  " >> expected &&
+       echo "| |/  " >> expected &&
+       echo "* | $A3" >> expected &&
+       echo "|/  " >> expected &&
+       echo "* $A2" >> expected &&
+       git rev-list --graph --full-history --all -- bar.txt > actual &&
+       test_cmp expected actual
+       '
+
+test_expect_success '--graph --full-history --simplify-merges -- bar.txt' '
+       rm -f expected &&
+       git tag -d B2
+       git tag -d B1
+       git branch -d B
+       echo "* $A7" >> expected &&
+       echo "*   $A6" >> expected &&
+       echo "|\\  " >> expected &&
+       echo "| * $C4" >> expected &&
+       echo "* | $A5" >> expected &&
+       echo "* | $A3" >> expected &&
+       echo "|/  " >> expected &&
+       echo "* $A2" >> expected &&
+       git rev-list --graph --full-history --simplify-merges --all \
+               -- bar.txt > actual &&
+       test_cmp expected actual
+       '
+
+test_expect_success '--graph -- bar.txt' '
+       rm -f expected &&
+       git tag -d B2
+       git tag -d B1
+       git branch -d B
+       echo "* $A7" >> expected &&
+       echo "* $A5" >> expected &&
+       echo "* $A3" >> expected &&
+       echo "| * $C4" >> expected &&
+       echo "|/  " >> expected &&
+       echo "* $A2" >> expected &&
+       git rev-list --graph --all -- bar.txt > actual &&
+       test_cmp expected actual
+       '
+
+test_expect_success '--graph --sparse -- bar.txt' '
+       rm -f expected &&
+       git tag -d B2
+       git tag -d B1
+       git branch -d B
+       echo "* $A7" >> expected &&
+       echo "* $A6" >> expected &&
+       echo "* $A5" >> expected &&
+       echo "* $A4" >> expected &&
+       echo "* $A3" >> expected &&
+       echo "| * $C4" >> expected &&
+       echo "| * $C3" >> expected &&
+       echo "| * $C2" >> expected &&
+       echo "| * $C1" >> expected &&
+       echo "|/  " >> expected &&
+       echo "* $A2" >> expected &&
+       echo "* $A1" >> expected &&
+       git rev-list --graph --sparse --all -- bar.txt > actual &&
+       test_cmp expected actual
+       '
+
+test_expect_success '--graph ^C4' '
+       rm -f expected &&
+       echo "* $A7" >> expected &&
+       echo "* $A6" >> expected &&
+       echo "* $A5" >> expected &&
+       echo "*   $A4" >> expected &&
+       echo "|\\  " >> expected &&
+       echo "| * $B2" >> expected &&
+       echo "| * $B1" >> expected &&
+       echo "* $A3" >> expected &&
+       git rev-list --graph --all ^C4 > actual &&
+       test_cmp expected actual
+       '
+
+test_expect_success '--graph ^C3' '
+       rm -f expected &&
+       echo "* $A7" >> expected &&
+       echo "*   $A6" >> expected &&
+       echo "|\\  " >> expected &&
+       echo "| * $C4" >> expected &&
+       echo "* $A5" >> expected &&
+       echo "*   $A4" >> expected &&
+       echo "|\\  " >> expected &&
+       echo "| * $B2" >> expected &&
+       echo "| * $B1" >> expected &&
+       echo "* $A3" >> expected &&
+       git rev-list --graph --all ^C3 > actual &&
+       test_cmp expected actual
+       '
+
+# I don't think the ordering of the boundary commits is really
+# that important, but this test depends on it.  If the ordering ever changes
+# in the code, we'll need to update this test.
+test_expect_success '--graph --boundary ^C3' '
+       rm -f expected &&
+       echo "* $A7" >> expected &&
+       echo "*   $A6" >> expected &&
+       echo "|\\  " >> expected &&
+       echo "| * $C4" >> expected &&
+       echo "* | $A5" >> expected &&
+       echo "| |     " >> expected &&
+       echo "|  \\    " >> expected &&
+       echo "*-. \\   $A4" >> expected &&
+       echo "|\\ \\ \\  " >> expected &&
+       echo "| * | | $B2" >> expected &&
+       echo "| * | | $B1" >> expected &&
+       echo "* | | | $A3" >> expected &&
+       echo "o | | | $A2" >> expected &&
+       echo "|/ / /  " >> expected &&
+       echo "o | | $A1" >> expected &&
+       echo " / /  " >> expected &&
+       echo "| o $C3" >> expected &&
+       echo "|/  " >> expected &&
+       echo "o $C2" >> expected &&
+       git rev-list --graph --boundary --all ^C3 > actual &&
+       test_cmp expected actual
+       '
+
+test_done
index 1315bab595c03f16b89060434588b505faf1c46b..def397c53a76dead449710eaca6333c2e1fb36aa 100755 (executable)
@@ -175,7 +175,7 @@ test_expect_success 'bisect skip: successfull result' '
        git bisect start $HASH4 $HASH1 &&
        git bisect skip &&
        git bisect bad > my_bisect_log.txt &&
-       grep "$HASH2 is first bad commit" my_bisect_log.txt &&
+       grep "$HASH2 is the first bad commit" my_bisect_log.txt &&
        git bisect reset
 '
 
@@ -261,7 +261,7 @@ test_expect_success \
      git bisect good $HASH1 &&
      git bisect bad $HASH4 &&
      git bisect run ./test_script.sh > my_bisect_log.txt &&
-     grep "$HASH3 is first bad commit" my_bisect_log.txt &&
+     grep "$HASH3 is the first bad commit" my_bisect_log.txt &&
      git bisect reset'
 
 # We want to automatically find the commit that
@@ -274,7 +274,7 @@ test_expect_success \
      chmod +x test_script.sh &&
      git bisect start $HASH4 $HASH1 &&
      git bisect run ./test_script.sh > my_bisect_log.txt &&
-     grep "$HASH4 is first bad commit" my_bisect_log.txt &&
+     grep "$HASH4 is the first bad commit" my_bisect_log.txt &&
      git bisect reset'
 
 # $HASH1 is good, $HASH5 is bad, we skip $HASH3
@@ -287,14 +287,14 @@ test_expect_success 'bisect skip: add line and then a new test' '
        git bisect start $HASH5 $HASH1 &&
        git bisect skip &&
        git bisect good > my_bisect_log.txt &&
-       grep "$HASH5 is first bad commit" my_bisect_log.txt &&
+       grep "$HASH5 is the first bad commit" my_bisect_log.txt &&
        git bisect log > log_to_replay.txt &&
        git bisect reset
 '
 
 test_expect_success 'bisect skip and bisect replay' '
        git bisect replay log_to_replay.txt > my_bisect_log.txt &&
-       grep "$HASH5 is first bad commit" my_bisect_log.txt &&
+       grep "$HASH5 is the first bad commit" my_bisect_log.txt &&
        git bisect reset
 '
 
@@ -335,7 +335,7 @@ test_expect_success 'bisect run & skip: find first bad' '
        chmod +x test_script.sh &&
        git bisect start $HASH7 $HASH1 &&
        git bisect run ./test_script.sh > my_bisect_log.txt &&
-       grep "$HASH6 is first bad commit" my_bisect_log.txt
+       grep "$HASH6 is the first bad commit" my_bisect_log.txt
 '
 
 test_expect_success 'bisect skip only one range' '
@@ -385,7 +385,7 @@ test_expect_success 'bisect does not create a "bisect" branch' '
        rev_hash6=$(git rev-parse --verify HEAD) &&
        test "$rev_hash6" = "$HASH6" &&
        git bisect good > my_bisect_log.txt &&
-       grep "$HASH7 is first bad commit" my_bisect_log.txt &&
+       grep "$HASH7 is the first bad commit" my_bisect_log.txt &&
        git bisect reset &&
        rev_hash6=$(git rev-parse --verify bisect) &&
        test "$rev_hash6" = "$HASH6" &&
@@ -534,7 +534,7 @@ test_expect_success 'restricting bisection on one dir' '
        para1=$(git rev-parse --verify HEAD) &&
        test "$para1" = "$PARA_HASH1" &&
        git bisect bad > my_bisect_log.txt &&
-       grep "$PARA_HASH1 is first bad commit" my_bisect_log.txt
+       grep "$PARA_HASH1 is the first bad commit" my_bisect_log.txt
 '
 
 test_expect_success 'restricting bisection on one dir and a file' '
@@ -552,7 +552,7 @@ test_expect_success 'restricting bisection on one dir and a file' '
        para1=$(git rev-parse --verify HEAD) &&
        test "$para1" = "$PARA_HASH1" &&
        git bisect good > my_bisect_log.txt &&
-       grep "$PARA_HASH4 is first bad commit" my_bisect_log.txt
+       grep "$PARA_HASH4 is the first bad commit" my_bisect_log.txt
 '
 
 test_expect_success 'skipping away from skipped commit' '
diff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh
new file mode 100755 (executable)
index 0000000..1044aa6
--- /dev/null
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+test_description='basic work tree status reporting'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+       test_commit A &&
+       test_commit B oneside added &&
+       git checkout A^0 &&
+       test_commit C oneside created
+'
+
+test_expect_success 'A/A conflict' '
+       git checkout B^0 &&
+       test_must_fail git merge C
+'
+
+test_expect_success 'Report path with conflict' '
+       git diff --cached --name-status >actual &&
+       echo "U oneside" >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'Report new path with conflict' '
+       git diff --cached --name-status HEAD^ >actual &&
+       echo "U oneside" >expect &&
+       test_cmp expect actual
+'
+
+cat >expect <<EOF
+# On branch side
+# Unmerged paths:
+#   (use "git reset HEAD <file>..." to unstage)
+#   (use "git add <file>..." to mark resolution)
+#
+#      deleted by us:      foo
+#
+no changes added to commit (use "git add" and/or "git commit -a")
+EOF
+
+test_expect_success 'M/D conflict does not segfault' '
+       mkdir mdconflict &&
+       (
+               cd mdconflict &&
+               git init &&
+               test_commit initial foo "" &&
+               test_commit modify foo foo &&
+               git checkout -b side HEAD^ &&
+               git rm foo &&
+               git commit -m delete &&
+               test_must_fail git merge master &&
+               test_must_fail git status > ../actual
+       ) &&
+       test_cmp expect actual
+'
+
+test_done
index e637c7d4dbdce337b4d005719c4aa86d447a70d9..e85ff02c3e636567a80586e92fdba1c5382fc995 100755 (executable)
@@ -419,7 +419,8 @@ test_expect_success 'resetting an unmodified path is a no-op' '
 '
 
 cat > expect << EOF
-file2: locally modified
+Unstaged changes after reset:
+M      file2
 EOF
 
 test_expect_success '--mixed refreshes the index' '
index 61498293b99e1cbbb4bfb4de45b6d14488aaddd0..6cc16c39fe75ee9dab942fc5ae376827d3b7ea44 100755 (executable)
@@ -56,6 +56,15 @@ test_expect_success 'modified submodule(forward)' "
 EOF
 "
 
+test_expect_success 'modified submodule(forward), --files' "
+       git submodule summary --files >actual &&
+       diff actual - <<-EOF
+* sm1 $head1...$head2 (1):
+  > Add foo3
+
+EOF
+"
+
 commit_file sm1 &&
 cd sm1 &&
 git reset --hard HEAD~2 >/dev/null &&
@@ -114,6 +123,15 @@ test_expect_success 'typechanged submodule(submodule->blob), --cached' "
 EOF
 "
 
+test_expect_success 'typechanged submodule(submodule->blob), --files' "
+    git submodule summary --files >actual &&
+    diff actual - <<-EOF
+* sm1 $head5(blob)->$head4(submodule) (3):
+  > Add foo5
+
+EOF
+"
+
 rm -rf sm1 &&
 git checkout-index sm1
 test_expect_success 'typechanged submodule(submodule->blob)' "
@@ -205,4 +223,8 @@ test_expect_success '--for-status' "
 EOF
 "
 
+test_expect_success 'fail when using --files together with --cached' "
+    test_must_fail git submodule summary --files --cached
+"
+
 test_done
diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
new file mode 100755 (executable)
index 0000000..2a52775
--- /dev/null
@@ -0,0 +1,237 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 Johan Herland
+#
+
+test_description='Test "git submodule foreach"
+
+This test verifies that "git submodule foreach" correctly visits all submodules
+that are currently checked out.
+'
+
+. ./test-lib.sh
+
+
+test_expect_success 'setup a submodule tree' '
+       echo file > file &&
+       git add file &&
+       test_tick &&
+       git commit -m upstream
+       git clone . super &&
+       git clone super submodule &&
+       (
+               cd super &&
+               git submodule add ../submodule sub1 &&
+               git submodule add ../submodule sub2 &&
+               git submodule add ../submodule sub3 &&
+               git config -f .gitmodules --rename-section \
+                       submodule.sub1 submodule.foo1 &&
+               git config -f .gitmodules --rename-section \
+                       submodule.sub2 submodule.foo2 &&
+               git config -f .gitmodules --rename-section \
+                       submodule.sub3 submodule.foo3 &&
+               git add .gitmodules
+               test_tick &&
+               git commit -m "submodules" &&
+               git submodule init sub1 &&
+               git submodule init sub2 &&
+               git submodule init sub3
+       ) &&
+       (
+               cd submodule &&
+               echo different > file &&
+               git add file &&
+               test_tick &&
+               git commit -m "different"
+       ) &&
+       (
+               cd super &&
+               (
+                       cd sub3 &&
+                       git pull
+               ) &&
+               git add sub3 &&
+               test_tick &&
+               git commit -m "update sub3"
+       )
+'
+
+sub1sha1=$(cd super/sub1 && git rev-parse HEAD)
+sub3sha1=$(cd super/sub3 && git rev-parse HEAD)
+
+cat > expect <<EOF
+Entering 'sub1'
+foo1-sub1-$sub1sha1
+Entering 'sub3'
+foo3-sub3-$sub3sha1
+EOF
+
+test_expect_success 'test basic "submodule foreach" usage' '
+       git clone super clone &&
+       (
+               cd clone &&
+               git submodule update --init -- sub1 sub3 &&
+               git submodule foreach "echo \$name-\$path-\$sha1" > ../actual
+       ) &&
+       test_cmp expect actual
+'
+
+test_expect_success 'setup nested submodules' '
+       git clone submodule nested1 &&
+       git clone submodule nested2 &&
+       git clone submodule nested3 &&
+       (
+               cd nested3 &&
+               git submodule add ../submodule submodule &&
+               test_tick &&
+               git commit -m "submodule" &&
+               git submodule init submodule
+       ) &&
+       (
+               cd nested2 &&
+               git submodule add ../nested3 nested3 &&
+               test_tick &&
+               git commit -m "nested3" &&
+               git submodule init nested3
+       ) &&
+       (
+               cd nested1 &&
+               git submodule add ../nested2 nested2 &&
+               test_tick &&
+               git commit -m "nested2" &&
+               git submodule init nested2
+       ) &&
+       (
+               cd super &&
+               git submodule add ../nested1 nested1 &&
+               test_tick &&
+               git commit -m "nested1" &&
+               git submodule init nested1
+       )
+'
+
+test_expect_success 'use "submodule foreach" to checkout 2nd level submodule' '
+       git clone super clone2 &&
+       (
+               cd clone2 &&
+               test ! -d sub1/.git &&
+               test ! -d sub2/.git &&
+               test ! -d sub3/.git &&
+               test ! -d nested1/.git &&
+               git submodule update --init &&
+               test -d sub1/.git &&
+               test -d sub2/.git &&
+               test -d sub3/.git &&
+               test -d nested1/.git &&
+               test ! -d nested1/nested2/.git &&
+               git submodule foreach "git submodule update --init" &&
+               test -d nested1/nested2/.git &&
+               test ! -d nested1/nested2/nested3/.git
+       )
+'
+
+test_expect_success 'use "foreach --recursive" to checkout all submodules' '
+       (
+               cd clone2 &&
+               git submodule foreach --recursive "git submodule update --init" &&
+               test -d nested1/nested2/nested3/.git &&
+               test -d nested1/nested2/nested3/submodule/.git
+       )
+'
+
+cat > expect <<EOF
+Entering 'nested1'
+Entering 'nested1/nested2'
+Entering 'nested1/nested2/nested3'
+Entering 'nested1/nested2/nested3/submodule'
+Entering 'sub1'
+Entering 'sub2'
+Entering 'sub3'
+EOF
+
+test_expect_success 'test messages from "foreach --recursive"' '
+       (
+               cd clone2 &&
+               git submodule foreach --recursive "true" > ../actual
+       ) &&
+       test_cmp expect actual
+'
+
+cat > expect <<EOF
+nested1-nested1
+nested2-nested2
+nested3-nested3
+submodule-submodule
+foo1-sub1
+foo2-sub2
+foo3-sub3
+EOF
+
+test_expect_success 'test "foreach --quiet --recursive"' '
+       (
+               cd clone2 &&
+               git submodule foreach -q --recursive "echo \$name-\$path" > ../actual
+       ) &&
+       test_cmp expect actual
+'
+
+test_expect_success 'use "update --recursive" to checkout all submodules' '
+       git clone super clone3 &&
+       (
+               cd clone3 &&
+               test ! -d sub1/.git &&
+               test ! -d sub2/.git &&
+               test ! -d sub3/.git &&
+               test ! -d nested1/.git &&
+               git submodule update --init --recursive &&
+               test -d sub1/.git &&
+               test -d sub2/.git &&
+               test -d sub3/.git &&
+               test -d nested1/.git &&
+               test -d nested1/nested2/.git &&
+               test -d nested1/nested2/nested3/.git &&
+               test -d nested1/nested2/nested3/submodule/.git
+       )
+'
+
+nested1sha1=$(cd clone3/nested1 && git rev-parse HEAD)
+nested2sha1=$(cd clone3/nested1/nested2 && git rev-parse HEAD)
+nested3sha1=$(cd clone3/nested1/nested2/nested3 && git rev-parse HEAD)
+submodulesha1=$(cd clone3/nested1/nested2/nested3/submodule && git rev-parse HEAD)
+sub1sha1=$(cd clone3/sub1 && git rev-parse HEAD)
+sub2sha1=$(cd clone3/sub2 && git rev-parse HEAD)
+sub3sha1=$(cd clone3/sub3 && git rev-parse HEAD)
+sub1sha1_short=$(cd clone3/sub1 && git rev-parse --short HEAD)
+sub2sha1_short=$(cd clone3/sub2 && git rev-parse --short HEAD)
+
+cat > expect <<EOF
+ $nested1sha1 nested1 (heads/master)
+ $nested2sha1 nested1/nested2 (heads/master)
+ $nested3sha1 nested1/nested2/nested3 (heads/master)
+ $submodulesha1 nested1/nested2/nested3/submodule (heads/master)
+ $sub1sha1 sub1 ($sub1sha1_short)
+ $sub2sha1 sub2 ($sub2sha1_short)
+ $sub3sha1 sub3 (heads/master)
+EOF
+
+test_expect_success 'test "status --recursive"' '
+       (
+               cd clone3 &&
+               git submodule status --recursive > ../actual
+       ) &&
+       test_cmp expect actual
+'
+
+test_expect_success 'use "git clone --recursive" to checkout all submodules' '
+       git clone --recursive super clone4 &&
+       test -d clone4/.git &&
+       test -d clone4/sub1/.git &&
+       test -d clone4/sub2/.git &&
+       test -d clone4/sub3/.git &&
+       test -d clone4/nested1/.git &&
+       test -d clone4/nested1/nested2/.git &&
+       test -d clone4/nested1/nested2/nested3/.git &&
+       test -d clone4/nested1/nested2/nested3/submodule/.git
+'
+
+test_done
diff --git a/t/t8005/iso8859-5.txt b/t/t8005/iso8859-5.txt
deleted file mode 100644 (file)
index 2e4b80c..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-ISO8859_5_NAME="¸ÒÐÝ ¿ÕâàÞÒØç ÁØÔÞàÞÒ"
-ISO8859_5_MSG="ÂÕáâÞÒÞÕ áÞÞÑéÕÝØÕ"
index 627518108acfbab990fc259412e395150c1fb5b1..2fc7fdb124583f86d5be622510f29ceca1dd3e09 100755 (executable)
@@ -9,73 +9,8 @@ This test runs gitweb (git web interface) as CGI script from
 commandline, and checks that it would not write any errors
 or warnings to log.'
 
-gitweb_init () {
-       safe_pwd="$(perl -MPOSIX=getcwd -e 'print quotemeta(getcwd)')"
-       cat >gitweb_config.perl <<EOF
-#!/usr/bin/perl
-
-# gitweb configuration for tests
-
-our \$version = "current";
-our \$GIT = "git";
-our \$projectroot = "$safe_pwd";
-our \$project_maxdepth = 8;
-our \$home_link_str = "projects";
-our \$site_name = "[localhost]";
-our \$site_header = "";
-our \$site_footer = "";
-our \$home_text = "indextext.html";
-our @stylesheets = ("file:///$TEST_DIRECTORY/../gitweb/gitweb.css");
-our \$logo = "file:///$TEST_DIRECTORY/../gitweb/git-logo.png";
-our \$favicon = "file:///$TEST_DIRECTORY/../gitweb/git-favicon.png";
-our \$projects_list = "";
-our \$export_ok = "";
-our \$strict_export = "";
 
-EOF
-
-       cat >.git/description <<EOF
-$0 test repository
-EOF
-}
-
-gitweb_run () {
-       GATEWAY_INTERFACE="CGI/1.1"
-       HTTP_ACCEPT="*/*"
-       REQUEST_METHOD="GET"
-       SCRIPT_NAME="$TEST_DIRECTORY/../gitweb/gitweb.perl"
-       QUERY_STRING=""$1""
-       PATH_INFO=""$2""
-       export GATEWAY_INTERFACE HTTP_ACCEPT REQUEST_METHOD \
-               SCRIPT_NAME QUERY_STRING PATH_INFO
-
-       GITWEB_CONFIG=$(pwd)/gitweb_config.perl
-       export GITWEB_CONFIG
-
-       # some of git commands write to STDERR on error, but this is not
-       # written to web server logs, so we are not interested in that:
-       # we are interested only in properly formatted errors/warnings
-       rm -f gitweb.log &&
-       perl -- "$SCRIPT_NAME" \
-               >/dev/null 2>gitweb.log &&
-       if grep "^[[]" gitweb.log >/dev/null 2>&1; then false; else true; fi
-
-       # gitweb.log is left for debugging
-}
-
-. ./test-lib.sh
-
-if ! test_have_prereq PERL; then
-       say 'skipping gitweb tests, perl not available'
-       test_done
-fi
-
-perl -MEncode -e 'decode_utf8("", Encode::FB_CROAK)' >/dev/null 2>&1 || {
-    say 'skipping gitweb tests, perl version is too old'
-    test_done
-}
-
-gitweb_init
+. ./gitweb-lib.sh
 
 # ----------------------------------------------------------------------
 # no commits (empty, just initialized repository)
diff --git a/t/t9501-gitweb-standalone-http-status.sh b/t/t9501-gitweb-standalone-http-status.sh
new file mode 100644 (file)
index 0000000..d0ff21d
--- /dev/null
@@ -0,0 +1,78 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 Mark Rada
+#
+
+test_description='gitweb as standalone script (http status tests).
+
+This test runs gitweb (git web interface) as a CGI script from the
+commandline, and checks that it returns the expected HTTP status
+code and message.'
+
+
+. ./gitweb-lib.sh
+
+# ----------------------------------------------------------------------
+# snapshot settings
+
+test_commit \
+       'SnapshotTests' \
+       'i can has snapshot?'
+
+cat >>gitweb_config.perl <<\EOF
+$feature{'snapshot'}{'override'} = 0;
+EOF
+
+test_expect_success \
+    'snapshots: tgz only default format enabled' \
+    'gitweb_run "p=.git;a=snapshot;h=HEAD;sf=tgz" &&
+    grep "Status: 200 OK" gitweb.output &&
+    gitweb_run "p=.git;a=snapshot;h=HEAD;sf=tbz2" &&
+    grep "403 - Unsupported snapshot format" gitweb.output &&
+    gitweb_run "p=.git;a=snapshot;h=HEAD;sf=txz" &&
+    grep "403 - Snapshot format not allowed" gitweb.output &&
+    gitweb_run "p=.git;a=snapshot;h=HEAD;sf=zip" &&
+    grep "403 - Unsupported snapshot format" gitweb.output'
+test_debug 'cat gitweb.output'
+
+
+cat >>gitweb_config.perl <<\EOF
+$feature{'snapshot'}{'default'} = ['tgz','tbz2','txz','zip'];
+EOF
+
+test_expect_success \
+    'snapshots: all enabled in default, use default disabled value' \
+    'gitweb_run "p=.git;a=snapshot;h=HEAD;sf=tgz" &&
+    grep "Status: 200 OK" gitweb.output &&
+    gitweb_run "p=.git;a=snapshot;h=HEAD;sf=tbz2" &&
+    grep "Status: 200 OK" gitweb.output &&
+    gitweb_run "p=.git;a=snapshot;h=HEAD;sf=txz" &&
+    grep "403 - Snapshot format not allowed" gitweb.output &&
+    gitweb_run "p=.git;a=snapshot;h=HEAD;sf=zip" &&
+    grep "Status: 200 OK" gitweb.output'
+test_debug 'cat gitweb.output'
+
+
+cat >>gitweb_config.perl <<\EOF
+$known_snapshot_formats{'zip'}{'disabled'} = 1;
+EOF
+
+test_expect_success \
+    'snapshots: zip explicitly disabled' \
+    'gitweb_run "p=.git;a=snapshot;h=HEAD;sf=zip" &&
+    grep "403 - Snapshot format not allowed" gitweb.output'
+test_debug 'cat gitweb.output'
+
+
+cat >>gitweb_config.perl <<\EOF
+$known_snapshot_formats{'tgz'}{'disabled'} = 0;
+EOF
+
+test_expect_success \
+    'snapshots: tgz explicitly enabled' \
+    'gitweb_run "p=.git;a=snapshot;h=HEAD;sf=tgz" &&
+    grep "Status: 200 OK" gitweb.output'
+test_debug 'cat gitweb.output'
+
+
+test_done
index a5b8d03db0fc88c42e38cdde13a6cd2b14c06581..f2ca5364722e9c85a23bdfdcf1e24122fd5e3a0f 100644 (file)
@@ -685,6 +685,21 @@ do
        esac
 done
 
+# Provide an implementation of the 'yes' utility
+yes () {
+       if test $# = 0
+       then
+               y=y
+       else
+               y="$*"
+       fi
+
+       while echo "$y"
+       do
+               :
+       done
+}
+
 # Fix some commands on Windows
 case $(uname -s) in
 *MINGW*)
index faee154c383c9726017f1995121b510f770b655e..f7e1663d18087f708da926d0978a4a3377ae2b50 100644 (file)
@@ -1059,11 +1059,12 @@ const struct ref *transport_get_remote_refs(struct transport *transport)
 int transport_fetch_refs(struct transport *transport, const struct ref *refs)
 {
        int rc;
-       int nr_heads = 0, nr_alloc = 0;
+       int nr_heads = 0, nr_alloc = 0, nr_refs = 0;
        const struct ref **heads = NULL;
        const struct ref *rm;
 
        for (rm = refs; rm; rm = rm->next) {
+               nr_refs++;
                if (rm->peer_ref &&
                    !hashcmp(rm->peer_ref->old_sha1, rm->old_sha1))
                        continue;
@@ -1071,6 +1072,19 @@ int transport_fetch_refs(struct transport *transport, const struct ref *refs)
                heads[nr_heads++] = rm;
        }
 
+       if (!nr_heads) {
+               /*
+                * When deepening of a shallow repository is requested,
+                * then local and remote refs are likely to still be equal.
+                * Just feed them all to the fetch method in that case.
+                * This condition shouldn't be met in a non-deepening fetch
+                * (see builtin-fetch.c:quickfetch()).
+                */
+               heads = xmalloc(nr_refs * sizeof(*heads));
+               for (rm = refs; rm; rm = rm->next)
+                       heads[nr_heads++] = rm;
+       }
+
        rc = transport->fetch(transport, nr_heads, heads);
        free(heads);
        return rc;
diff --git a/update-server-info.c b/update-server-info.c
deleted file mode 100644 (file)
index 7b38fd8..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#include "cache.h"
-#include "exec_cmd.h"
-
-static const char update_server_info_usage[] =
-"git update-server-info [--force]";
-
-int main(int ac, char **av)
-{
-       int i;
-       int force = 0;
-       for (i = 1; i < ac; i++) {
-               if (av[i][0] == '-') {
-                       if (!strcmp("--force", av[i]) ||
-                           !strcmp("-f", av[i]))
-                               force = 1;
-                       else
-                               usage(update_server_info_usage);
-               }
-       }
-       if (i != ac)
-               usage(update_server_info_usage);
-
-       git_extract_argv0_path(av[0]);
-
-       setup_git_directory();
-
-       return !!update_server_info(force);
-}
index 47735d8129fd3632b85d54b451e30752f251a949..63598ce40cdad4bc9acc5446d304f0512341f973 100644 (file)
@@ -1,6 +1,5 @@
 #include "cache.h"
 #include "wt-status.h"
-#include "color.h"
 #include "object.h"
 #include "dir.h"
 #include "commit.h"
 #include "run-command.h"
 #include "remote.h"
 
-int wt_status_relative_paths = 1;
-int wt_status_use_color = -1;
-static int wt_status_submodule_summary;
-static char wt_status_colors[][COLOR_MAXLEN] = {
+static char default_wt_status_colors[][COLOR_MAXLEN] = {
        GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */
        GIT_COLOR_GREEN,  /* WT_STATUS_UPDATED */
        GIT_COLOR_RED,    /* WT_STATUS_CHANGED */
        GIT_COLOR_RED,    /* WT_STATUS_UNTRACKED */
        GIT_COLOR_RED,    /* WT_STATUS_NOBRANCH */
+       GIT_COLOR_RED,    /* WT_STATUS_UNMERGED */
 };
 
-enum untracked_status_type show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
-
-static int parse_status_slot(const char *var, int offset)
-{
-       if (!strcasecmp(var+offset, "header"))
-               return WT_STATUS_HEADER;
-       if (!strcasecmp(var+offset, "updated")
-               || !strcasecmp(var+offset, "added"))
-               return WT_STATUS_UPDATED;
-       if (!strcasecmp(var+offset, "changed"))
-               return WT_STATUS_CHANGED;
-       if (!strcasecmp(var+offset, "untracked"))
-               return WT_STATUS_UNTRACKED;
-       if (!strcasecmp(var+offset, "nobranch"))
-               return WT_STATUS_NOBRANCH;
-       die("bad config variable '%s'", var);
-}
-
-static const char *color(int slot)
+static const char *color(int slot, struct wt_status *s)
 {
-       return wt_status_use_color > 0 ? wt_status_colors[slot] : "";
+       return s->use_color > 0 ? s->color_palette[slot] : "";
 }
 
 void wt_status_prepare(struct wt_status *s)
@@ -51,16 +30,35 @@ void wt_status_prepare(struct wt_status *s)
        const char *head;
 
        memset(s, 0, sizeof(*s));
+       memcpy(s->color_palette, default_wt_status_colors,
+              sizeof(default_wt_status_colors));
+       s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
+       s->use_color = -1;
+       s->relative_paths = 1;
        head = resolve_ref("HEAD", sha1, 0, NULL);
        s->branch = head ? xstrdup(head) : NULL;
        s->reference = "HEAD";
        s->fp = stdout;
        s->index_file = get_index_file();
+       s->change.strdup_strings = 1;
+       s->untracked.strdup_strings = 1;
+}
+
+static void wt_status_print_unmerged_header(struct wt_status *s)
+{
+       const char *c = color(WT_STATUS_HEADER, s);
+       color_fprintf_ln(s->fp, c, "# Unmerged paths:");
+       if (!s->is_initial)
+               color_fprintf_ln(s->fp, c, "#   (use \"git reset %s <file>...\" to unstage)", s->reference);
+       else
+               color_fprintf_ln(s->fp, c, "#   (use \"git rm --cached <file>...\" to unstage)");
+       color_fprintf_ln(s->fp, c, "#   (use \"git add <file>...\" to mark resolution)");
+       color_fprintf_ln(s->fp, c, "#");
 }
 
 static void wt_status_print_cached_header(struct wt_status *s)
 {
-       const char *c = color(WT_STATUS_HEADER);
+       const char *c = color(WT_STATUS_HEADER, s);
        color_fprintf_ln(s->fp, c, "# Changes to be committed:");
        if (!s->is_initial) {
                color_fprintf_ln(s->fp, c, "#   (use \"git reset %s <file>...\" to unstage)", s->reference);
@@ -73,7 +71,7 @@ static void wt_status_print_cached_header(struct wt_status *s)
 static void wt_status_print_dirty_header(struct wt_status *s,
                                         int has_deleted)
 {
-       const char *c = color(WT_STATUS_HEADER);
+       const char *c = color(WT_STATUS_HEADER, s);
        color_fprintf_ln(s->fp, c, "# Changed but not updated:");
        if (!has_deleted)
                color_fprintf_ln(s->fp, c, "#   (use \"git add <file>...\" to update what will be committed)");
@@ -85,7 +83,7 @@ static void wt_status_print_dirty_header(struct wt_status *s,
 
 static void wt_status_print_untracked_header(struct wt_status *s)
 {
-       const char *c = color(WT_STATUS_HEADER);
+       const char *c = color(WT_STATUS_HEADER, s);
        color_fprintf_ln(s->fp, c, "# Untracked files:");
        color_fprintf_ln(s->fp, c, "#   (use \"git add <file>...\" to include in what will be committed)");
        color_fprintf_ln(s->fp, c, "#");
@@ -93,23 +91,63 @@ static void wt_status_print_untracked_header(struct wt_status *s)
 
 static void wt_status_print_trailer(struct wt_status *s)
 {
-       color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
+       color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
 }
 
 #define quote_path quote_path_relative
 
-static void wt_status_print_filepair(struct wt_status *s,
-                                    int t, struct diff_filepair *p)
+static void wt_status_print_unmerged_data(struct wt_status *s,
+                                         struct string_list_item *it)
 {
-       const char *c = color(t);
+       const char *c = color(WT_STATUS_UNMERGED, s);
+       struct wt_status_change_data *d = it->util;
+       struct strbuf onebuf = STRBUF_INIT;
+       const char *one, *how = "bug";
+
+       one = quote_path(it->string, -1, &onebuf, s->prefix);
+       color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t");
+       switch (d->stagemask) {
+       case 1: how = "both deleted:"; break;
+       case 2: how = "added by us:"; break;
+       case 3: how = "deleted by them:"; break;
+       case 4: how = "added by them:"; break;
+       case 5: how = "deleted by us:"; break;
+       case 6: how = "both added:"; break;
+       case 7: how = "both modified:"; break;
+       }
+       color_fprintf(s->fp, c, "%-20s%s\n", how, one);
+       strbuf_release(&onebuf);
+}
+
+static void wt_status_print_change_data(struct wt_status *s,
+                                       int change_type,
+                                       struct string_list_item *it)
+{
+       struct wt_status_change_data *d = it->util;
+       const char *c = color(change_type, s);
+       int status = status;
+       char *one_name;
+       char *two_name;
        const char *one, *two;
        struct strbuf onebuf = STRBUF_INIT, twobuf = STRBUF_INIT;
 
-       one = quote_path(p->one->path, -1, &onebuf, s->prefix);
-       two = quote_path(p->two->path, -1, &twobuf, s->prefix);
+       one_name = two_name = it->string;
+       switch (change_type) {
+       case WT_STATUS_UPDATED:
+               status = d->index_status;
+               if (d->head_path)
+                       one_name = d->head_path;
+               break;
+       case WT_STATUS_CHANGED:
+               status = d->worktree_status;
+               break;
+       }
 
-       color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t");
-       switch (p->status) {
+       one = quote_path(one_name, -1, &onebuf, s->prefix);
+       two = quote_path(two_name, -1, &twobuf, s->prefix);
+
+       color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t");
+       switch (status) {
        case DIFF_STATUS_ADDED:
                color_fprintf(s->fp, c, "new file:   %s", one);
                break;
@@ -135,64 +173,114 @@ static void wt_status_print_filepair(struct wt_status *s,
                color_fprintf(s->fp, c, "unmerged:   %s", one);
                break;
        default:
-               die("bug: unhandled diff status %c", p->status);
+               die("bug: unhandled diff status %c", status);
        }
        fprintf(s->fp, "\n");
        strbuf_release(&onebuf);
        strbuf_release(&twobuf);
 }
 
-static void wt_status_print_updated_cb(struct diff_queue_struct *q,
-               struct diff_options *options,
-               void *data)
+static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
+                                        struct diff_options *options,
+                                        void *data)
 {
        struct wt_status *s = data;
-       int shown_header = 0;
        int i;
+
+       if (!q->nr)
+               return;
+       s->workdir_dirty = 1;
        for (i = 0; i < q->nr; i++) {
-               if (q->queue[i]->status == 'U')
-                       continue;
-               if (!shown_header) {
-                       wt_status_print_cached_header(s);
-                       s->commitable = 1;
-                       shown_header = 1;
+               struct diff_filepair *p;
+               struct string_list_item *it;
+               struct wt_status_change_data *d;
+
+               p = q->queue[i];
+               it = string_list_insert(p->one->path, &s->change);
+               d = it->util;
+               if (!d) {
+                       d = xcalloc(1, sizeof(*d));
+                       it->util = d;
                }
-               wt_status_print_filepair(s, WT_STATUS_UPDATED, q->queue[i]);
+               if (!d->worktree_status)
+                       d->worktree_status = p->status;
        }
-       if (shown_header)
-               wt_status_print_trailer(s);
 }
 
-static void wt_status_print_changed_cb(struct diff_queue_struct *q,
-                        struct diff_options *options,
-                        void *data)
+static int unmerged_mask(const char *path)
+{
+       int pos, mask;
+       struct cache_entry *ce;
+
+       pos = cache_name_pos(path, strlen(path));
+       if (0 <= pos)
+               return 0;
+
+       mask = 0;
+       pos = -pos-1;
+       while (pos < active_nr) {
+               ce = active_cache[pos++];
+               if (strcmp(ce->name, path) || !ce_stage(ce))
+                       break;
+               mask |= (1 << (ce_stage(ce) - 1));
+       }
+       return mask;
+}
+
+static void wt_status_collect_updated_cb(struct diff_queue_struct *q,
+                                        struct diff_options *options,
+                                        void *data)
 {
        struct wt_status *s = data;
        int i;
-       if (q->nr) {
-               int has_deleted = 0;
-               s->workdir_dirty = 1;
-               for (i = 0; i < q->nr; i++)
-                       if (q->queue[i]->status == DIFF_STATUS_DELETED) {
-                               has_deleted = 1;
-                               break;
-                       }
-               wt_status_print_dirty_header(s, has_deleted);
+
+       for (i = 0; i < q->nr; i++) {
+               struct diff_filepair *p;
+               struct string_list_item *it;
+               struct wt_status_change_data *d;
+
+               p = q->queue[i];
+               it = string_list_insert(p->two->path, &s->change);
+               d = it->util;
+               if (!d) {
+                       d = xcalloc(1, sizeof(*d));
+                       it->util = d;
+               }
+               if (!d->index_status)
+                       d->index_status = p->status;
+               switch (p->status) {
+               case DIFF_STATUS_COPIED:
+               case DIFF_STATUS_RENAMED:
+                       d->head_path = xstrdup(p->one->path);
+                       break;
+               case DIFF_STATUS_UNMERGED:
+                       d->stagemask = unmerged_mask(p->two->path);
+                       break;
+               }
        }
-       for (i = 0; i < q->nr; i++)
-               wt_status_print_filepair(s, WT_STATUS_CHANGED, q->queue[i]);
-       if (q->nr)
-               wt_status_print_trailer(s);
 }
 
-static void wt_status_print_updated(struct wt_status *s)
+static void wt_status_collect_changes_worktree(struct wt_status *s)
 {
        struct rev_info rev;
+
+       init_revisions(&rev, NULL);
+       setup_revisions(0, NULL, &rev, NULL);
+       rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
+       rev.diffopt.format_callback = wt_status_collect_changed_cb;
+       rev.diffopt.format_callback_data = s;
+       run_diff_files(&rev, 0);
+}
+
+static void wt_status_collect_changes_index(struct wt_status *s)
+{
+       struct rev_info rev;
+
        init_revisions(&rev, NULL);
        setup_revisions(0, NULL, &rev,
                s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference);
        rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
-       rev.diffopt.format_callback = wt_status_print_updated_cb;
+       rev.diffopt.format_callback = wt_status_collect_updated_cb;
        rev.diffopt.format_callback_data = s;
        rev.diffopt.detect_rename = 1;
        rev.diffopt.rename_limit = 200;
@@ -200,15 +288,155 @@ static void wt_status_print_updated(struct wt_status *s)
        run_diff_index(&rev, 1);
 }
 
+static void wt_status_collect_changes_initial(struct wt_status *s)
+{
+       int i;
+
+       for (i = 0; i < active_nr; i++) {
+               struct string_list_item *it;
+               struct wt_status_change_data *d;
+               struct cache_entry *ce = active_cache[i];
+
+               it = string_list_insert(ce->name, &s->change);
+               d = it->util;
+               if (!d) {
+                       d = xcalloc(1, sizeof(*d));
+                       it->util = d;
+               }
+               if (ce_stage(ce)) {
+                       d->index_status = DIFF_STATUS_UNMERGED;
+                       d->stagemask |= (1 << (ce_stage(ce) - 1));
+               }
+               else
+                       d->index_status = DIFF_STATUS_ADDED;
+       }
+}
+
+static void wt_status_collect_untracked(struct wt_status *s)
+{
+       int i;
+       struct dir_struct dir;
+
+       if (!s->show_untracked_files)
+               return;
+       memset(&dir, 0, sizeof(dir));
+       if (s->show_untracked_files != SHOW_ALL_UNTRACKED_FILES)
+               dir.flags |=
+                       DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
+       setup_standard_excludes(&dir);
+
+       fill_directory(&dir, NULL);
+       for(i = 0; i < dir.nr; i++) {
+               struct dir_entry *ent = dir.entries[i];
+               if (!cache_name_is_other(ent->name, ent->len))
+                       continue;
+               s->workdir_untracked = 1;
+               string_list_insert(ent->name, &s->untracked);
+       }
+}
+
+void wt_status_collect(struct wt_status *s)
+{
+       wt_status_collect_changes_worktree(s);
+
+       if (s->is_initial)
+               wt_status_collect_changes_initial(s);
+       else
+               wt_status_collect_changes_index(s);
+       wt_status_collect_untracked(s);
+}
+
+static void wt_status_print_unmerged(struct wt_status *s)
+{
+       int shown_header = 0;
+       int i;
+
+       for (i = 0; i < s->change.nr; i++) {
+               struct wt_status_change_data *d;
+               struct string_list_item *it;
+               it = &(s->change.items[i]);
+               d = it->util;
+               if (!d->stagemask)
+                       continue;
+               if (!shown_header) {
+                       wt_status_print_unmerged_header(s);
+                       shown_header = 1;
+               }
+               wt_status_print_unmerged_data(s, it);
+       }
+       if (shown_header)
+               wt_status_print_trailer(s);
+
+}
+
+static void wt_status_print_updated(struct wt_status *s)
+{
+       int shown_header = 0;
+       int i;
+
+       for (i = 0; i < s->change.nr; i++) {
+               struct wt_status_change_data *d;
+               struct string_list_item *it;
+               it = &(s->change.items[i]);
+               d = it->util;
+               if (!d->index_status ||
+                   d->index_status == DIFF_STATUS_UNMERGED)
+                       continue;
+               if (!shown_header) {
+                       wt_status_print_cached_header(s);
+                       s->commitable = 1;
+                       shown_header = 1;
+               }
+               wt_status_print_change_data(s, WT_STATUS_UPDATED, it);
+       }
+       if (shown_header)
+               wt_status_print_trailer(s);
+}
+
+/*
+ * -1 : has delete
+ *  0 : no change
+ *  1 : some change but no delete
+ */
+static int wt_status_check_worktree_changes(struct wt_status *s)
+{
+       int i;
+       int changes = 0;
+
+       for (i = 0; i < s->change.nr; i++) {
+               struct wt_status_change_data *d;
+               d = s->change.items[i].util;
+               if (!d->worktree_status ||
+                   d->worktree_status == DIFF_STATUS_UNMERGED)
+                       continue;
+               changes = 1;
+               if (d->worktree_status == DIFF_STATUS_DELETED)
+                       return -1;
+       }
+       return changes;
+}
+
 static void wt_status_print_changed(struct wt_status *s)
 {
-       struct rev_info rev;
-       init_revisions(&rev, "");
-       setup_revisions(0, NULL, &rev, NULL);
-       rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
-       rev.diffopt.format_callback = wt_status_print_changed_cb;
-       rev.diffopt.format_callback_data = s;
-       run_diff_files(&rev, 0);
+       int i;
+       int worktree_changes = wt_status_check_worktree_changes(s);
+
+       if (!worktree_changes)
+               return;
+
+       wt_status_print_dirty_header(s, worktree_changes < 0);
+
+       for (i = 0; i < s->change.nr; i++) {
+               struct wt_status_change_data *d;
+               struct string_list_item *it;
+               it = &(s->change.items[i]);
+               d = it->util;
+               if (!d->worktree_status ||
+                   d->worktree_status == DIFF_STATUS_UNMERGED)
+                       continue;
+               wt_status_print_change_data(s, WT_STATUS_CHANGED, it);
+       }
+       wt_status_print_trailer(s);
 }
 
 static void wt_status_print_submodule_summary(struct wt_status *s)
@@ -228,7 +456,7 @@ static void wt_status_print_submodule_summary(struct wt_status *s)
                NULL
        };
 
-       sprintf(summary_limit, "%d", wt_status_submodule_summary);
+       sprintf(summary_limit, "%d", s->submodule_summary);
        snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", s->index_file);
 
        memset(&sm_summary, 0, sizeof(sm_summary));
@@ -243,32 +471,20 @@ static void wt_status_print_submodule_summary(struct wt_status *s)
 
 static void wt_status_print_untracked(struct wt_status *s)
 {
-       struct dir_struct dir;
        int i;
-       int shown_header = 0;
        struct strbuf buf = STRBUF_INIT;
 
-       memset(&dir, 0, sizeof(dir));
-
-       if (!s->untracked)
-               dir.flags |=
-                       DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
-       setup_standard_excludes(&dir);
+       if (!s->untracked.nr)
+               return;
 
-       fill_directory(&dir, NULL);
-       for(i = 0; i < dir.nr; i++) {
-               struct dir_entry *ent = dir.entries[i];
-               if (!cache_name_is_other(ent->name, ent->len))
-                       continue;
-               if (!shown_header) {
-                       s->workdir_untracked = 1;
-                       wt_status_print_untracked_header(s);
-                       shown_header = 1;
-               }
-               color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t");
-               color_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED), "%s",
-                               quote_path(ent->name, ent->len,
-                                       &buf, s->prefix));
+       wt_status_print_untracked_header(s);
+       for (i = 0; i < s->untracked.nr; i++) {
+               struct string_list_item *it;
+               it = &(s->untracked.items[i]);
+               color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t");
+               color_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED, s), "%s",
+                                quote_path(it->string, strlen(it->string),
+                                           &buf, s->prefix));
        }
        strbuf_release(&buf);
 }
@@ -310,15 +526,15 @@ static void wt_status_print_tracking(struct wt_status *s)
                return;
 
        for (cp = sb.buf; (ep = strchr(cp, '\n')) != NULL; cp = ep + 1)
-               color_fprintf_ln(s->fp, color(WT_STATUS_HEADER),
+               color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s),
                                 "# %.*s", (int)(ep - cp), cp);
-       color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
+       color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
 }
 
 void wt_status_print(struct wt_status *s)
 {
        unsigned char sha1[20];
-       const char *branch_color = color(WT_STATUS_HEADER);
+       const char *branch_color = color(WT_STATUS_HEADER, s);
 
        s->is_initial = get_sha1(s->reference, sha1) ? 1 : 0;
        if (s->branch) {
@@ -328,26 +544,29 @@ void wt_status_print(struct wt_status *s)
                        branch_name += 11;
                else if (!strcmp(branch_name, "HEAD")) {
                        branch_name = "";
-                       branch_color = color(WT_STATUS_NOBRANCH);
+                       branch_color = color(WT_STATUS_NOBRANCH, s);
                        on_what = "Not currently on any branch.";
                }
-               color_fprintf(s->fp, color(WT_STATUS_HEADER), "# ");
+               color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "# ");
                color_fprintf_ln(s->fp, branch_color, "%s%s", on_what, branch_name);
                if (!s->is_initial)
                        wt_status_print_tracking(s);
        }
 
+       wt_status_collect(s);
+
        if (s->is_initial) {
-               color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
-               color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "# Initial commit");
-               color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
+               color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
+               color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "# Initial commit");
+               color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
        }
 
+       wt_status_print_unmerged(s);
        wt_status_print_updated(s);
        wt_status_print_changed(s);
-       if (wt_status_submodule_summary)
+       if (s->submodule_summary)
                wt_status_print_submodule_summary(s);
-       if (show_untracked_files)
+       if (s->show_untracked_files)
                wt_status_print_untracked(s);
        else if (s->commitable)
                 fprintf(s->fp, "# Untracked files not listed (use -u option to show untracked files)\n");
@@ -361,53 +580,13 @@ void wt_status_print(struct wt_status *s)
                        ; /* nothing */
                else if (s->workdir_dirty)
                        printf("no changes added to commit (use \"git add\" and/or \"git commit -a\")\n");
-               else if (s->workdir_untracked)
+               else if (s->untracked.nr)
                        printf("nothing added to commit but untracked files present (use \"git add\" to track)\n");
                else if (s->is_initial)
                        printf("nothing to commit (create/copy files and use \"git add\" to track)\n");
-               else if (!show_untracked_files)
+               else if (!s->show_untracked_files)
                        printf("nothing to commit (use -u to show untracked files)\n");
                else
                        printf("nothing to commit (working directory clean)\n");
        }
 }
-
-int git_status_config(const char *k, const char *v, void *cb)
-{
-       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;
-       }
-       if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) {
-               int slot = parse_status_slot(k, 13);
-               if (!v)
-                       return config_error_nonbool(k);
-               color_parse(v, k, wt_status_colors[slot]);
-               return 0;
-       }
-       if (!strcmp(k, "status.relativepaths")) {
-               wt_status_relative_paths = git_config_bool(k, v);
-               return 0;
-       }
-       if (!strcmp(k, "status.showuntrackedfiles")) {
-               if (!v)
-                       return config_error_nonbool(k);
-               else if (!strcmp(v, "no"))
-                       show_untracked_files = SHOW_NO_UNTRACKED_FILES;
-               else if (!strcmp(v, "normal"))
-                       show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
-               else if (!strcmp(v, "all"))
-                       show_untracked_files = SHOW_ALL_UNTRACKED_FILES;
-               else
-                       return error("Invalid untracked files mode '%s'", v);
-               return 0;
-       }
-       return git_diff_ui_config(k, v, cb);
-}
index 78add09bd67c727babb61cd1eaa773bcd0c6e55e..a0e75177bec925e95b4257811aae0bdee93c41f1 100644 (file)
@@ -2,13 +2,16 @@
 #define STATUS_H
 
 #include <stdio.h>
+#include "string-list.h"
+#include "color.h"
 
 enum color_wt_status {
-       WT_STATUS_HEADER,
+       WT_STATUS_HEADER = 0,
        WT_STATUS_UPDATED,
        WT_STATUS_CHANGED,
        WT_STATUS_UNTRACKED,
        WT_STATUS_NOBRANCH,
+       WT_STATUS_UNMERGED,
 };
 
 enum untracked_status_type {
@@ -16,7 +19,13 @@ enum untracked_status_type {
        SHOW_NORMAL_UNTRACKED_FILES,
        SHOW_ALL_UNTRACKED_FILES
 };
-extern enum untracked_status_type show_untracked_files;
+
+struct wt_status_change_data {
+       int worktree_status;
+       int index_status;
+       int stagemask;
+       char *head_path;
+};
 
 struct wt_status {
        int is_initial;
@@ -24,8 +33,13 @@ struct wt_status {
        const char *reference;
        int verbose;
        int amend;
-       int untracked;
        int nowarn;
+       int use_color;
+       int relative_paths;
+       int submodule_summary;
+       enum untracked_status_type show_untracked_files;
+       char color_palette[WT_STATUS_UNMERGED+1][COLOR_MAXLEN];
+
        /* These are computed during processing of the individual sections */
        int commitable;
        int workdir_dirty;
@@ -33,12 +47,12 @@ struct wt_status {
        const char *index_file;
        FILE *fp;
        const char *prefix;
+       struct string_list change;
+       struct string_list untracked;
 };
 
-int git_status_config(const char *var, const char *value, void *cb);
-extern int wt_status_use_color;
-extern int wt_status_relative_paths;
 void wt_status_prepare(struct wt_status *s);
 void wt_status_print(struct wt_status *s);
+void wt_status_collect(struct wt_status *s);
 
 #endif /* STATUS_H */
index 04ad468702209b77427e635370d41001986042ce..bc12f298953a4e72b323f73607278028ec4a2805 100644 (file)
@@ -190,48 +190,66 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
 {
        int i1, i2;
 
+       if (!(flags & XDF_WHITESPACE_FLAGS))
+               return s1 == s2 && !memcmp(l1, l2, s1);
+
+       i1 = 0;
+       i2 = 0;
+
+       /*
+        * -w matches everything that matches with -b, and -b in turn
+        * matches everything that matches with --ignore-space-at-eol.
+        *
+        * Each flavor of ignoring needs different logic to skip whitespaces
+        * while we have both sides to compare.
+        */
        if (flags & XDF_IGNORE_WHITESPACE) {
-               for (i1 = i2 = 0; i1 < s1 && i2 < s2; ) {
-                       if (isspace(l1[i1]))
-                               while (isspace(l1[i1]) && i1 < s1)
-                                       i1++;
-                       if (isspace(l2[i2]))
-                               while (isspace(l2[i2]) && i2 < s2)
-                                       i2++;
-                       if (i1 < s1 && i2 < s2 && l1[i1++] != l2[i2++])
+               goto skip_ws;
+               while (i1 < s1 && i2 < s2) {
+                       if (l1[i1++] != l2[i2++])
                                return 0;
+               skip_ws:
+                       while (i1 < s1 && isspace(l1[i1]))
+                               i1++;
+                       while (i2 < s2 && isspace(l2[i2]))
+                               i2++;
                }
-               return (i1 >= s1 && i2 >= s2);
        } else if (flags & XDF_IGNORE_WHITESPACE_CHANGE) {
-               for (i1 = i2 = 0; i1 < s1 && i2 < s2; ) {
-                       if (isspace(l1[i1])) {
-                               if (!isspace(l2[i2]))
-                                       return 0;
-                               while (isspace(l1[i1]) && i1 < s1)
-                                       i1++;
-                               while (isspace(l2[i2]) && i2 < s2)
-                                       i2++;
-                       } else if (l1[i1++] != l2[i2++])
-                               return 0;
-               }
-               return (i1 >= s1 && i2 >= s2);
-       } else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL) {
-               for (i1 = i2 = 0; i1 < s1 && i2 < s2; ) {
-                       if (l1[i1] != l2[i2]) {
+               while (i1 < s1 && i2 < s2) {
+                       if (isspace(l1[i1]) && isspace(l2[i2])) {
+                               /* Skip matching spaces and try again */
                                while (i1 < s1 && isspace(l1[i1]))
                                        i1++;
                                while (i2 < s2 && isspace(l2[i2]))
                                        i2++;
-                               if (i1 < s1 || i2 < s2)
-                                       return 0;
-                               return 1;
+                               continue;
                        }
+                       if (l1[i1++] != l2[i2++])
+                               return 0;
+               }
+       } else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL) {
+               while (i1 < s1 && i2 < s2 && l1[i1++] == l2[i2++])
+                       ; /* keep going */
+       }
+
+       /*
+        * After running out of one side, the remaining side must have
+        * nothing but whitespace for the lines to match.  Note that
+        * ignore-whitespace-at-eol case may break out of the loop
+        * while there still are characters remaining on both lines.
+        */
+       if (i1 < s1) {
+               while (i1 < s1 && isspace(l1[i1]))
                        i1++;
+               if (s1 != i1)
+                       return 0;
+       }
+       if (i2 < s2) {
+               while (i2 < s2 && isspace(l2[i2]))
                        i2++;
-               }
-               return i1 >= s1 && i2 >= s2;
-       } else
-               return s1 == s2 && !memcmp(l1, l2, s1);
+               return (s2 == i2);
+       }
+       return 1;
 }
 
 static unsigned long xdl_hash_record_with_whitespace(char const **data,
@@ -242,18 +260,20 @@ static unsigned long xdl_hash_record_with_whitespace(char const **data,
        for (; ptr < top && *ptr != '\n'; ptr++) {
                if (isspace(*ptr)) {
                        const char *ptr2 = ptr;
+                       int at_eol;
                        while (ptr + 1 < top && isspace(ptr[1])
                                        && ptr[1] != '\n')
                                ptr++;
+                       at_eol = (top <= ptr + 1 || ptr[1] == '\n');
                        if (flags & XDF_IGNORE_WHITESPACE)
                                ; /* already handled */
                        else if (flags & XDF_IGNORE_WHITESPACE_CHANGE
-                                       && ptr[1] != '\n') {
+                                && !at_eol) {
                                ha += (ha << 5);
                                ha ^= (unsigned long) ' ';
                        }
                        else if (flags & XDF_IGNORE_WHITESPACE_AT_EOL
-                                       && ptr[1] != '\n') {
+                                && !at_eol) {
                                while (ptr2 != ptr + 1) {
                                        ha += (ha << 5);
                                        ha ^= (unsigned long) *ptr2;