Merge branch 'lt/rev-list-gitlink'
authorJunio C Hamano <gitster@pobox.com>
Mon, 19 Nov 2007 00:16:37 +0000 (16:16 -0800)
committerJunio C Hamano <gitster@pobox.com>
Mon, 19 Nov 2007 00:16:37 +0000 (16:16 -0800)
* lt/rev-list-gitlink:
Fix rev-list when showing objects involving submodules

116 files changed:
Documentation/RelNotes-1.5.3.6.txt
Documentation/RelNotes-1.5.4.txt
Documentation/config.txt
Documentation/diff-options.txt
Documentation/git-clone.txt
Documentation/git-cvsexportcommit.txt
Documentation/git-diff.txt
Documentation/git-format-patch.txt
Documentation/git-ls-files.txt
Documentation/git-rev-list.txt
Documentation/git-rev-parse.txt
Documentation/git.txt
Documentation/urls.txt
Documentation/user-manual.txt
Makefile
builtin-add.c
builtin-apply.c
builtin-blame.c
builtin-branch.c
builtin-diff-files.c
builtin-diff-index.c
builtin-diff-tree.c
builtin-diff.c
builtin-fetch--tool.c
builtin-fetch.c
builtin-fmt-merge-msg.c
builtin-for-each-ref.c
builtin-grep.c
builtin-log.c
builtin-ls-files.c
builtin-pack-refs.c
builtin-rev-list.c
builtin-rev-parse.c
builtin-tag.c
cache.h
check-racy.c
combine-diff.c
commit.c
commit.h
config.c
contrib/fast-import/git-p4
csum-file.c
csum-file.h
diff-lib.c
diff.c
diff.h
dir.c
dir.h
entry.c
environment.c
git-add--interactive.perl
git-am.sh
git-bisect.sh
git-checkout.sh
git-clean.sh
git-clone.sh
git-commit.sh
git-compat-util.h
git-cvsexportcommit.perl
git-cvsimport.perl
git-filter-branch.sh
git-instaweb.sh
git-lost-found.sh
git-merge.sh
git-mergetool.sh
git-pull.sh
git-quiltimport.sh
git-rebase--interactive.sh
git-rebase.sh
git-repack.sh
git-request-pull.sh
git-send-email.perl
git-sh-setup.sh
git-stash.sh
git-submodule.sh
git-svn.perl
git.c
index-pack.c
log-tree.c
merge-recursive.c
parse-options.c
parse-options.h
patch-ids.c
pretty.c
progress.c
progress.h
read-cache.c
refs.c
refs.h
revision.c
revision.h
run-command.c
run-command.h
sideband.c
strbuf.c
strbuf.h
t/t2008-checkout-subdir.sh [new file with mode: 0755]
t/t2200-add-update.sh
t/t3402-rebase-merge.sh
t/t3403-rebase-skip.sh
t/t3700-add.sh
t/t4021-format-patch-numbered.sh [new file with mode: 0755]
t/t5502-quickfetch.sh
t/t7004-tag.sh
t/t7005-editor.sh
t/t7500-commit.sh
t/t7501-commit.sh
t/t9101-git-svn-props.sh
t/t9116-git-svn-log.sh
t/t9117-git-svn-init-clone.sh [new file with mode: 0755]
tree-diff.c
unpack-trees.c
utf8.c
wt-status.c
xdiff/xdiffi.c
xdiff/xutils.c
index 06e44f7735fde8aed8d0268c1034f47799dd8287..069a2b2cf9e9f28a2f9e6dc0817723a38b25f475 100644 (file)
@@ -4,18 +4,45 @@ GIT v1.5.3.6 Release Notes
 Fixes since v1.5.3.5
 --------------------
 
- * git-cvsexportcommit handles root commits better;
+ * git-cvsexportcommit handles root commits better.
 
  * git-svn dcommit used to clobber when sending a series of
-   patches;
+   patches.
+
+ * git-svn dcommit failed after attempting to rebase when
+   started with a dirty index; now it stops upfront.
 
  * git-grep sometimes refused to work when your index was
-   unmerged;
+   unmerged.
 
- * Quite a lot of documentation clarifications.
+ * "git-grep -A1 -B2" acted as if it was told to run "git -A1 -B21".
+
+ * git-hash-object did not honor configuration variables, such as
+   core.compression.
+
+ * git-index-pack choked on a huge pack on 32-bit machines, even when
+   large file offsets are supported.
+
+ * atom feeds from git-web said "10" for the month of November.
+
+ * a memory leak in commit walker was plugged.
+
+ * When git-send-email inserted the original author's From:
+   address in body, it did not mark the message with
+   Content-type: as needed.
 
---
-exec >/var/tmp/1
-O=v1.5.3.5-32-gcb6c162
-echo O=`git describe refs/heads/maint`
-git shortlog --no-merges $O..refs/heads/maint
+ * git-revert and git-cherry-pick incorrectly refused to start
+   when the work tree was dirty.
+
+ * git-clean did not honor core.excludesfile configuration.
+
+ * git-add mishandled ".gitignore" files when applying them to
+   subdirectories.
+
+ * While importing a too branchy history, git-fastimport did not
+   honor delta depth limit properly.
+
+ * Support for zlib implementations that lack ZLIB_VERNUM and definition
+   of deflateBound() has been added.
+
+ * Quite a lot of documentation clarifications.
index 93fb9c914c38388b3b1db11d2b6e63183a9bb952..7f7d4273e23a78f6ee937d00fd036f191f79d188 100644 (file)
@@ -32,6 +32,10 @@ Updates since v1.5.3
    (read: safer than the usual one) after the user accumulates
    too many loose objects.
 
+ * You need to explicitly set clean.requireForce to "false" to allow
+   git-clean to do any damage (lack of the configuration variable
+   used to mean "do not require", but we now use the safer default).
+
  * git-push has been rewritten in C.
 
  * git-push learned --dry-run option to show what would happen
@@ -56,7 +60,28 @@ Updates since v1.5.3
 
  * git-bisect learned "skip" action to mark untestable commits.
 
- * rename detection diff family, while detecting exact matches,
+ * git-format-patch learned "format.numbered" configuration variable
+   to automatically turn --numbered option on when more than one
+   commits are formatted.
+
+ * git-ls-files learned "--exclude-standard" to use the canned
+   set of exclude files.
+
+ * git-rebase now detaches head during its operation, so after a
+   successful "git rebase" operation, the reflog entry branch@{1}
+   for the current branch points at the commit before the rebase
+   was started.
+
+ * "git-tag -a -f existing" begins the editor session using the
+   existing annotation message.
+
+ * "git cvsexportcommit" learned -w option to specify and switch
+   to the CVS working directory.
+
+ * Output processing for '--pretty=format:<user format>' has
+   been optimized.
+
+ * Rename detection diff family, while detecting exact matches,
    has been greatly optimized.
 
  * Example update and post-receive hooks have been improved.
@@ -77,8 +102,11 @@ Fixes since v1.5.3
 All of the fixes in v1.5.3 maintenance series are included in
 this release, unless otherwise noted.
 
+ * git-svn talking with the SVN over http will correctly quote branch
+   and project names.
+
 --
 exec >/var/tmp/1
-O=v1.5.3.5-618-g5d4138a
+O=v1.5.3.6-706-gcb02958
 echo O=`git describe refs/heads/master`
 git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
index 8d5d2005806289b7da9290fd0c40f12016d5ef53..6dc9f3ed02b2dd4a3fe439c28df7b2ba6778244d 100644 (file)
@@ -432,6 +432,12 @@ fetch.unpackLimit::
        pack from a push can make the push operation complete faster,
        especially on slow filesystems.
 
+format.numbered::
+       A boolean which can enable sequence numbers in patch subjects.
+       Seting this option to "auto" will enable it only if there is
+       more than one patch.  See --numbered option in
+       gitlink:git-format-patch[1].
+
 format.headers::
        Additional email headers to include in a patch to be submitted
        by mail.  See gitlink:git-format-patch[1].
index b1f528ae8864e429a509365a79d16bb8341620e1..e4af393515c346528bccb7a4f2d3823aebddddfc 100644 (file)
@@ -1,5 +1,25 @@
+// Please don't remove this comment as asciidoc behaves badly when
+// the first non-empty line is ifdef/ifndef. The symptom is that
+// without this comment the <git-diff-core> attribute conditionally
+// defined below ends up being defined unconditionally.
+// Last checked with asciidoc 7.0.2.
+
+ifndef::git-format-patch[]
+ifndef::git-diff[]
+:git-diff-core: 1
+endif::git-diff[]
+endif::git-format-patch[]
+
+ifdef::git-format-patch[]
 -p::
-       Generate patch (see section on generating patches)
+       Generate patches without diffstat.
+endif::git-format-patch[]
+
+ifndef::git-format-patch[]
+-p::
+       Generate patch (see section on generating patches).
+       {git-diff? This is the default.}
+endif::git-format-patch[]
 
 -u::
        Synonym for "-p".
@@ -13,6 +33,7 @@
 
 --raw::
        Generate the raw format.
+       {git-diff-core? This is the default.}
 
 --patch-with-raw::
        Synonym for "-p --raw".
@@ -41,6 +62,7 @@
 
 --patch-with-stat::
        Synonym for "-p --stat".
+       {git-format-patch? This is the default.}
 
 -z::
        NUL-line termination on output.  This affects the --raw
index 14e58f3866e3a4e7d1da01753cb68082e88ae2f6..c90bcece24c0fcbf9513af7808f6d0d13846c528 100644 (file)
@@ -130,6 +130,7 @@ OPTIONS
        for "host.xz:foo/.git").  Cloning into an existing directory
        is not allowed.
 
+:git-clone: 1
 include::urls.txt[]
 
 Examples
index c3922f9238cf9f33d404665714fb0458122b6e43..3f9d2295d38b4728929764b0adcbdf5785167f75 100644 (file)
@@ -8,7 +8,7 @@ git-cvsexportcommit - Export a single commit to a CVS checkout
 
 SYNOPSIS
 --------
-'git-cvsexportcommit' [-h] [-u] [-v] [-c] [-P] [-p] [-a] [-d cvsroot] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID
+'git-cvsexportcommit' [-h] [-u] [-v] [-c] [-P] [-p] [-a] [-d cvsroot] [-w cvsworkdir] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID
 
 
 DESCRIPTION
@@ -16,8 +16,9 @@ DESCRIPTION
 Exports a commit from GIT to a CVS checkout, making it easier
 to merge patches from a git repository into a CVS repository.
 
-Execute it from the root of the CVS working copy. GIT_DIR must be defined.
-See examples below.
+Specify the name of a CVS checkout using the -w switch or execute it
+from the root of the CVS working copy. In the latter case GIT_DIR must
+be defined. See examples below.
 
 It does its best to do the safe thing, it will check that the files are
 unchanged and up to date in the CVS checkout, and it will not autocommit
@@ -61,6 +62,11 @@ OPTIONS
 -u::
        Update affected files from CVS repository before attempting export.
 
+-w::
+       Specify the location of the CVS checkout to use for the export. This
+       option does not require GIT_DIR to be set before execution if the
+       current directory is within a git repository.
+
 -v::
        Verbose.
 
@@ -76,6 +82,12 @@ $ git-cvsexportcommit -v <commit-sha1>
 $ cvs commit -F .msg <files>
 ------------
 
+Merge one patch into CVS (-c and -w options). The working directory is within the Git Repo::
++
+------------
+       $ git-cvsexportcommit -v -c -w ~/project_cvs_checkout <commit-sha1>
+------------
+
 Merge pending patches into CVS automatically -- only if you really know what you are doing::
 +
 ------------
@@ -86,11 +98,11 @@ $ git-cherry cvshead myhead | sed -n 's/^+ //p' | xargs -l1 git-cvsexportcommit
 
 Author
 ------
-Written by Martin Langhoff <martin@catalyst.net.nz>
+Written by Martin Langhoff <martin@catalyst.net.nz> and others.
 
 Documentation
 --------------
-Documentation by Martin Langhoff <martin@catalyst.net.nz>
+Documentation by Martin Langhoff <martin@catalyst.net.nz> and others.
 
 GIT
 ---
index 11c4216c4a5c705c6af55b1367cae96b13c20251..2808a5ec44d8a9e911faf4c7d24eb844d69390f2 100644 (file)
@@ -75,6 +75,7 @@ and the range notations ("<commit>..<commit>" and
 
 OPTIONS
 -------
+:git-diff: 1
 include::diff-options.txt[]
 
 <path>...::
index f0617efa0ab5d6c046e2b880a710ab852f1afd6a..6fb94298516620e6991e82272a7e657a8296f7ca 100644 (file)
@@ -9,9 +9,10 @@ git-format-patch - Prepare patches for e-mail submission
 SYNOPSIS
 --------
 [verse]
-'git-format-patch' [-n | -k] [-o <dir> | --stdout] [--thread]
+'git-format-patch' [-k] [-o <dir> | --stdout] [--thread]
                    [--attach[=<boundary>] | --inline[=<boundary>]]
                    [-s | --signoff] [<common diff options>]
+                   [-n | --numbered | -N | --no-numbered]
                    [--start-number <n>] [--numbered-files]
                    [--in-reply-to=Message-Id] [--suffix=.<sfx>]
                    [--ignore-if-in-upstream]
@@ -65,6 +66,7 @@ reference.
 
 OPTIONS
 -------
+:git-format-patch: 1
 include::diff-options.txt[]
 
 -<n>::
@@ -77,6 +79,9 @@ include::diff-options.txt[]
 -n|--numbered::
        Name output in '[PATCH n/m]' format.
 
+-N|--no-numbered::
+       Name output in '[PATCH]' format.
+
 --start-number <n>::
        Start numbering the patches at <n> instead of 1.
 
@@ -142,15 +147,16 @@ not add any suffix.
 
 CONFIGURATION
 -------------
-You can specify extra mail header lines to be added to each
-message in the repository configuration.  You can also specify
-new defaults for the subject prefix and file suffix.
+You can specify extra mail header lines to be added to each message
+in the repository configuration, new defaults for the subject prefix
+and file suffix, and number patches when outputting more than one.
 
 ------------
 [format]
         headers = "Organization: git-foo\n"
         subjectprefix = CHANGE
         suffix = .txt
+        numbered = auto
 ------------
 
 
index 9e454f0a4da465606afbed1720b7bd10cca8b241..2ec0c0d270edde03adff3f56531e4cee5fe05a57 100644 (file)
@@ -15,6 +15,7 @@ SYNOPSIS
                [-x <pattern>|--exclude=<pattern>]
                [-X <file>|--exclude-from=<file>]
                [--exclude-per-directory=<file>]
+               [--exclude-standard]
                [--error-unmatch] [--with-tree=<tree-ish>]
                [--full-name] [--abbrev] [--] [<file>]\*
 
@@ -77,6 +78,10 @@ OPTIONS
        read additional exclude patterns that apply only to the
        directory and its subdirectories in <file>.
 
+--exclude-standard::
+       Add the standard git exclusions: .git/info/exclude, .gitignore
+       in each directory, and the user's global exclusion file.
+
 --error-unmatch::
        If any <file> does not appear in the index, treat this as an
        error (return 1).
index 485280423e90bac43b4c372bbc8d350c34cf4fa8..989fbf3562977866d7d2558022587847f538ae4b 100644 (file)
@@ -20,6 +20,7 @@ SYNOPSIS
             [ \--not ]
             [ \--all ]
             [ \--stdin ]
+            [ \--quiet ]
             [ \--topo-order ]
             [ \--parents ]
             [ \--timestamp ]
@@ -270,6 +271,14 @@ limiting may be applied.
        In addition to the '<commit>' listed on the command
        line, read them from the standard input.
 
+--quiet::
+
+       Don't print anything to standard output.  This form of
+       git-rev-list is primarly meant to allow the caller to
+       test the exit status to see if a range of objects is fully
+       connected (or not).  It is faster than redirecting stdout
+       to /dev/null as the output does not have to be formatted.
+
 --cherry-pick::
 
        Omit any commit that introduces the same change as
index 4758c33dee53b21c0e8a489f0da11a30c63cbf48..329fce0aab417e5fe02845bd21b693f5200b3634 100644 (file)
@@ -23,6 +23,13 @@ distinguish between them.
 
 OPTIONS
 -------
+--parseopt::
+       Use `git-rev-parse` in option parsing mode (see PARSEOPT section below).
+
+--keep-dash-dash::
+       Only meaningful in `--parseopt` mode. Tells the option parser to echo
+       out the first `--` met instead of skipping it.
+
 --revs-only::
        Do not output flags and parameters not meant for
        `git-rev-list` command.
@@ -288,10 +295,75 @@ Here are a handful examples:
    C^@              I J F
    F^! D            G H D F
 
+PARSEOPT
+--------
+
+In `--parseopt` mode, `git-rev-parse` helps massaging options to bring to shell
+scripts the same facilities C builtins have. It works as an option normalizer
+(e.g. splits single switches aggregate values), a bit like `getopt(1)` does.
+
+It takes on the standard input the specification of the options to parse and
+understand, and echoes on the standard output a line suitable for `sh(1)` `eval`
+to replace the arguments with normalized ones.  In case of error, it outputs
+usage on the standard error stream, and exits with code 129.
+
+Input Format
+~~~~~~~~~~~~
+
+`git-rev-parse --parseopt` input format is fully text based. It has two parts,
+separated by a line that contains only `--`. The lines before the separator
+(should be more than one) are used for the usage.
+The lines after the separator describe the options.
+
+Each line of options has this format:
+
+------------
+<opt_spec><arg_spec>? SP+ help LF
+------------
+
+`<opt_spec>`::
+       its format is the short option character, then the long option name
+       separated by a comma. Both parts are not required, though at least one
+       is necessary. `h,help`, `dry-run` and `f` are all three correct
+       `<opt_spec>`.
+
+`<arg_spec>`::
+       an `<arg_spec>` tells the option parser if the option has an argument
+       (`=`), an optional one (`?` though its use is discouraged) or none
+       (no `<arg_spec>` in that case).
+
+The remainder of the line, after stripping the spaces, is used
+as the help associated to the option.
+
+Blank lines are ignored, and lines that don't match this specification are used
+as option group headers (start the line with a space to create such
+lines on purpose).
+
+Example
+~~~~~~~
+
+------------
+OPTS_SPEC="\
+some-command [options] <args>...
+
+some-command does foo and bar!
+--
+h,help    show the help
+
+foo       some nifty option --foo
+bar=      some cool option --bar with an argument
+
+  An option group Header
+C?        option C with an optional argument"
+
+eval `echo "$OPTS_SPEC" | git-rev-parse --parseopt -- "$@" || echo exit $?`
+------------
+
+
 Author
 ------
-Written by Linus Torvalds <torvalds@osdl.org> and
-Junio C Hamano <junkio@cox.net>
+Written by Linus Torvalds <torvalds@osdl.org> .
+Junio C Hamano <junkio@cox.net> and Pierre Habouzit <madcoder@debian.org>
 
 Documentation
 --------------
index 6db7ae1ea7073ecef07430f13d6bf88758c922ff..546020100a533b99126adb1635299e7d025bca4b 100644 (file)
@@ -46,6 +46,7 @@ Documentation for older releases are available here:
 * link:v1.5.3/git.html[documentation for release 1.5.3]
 
 * release notes for
+  link:RelNotes-1.5.3.6.txt[1.5.3.6],
   link:RelNotes-1.5.3.5.txt[1.5.3.5],
   link:RelNotes-1.5.3.4.txt[1.5.3.4],
   link:RelNotes-1.5.3.3.txt[1.5.3.3],
index e67f9140ab6be15499b60a8a87ec524a5357a284..4f667382ec1b3a93871c8b2beb31111278ec27b8 100644 (file)
@@ -36,5 +36,11 @@ To sync with a local directory, you can use:
 - file:///path/to/repo.git/
 ===============================================================
 
+ifndef::git-clone[]
 They are mostly equivalent, except when cloning.  See
 gitlink:git-clone[1] for details.
+endif::git-clone[]
+
+ifdef::git-clone[]
+They are equivalent, except the former implies --local option.
+endif::git-clone[]
index 60e13853dc6a32ecf9a8aa0cad484531c69b2027..518b7b5c9e283eccd20ce2d84ea85f107c98ca39 100644 (file)
@@ -1367,7 +1367,7 @@ If you make a commit that you later wish you hadn't, there are two
 fundamentally different ways to fix the problem:
 
        1. You can create a new commit that undoes whatever was done
-       by the previous commit.  This is the correct thing if your
+       by the old commit.  This is the correct thing if your
        mistake has already been made public.
 
        2. You can go back and modify the old commit.  You should
@@ -1567,9 +1567,9 @@ old history using, for example,
 $ git log master@{1}
 -------------------------------------------------
 
-This lists the commits reachable from the previous version of the branch.
-This syntax can be used with any git command that accepts a commit,
-not just with git log.  Some other examples:
+This lists the commits reachable from the previous version of the
+"master" branch head.  This syntax can be used with any git command
+that accepts a commit, not just with git log.  Some other examples:
 
 -------------------------------------------------
 $ git show master@{2}          # See where the branch pointed 2,
index e830bc7445c5753b29b6bb329ec8d977557df97b..cabde8177e1dd2ad03c558339f932b6959a9bce2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -416,18 +416,17 @@ ifeq ($(uname_S),SunOS)
        NO_STRCASESTR = YesPlease
        NO_MEMMEM = YesPlease
        NO_HSTRERROR = YesPlease
+       NO_MKDTEMP = YesPlease
        ifeq ($(uname_R),5.8)
                NEEDS_LIBICONV = YesPlease
                NO_UNSETENV = YesPlease
                NO_SETENV = YesPlease
-               NO_MKDTEMP = YesPlease
                NO_C99_FORMAT = YesPlease
                NO_STRTOUMAX = YesPlease
        endif
        ifeq ($(uname_R),5.9)
                NO_UNSETENV = YesPlease
                NO_SETENV = YesPlease
-               NO_MKDTEMP = YesPlease
                NO_C99_FORMAT = YesPlease
                NO_STRTOUMAX = YesPlease
        endif
index 45b14e8a61764e18d8b89ebfef550a820ffbf831..cf815a0b8ef0e588cfaf25f71747ba7248d19d70 100644 (file)
@@ -21,7 +21,6 @@ static const char * const builtin_add_usage[] = {
 };
 
 static int take_worktree_changes;
-static const char *excludes_file;
 
 static void prune_directory(struct dir_struct *dir, const char **pathspec, int prefix)
 {
@@ -61,12 +60,7 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec,
        memset(dir, 0, sizeof(*dir));
        if (!ignored_too) {
                dir->collect_ignored = 1;
-               dir->exclude_per_dir = ".gitignore";
-               path = git_path("info/exclude");
-               if (!access(path, R_OK))
-                       add_excludes_from_file(dir, path);
-               if (excludes_file != NULL && !access(excludes_file, R_OK))
-                       add_excludes_from_file(dir, excludes_file);
+               setup_standard_excludes(dir);
        }
 
        /*
@@ -120,7 +114,7 @@ void add_files_to_cache(int verbose, const char *prefix, const char **files)
        rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
        rev.diffopt.format_callback = update_callback;
        rev.diffopt.format_callback_data = &verbose;
-       run_diff_files(&rev, 0);
+       run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
 }
 
 static void refresh(int verbose, const char **pathspec)
@@ -141,18 +135,6 @@ static void refresh(int verbose, const char **pathspec)
         free(seen);
 }
 
-static int git_add_config(const char *var, const char *value)
-{
-       if (!strcmp(var, "core.excludesfile")) {
-               if (!value)
-                       die("core.excludesfile without value");
-               excludes_file = xstrdup(value);
-               return 0;
-       }
-
-       return git_default_config(var, value);
-}
-
 int interactive_add(void)
 {
        const char *argv[2] = { "add--interactive", NULL };
@@ -193,7 +175,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
                exit(interactive_add());
        }
 
-       git_config(git_add_config);
+       git_config(git_default_config);
 
        newfd = hold_locked_index(&lock_file, 1);
 
index 8411b38c7963852bffeb6dea1494399e8c9daa02..91f8752ff7fdb588e64f594519a2e9503c516630 100644 (file)
@@ -683,7 +683,6 @@ static char *git_header_name(char *line, int llen)
                        }
                }
        }
-       return NULL;
 }
 
 /* Verify that we recognize the lines following a git header */
@@ -1993,7 +1992,7 @@ static int verify_index_match(struct cache_entry *ce, struct stat *st)
                        return -1;
                return 0;
        }
-       return ce_match_stat(ce, st, 1);
+       return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID);
 }
 
 static int check_patch(struct patch *patch, struct patch *prev_patch)
index ba80bf8942f1db42b8a132471ddbfc38e565f115..c158d319dce78c6b1f0cfeffd91ee565a2d14eff 100644 (file)
@@ -335,7 +335,7 @@ static struct origin *find_origin(struct scoreboard *sb,
         * same and diff-tree is fairly efficient about this.
         */
        diff_setup(&diff_opts);
-       diff_opts.recursive = 1;
+       DIFF_OPT_SET(&diff_opts, RECURSIVE);
        diff_opts.detect_rename = 0;
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
        paths[0] = origin->path;
@@ -409,7 +409,7 @@ static struct origin *find_rename(struct scoreboard *sb,
        const char *paths[2];
 
        diff_setup(&diff_opts);
-       diff_opts.recursive = 1;
+       DIFF_OPT_SET(&diff_opts, RECURSIVE);
        diff_opts.detect_rename = DIFF_DETECT_RENAME;
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
        diff_opts.single_follow = origin->path;
@@ -1075,7 +1075,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
                return 1; /* nothing remains for this target */
 
        diff_setup(&diff_opts);
-       diff_opts.recursive = 1;
+       DIFF_OPT_SET(&diff_opts, RECURSIVE);
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
 
        paths[0] = NULL;
@@ -1093,7 +1093,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
        if ((opt & PICKAXE_BLAME_COPY_HARDEST)
            || ((opt & PICKAXE_BLAME_COPY_HARDER)
                && (!porigin || strcmp(target->path, porigin->path))))
-               diff_opts.find_copies_harder = 1;
+               DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER);
 
        if (is_null_sha1(target->commit->object.sha1))
                do_diff_cache(parent->tree->object.sha1, &diff_opts);
@@ -1102,7 +1102,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
                               target->commit->tree->object.sha1,
                               "", &diff_opts);
 
-       if (!diff_opts.find_copies_harder)
+       if (!DIFF_OPT_TST(&diff_opts, FIND_COPIES_HARDER))
                diffcore_std(&diff_opts);
 
        retval = 0;
index 3bf40f145378e06131a288d8234f123e0217a932..2694c9cf497bb0f20c771a560d65eae5702bf931 100644 (file)
@@ -507,48 +507,36 @@ static void rename_branch(const char *oldname, const char *newname, int force)
 
 int cmd_branch(int argc, const char **argv, const char *prefix)
 {
-       int delete = 0, force_delete = 0, force_create = 0;
-       int rename = 0, force_rename = 0;
+       int delete = 0, rename = 0, force_create = 0;
        int verbose = 0, abbrev = DEFAULT_ABBREV, detached = 0;
        int reflog = 0, track;
-       int kinds = REF_LOCAL_BRANCH, kind_remote = 0, kind_any = 0;
+       int kinds = REF_LOCAL_BRANCH;
 
        struct option options[] = {
                OPT_GROUP("Generic options"),
                OPT__VERBOSE(&verbose),
                OPT_BOOLEAN( 0 , "track",  &track, "set up tracking mode (see git-pull(1))"),
                OPT_BOOLEAN( 0 , "color",  &branch_use_color, "use colored output"),
-               OPT_BOOLEAN('r', NULL,     &kind_remote, "act on remote-tracking branches"),
+               OPT_SET_INT('r', NULL,     &kinds, "act on remote-tracking branches",
+                       REF_REMOTE_BRANCH),
                OPT__ABBREV(&abbrev),
 
                OPT_GROUP("Specific git-branch actions:"),
-               OPT_BOOLEAN('a', NULL,     &kind_any, "list both remote-tracking and local branches"),
-               OPT_BOOLEAN('d', NULL,     &delete, "delete fully merged branch"),
-               OPT_BOOLEAN('D', NULL,     &force_delete, "delete branch (even if not merged)"),
-               OPT_BOOLEAN('l', NULL,     &reflog, "create the branch's reflog"),
-               OPT_BOOLEAN('f', NULL,     &force_create, "force creation (when already exists)"),
-               OPT_BOOLEAN('m', NULL,     &rename, "move/rename a branch and its reflog"),
-               OPT_BOOLEAN('M', NULL,     &force_rename, "move/rename a branch, even if target exists"),
+               OPT_SET_INT('a', NULL, &kinds, "list both remote-tracking and local branches",
+                       REF_REMOTE_BRANCH | REF_LOCAL_BRANCH),
+               OPT_BIT('d', NULL, &delete, "delete fully merged branch", 1),
+               OPT_BIT('D', NULL, &delete, "delete branch (even if not merged)", 2),
+               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_END(),
        };
 
        git_config(git_branch_config);
        track = branch_track;
        argc = parse_options(argc, argv, options, builtin_branch_usage, 0);
-
-       delete |= force_delete;
-       rename |= force_rename;
-       if (kind_remote)
-               kinds = REF_REMOTE_BRANCH;
-       if (kind_any)
-               kinds = REF_REMOTE_BRANCH | REF_LOCAL_BRANCH;
-       if (abbrev && abbrev < MINIMUM_ABBREV)
-               abbrev = MINIMUM_ABBREV;
-       else if (abbrev > 40)
-               abbrev = 40;
-
-       if ((delete && rename) || (delete && force_create) ||
-           (rename && force_create))
+       if (!!delete + !!rename + !!force_create > 1)
                usage_with_options(builtin_branch_usage, options);
 
        head = resolve_ref("HEAD", head_sha1, 0, NULL);
@@ -564,13 +552,13 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
        }
 
        if (delete)
-               return delete_branches(argc, argv, force_delete, kinds);
+               return delete_branches(argc, argv, delete > 1, kinds);
        else if (argc == 0)
                print_ref_list(kinds, detached, verbose, abbrev);
        else if (rename && (argc == 1))
-               rename_branch(head, argv[0], force_rename);
+               rename_branch(head, argv[0], rename > 1);
        else if (rename && (argc == 2))
-               rename_branch(argv[0], argv[1], force_rename);
+               rename_branch(argv[0], argv[1], rename > 1);
        else if (argc <= 2)
                create_branch(argv[0], (argc == 2) ? argv[1] : head,
                              force_create, reflog, track);
index 6cb30c8e12488f42521df71a844a86a2e9a968c7..046b7e34b5d5c6306d335dddbd5e283c8166e80e 100644 (file)
@@ -31,5 +31,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
        if (!rev.diffopt.output_format)
                rev.diffopt.output_format = DIFF_FORMAT_RAW;
        result = run_diff_files_cmd(&rev, argc, argv);
-       return rev.diffopt.exit_with_status ? rev.diffopt.has_changes: result;
+       if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS))
+               return DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0;
+       return result;
 }
index 81e7167438ecfc25a6f9a317af663034d653588e..556c506bfa7b5c5ef739d4203c585412a2764073 100644 (file)
@@ -44,5 +44,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
                return -1;
        }
        result = run_diff_index(&rev, cached);
-       return rev.diffopt.exit_with_status ? rev.diffopt.has_changes: result;
+       if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS))
+               return DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0;
+       return result;
 }
index 0b591c87169ff4b8c2173bedb26d6ed1a8a84b68..2e13716eec985e7274d6f44646c94d8224964b7c 100644 (file)
@@ -118,8 +118,8 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
        }
 
        if (!read_stdin)
-               return opt->diffopt.exit_with_status ?
-                   opt->diffopt.has_changes: 0;
+               return DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS)
+                       && DIFF_OPT_TST(&opt->diffopt, HAS_CHANGES);
 
        if (opt->diffopt.detect_rename)
                opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE |
@@ -134,5 +134,6 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
                else
                        diff_tree_stdin(line);
        }
-       return opt->diffopt.exit_with_status ? opt->diffopt.has_changes: 0;
+       return DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS)
+               && DIFF_OPT_TST(&opt->diffopt, HAS_CHANGES);
 }
index f557d21929fe3df018f30e68c7943ead7f8eb4a1..1b615991e1fc6aaa329811cc9f7b615e20b00917 100644 (file)
@@ -35,7 +35,7 @@ static void stuff_change(struct diff_options *opt,
            !hashcmp(old_sha1, new_sha1) && (old_mode == new_mode))
                return;
 
-       if (opt->reverse_diff) {
+       if (DIFF_OPT_TST(opt, REVERSE_DIFF)) {
                unsigned tmp;
                const unsigned char *tmp_u;
                const char *tmp_c;
@@ -253,13 +253,13 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
                if (diff_setup_done(&rev.diffopt) < 0)
                        die("diff_setup_done failed");
        }
-       rev.diffopt.allow_external = 1;
-       rev.diffopt.recursive = 1;
+       DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL);
+       DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
 
        /* If the user asked for our exit code then don't start a
         * pager or we would end up reporting its exit code instead.
         */
-       if (!rev.diffopt.exit_with_status)
+       if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS))
                setup_pager();
 
        /* Do we have --cached and not have a pending object, then
@@ -363,8 +363,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
        else
                result = builtin_diff_combined(&rev, argc, argv,
                                             ent, ents);
-       if (rev.diffopt.exit_with_status)
-               result = rev.diffopt.has_changes;
+       if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS))
+               result = DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0;
 
        if (1 < rev.diffopt.skip_stat_unmatch)
                refresh_index_quietly();
index 6a78517958567e9dee4bfb00236caf5c3d1c3d67..ed60847d9fcd0ad8803c432af8d0bc2dd3567768 100644 (file)
@@ -435,9 +435,7 @@ static int pick_rref(int sha1_only, const char *rref, const char *ls_remote_resu
                                cp++;
                        if (!*cp)
                                break;
-                       np = strchr(cp, '\n');
-                       if (!np)
-                               np = cp + strlen(cp);
+                       np = strchrnul(cp, '\n');
                        if (pass) {
                                lrr_list[i].line = cp;
                                lrr_list[i].name = cp + 41;
@@ -461,9 +459,7 @@ static int pick_rref(int sha1_only, const char *rref, const char *ls_remote_resu
                        rref++;
                if (!*rref)
                        break;
-               next = strchr(rref, '\n');
-               if (!next)
-                       next = rref + strlen(rref);
+               next = strchrnul(rref, '\n');
                rreflen = next - rref;
 
                for (i = 0; i < lrr_count; i++) {
index 5f5b59bfdb5056dfedf692215db2f9e4207f8580..be9e3ea2bcea0d0ab88a51d396aff5714822b77a 100644 (file)
@@ -8,10 +8,12 @@
 #include "path-list.h"
 #include "remote.h"
 #include "transport.h"
+#include "run-command.h"
 
 static const char fetch_usage[] = "git-fetch [-a | --append] [--upload-pack <upload-pack>] [-f | --force] [--no-tags] [-t | --tags] [-k | --keep] [-u | --update-head-ok] [--depth <depth>] [-v | --verbose] [<repository> <refspec>...]";
 
 static int append, force, tags, no_tags, update_head_ok, verbose, quiet;
+static const char *depth;
 static char *default_rla = NULL;
 static struct transport *transport;
 
@@ -152,6 +154,7 @@ static int s_update_ref(const char *action,
 }
 
 #define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
+#define REFCOL_WIDTH  10
 
 static int update_local_ref(struct ref *ref,
                            const char *remote,
@@ -181,8 +184,9 @@ static int update_local_ref(struct ref *ref,
 
        if (!hashcmp(ref->old_sha1, ref->new_sha1)) {
                if (verbose)
-                       sprintf(display, "= %-*s %s -> %s", SUMMARY_WIDTH,
-                               "[up to date]", remote, pretty_ref);
+                       sprintf(display, "= %-*s %-*s -> %s", SUMMARY_WIDTH,
+                               "[up to date]", REFCOL_WIDTH, remote,
+                               pretty_ref);
                return 0;
        }
 
@@ -194,15 +198,17 @@ static int update_local_ref(struct ref *ref,
                 * If this is the head, and it's not okay to update
                 * the head, and the old value of the head isn't empty...
                 */
-               sprintf(display, "! %-*s %s -> %s  (can't  fetch in current branch)",
-                       SUMMARY_WIDTH, "[rejected]", remote, pretty_ref);
+               sprintf(display, "! %-*s %-*s -> %s  (can't fetch in current branch)",
+                       SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote,
+                       pretty_ref);
                return 1;
        }
 
        if (!is_null_sha1(ref->old_sha1) &&
            !prefixcmp(ref->name, "refs/tags/")) {
-               sprintf(display, "- %-*s %s -> %s",
-                       SUMMARY_WIDTH, "[tag update]", remote, pretty_ref);
+               sprintf(display, "- %-*s %-*s -> %s",
+                       SUMMARY_WIDTH, "[tag update]", REFCOL_WIDTH, remote,
+                       pretty_ref);
                return s_update_ref("updating tag", ref, 0);
        }
 
@@ -220,8 +226,8 @@ static int update_local_ref(struct ref *ref,
                        what = "[new branch]";
                }
 
-               sprintf(display, "* %-*s %s -> %s",
-                       SUMMARY_WIDTH, what, remote, pretty_ref);
+               sprintf(display, "* %-*s %-*s -> %s", SUMMARY_WIDTH, what,
+                       REFCOL_WIDTH, remote, pretty_ref);
                return s_update_ref(msg, ref, 0);
        }
 
@@ -230,20 +236,21 @@ static int update_local_ref(struct ref *ref,
                strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
                strcat(quickref, "..");
                strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV));
-               sprintf(display, "  %-*s %s -> %s  (fast forward)",
-                       SUMMARY_WIDTH, quickref, remote, pretty_ref);
+               sprintf(display, "  %-*s %-*s -> %s", SUMMARY_WIDTH, quickref,
+                       REFCOL_WIDTH, remote, pretty_ref);
                return s_update_ref("fast forward", ref, 1);
        } else if (force || ref->force) {
                char quickref[84];
                strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
                strcat(quickref, "...");
                strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV));
-               sprintf(display, "+ %-*s %s -> %s  (forced update)",
-                       SUMMARY_WIDTH, quickref, remote, pretty_ref);
+               sprintf(display, "+ %-*s %-*s -> %s  (forced update)",
+                       SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote, pretty_ref);
                return s_update_ref("forced-update", ref, 1);
        } else {
-               sprintf(display, "! %-*s %s -> %s  (non fast forward)",
-                       SUMMARY_WIDTH, "[rejected]", remote, pretty_ref);
+               sprintf(display, "! %-*s %-*s -> %s  (non fast forward)",
+                       SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote,
+                       pretty_ref);
                return 1;
        }
 }
@@ -330,9 +337,72 @@ static void store_updated_refs(const char *url, struct ref *ref_map)
        fclose(fp);
 }
 
+/*
+ * We would want to bypass the object transfer altogether if
+ * everything we are going to fetch already exists and connected
+ * locally.
+ *
+ * The refs we are going to fetch are in to_fetch (nr_heads in
+ * total).  If running
+ *
+ *  $ git-rev-list --objects to_fetch[0] to_fetch[1] ... --not --all
+ *
+ * does not error out, that means everything reachable from the
+ * refs we are going to fetch exists and is connected to some of
+ * our existing refs.
+ */
+static int quickfetch(struct ref *ref_map)
+{
+       struct child_process revlist;
+       struct ref *ref;
+       char **argv;
+       int i, err;
+
+       /*
+        * If we are deepening a shallow clone we already have these
+        * objects reachable.  Running rev-list here will return with
+        * a good (0) exit status and we'll bypass the fetch that we
+        * really need to perform.  Claiming failure now will ensure
+        * we perform the network exchange to deepen our history.
+        */
+       if (depth)
+               return -1;
+
+       for (i = 0, ref = ref_map; ref; ref = ref->next)
+               i++;
+       if (!i)
+               return 0;
+
+       argv = xmalloc(sizeof(*argv) * (i + 6));
+       i = 0;
+       argv[i++] = xstrdup("rev-list");
+       argv[i++] = xstrdup("--quiet");
+       argv[i++] = xstrdup("--objects");
+       for (ref = ref_map; ref; ref = ref->next)
+               argv[i++] = xstrdup(sha1_to_hex(ref->old_sha1));
+       argv[i++] = xstrdup("--not");
+       argv[i++] = xstrdup("--all");
+       argv[i++] = NULL;
+
+       memset(&revlist, 0, sizeof(revlist));
+       revlist.argv = (const char**)argv;
+       revlist.git_cmd = 1;
+       revlist.no_stdin = 1;
+       revlist.no_stdout = 1;
+       revlist.no_stderr = 1;
+       err = run_command(&revlist);
+
+       for (i = 0; argv[i]; i++)
+               free(argv[i]);
+       free(argv);
+       return err;
+}
+
 static int fetch_refs(struct transport *transport, struct ref *ref_map)
 {
-       int ret = transport_fetch_refs(transport, ref_map);
+       int ret = quickfetch(ref_map);
+       if (ret)
+               ret = transport_fetch_refs(transport, ref_map);
        if (!ret)
                store_updated_refs(transport->url, ref_map);
        transport_unlock_pack(transport);
@@ -384,7 +454,7 @@ static struct ref *find_non_local_tags(struct transport *transport,
 
                if (!path_list_has_path(&existing_refs, ref_name) &&
                    !path_list_has_path(&new_refs, ref_name) &&
-                   lookup_object(ref->old_sha1)) {
+                   has_sha1_file(ref->old_sha1)) {
                        path_list_insert(ref_name, &new_refs);
 
                        rm = alloc_ref(strlen(ref_name) + 1);
@@ -468,7 +538,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        static const char **refs = NULL;
        int ref_nr = 0;
        int cmd_len = 0;
-       const char *depth = NULL, *upload_pack = NULL;
+       const char *upload_pack = NULL;
        int keep = 0;
 
        for (i = 1; i < argc; i++) {
index 8a3c962f8920bb883287053c850adf78312ff19b..6163bd4975e3e361e36ffc89ea4c91d0edd02949 100644 (file)
@@ -176,7 +176,7 @@ static void shortlog(const char *name, unsigned char *sha1,
        struct commit *commit;
        struct object *branch;
        struct list subjects = { NULL, NULL, 0, 0 };
-       int flags = UNINTERESTING | TREECHANGE | SEEN | SHOWN | ADDED;
+       int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
 
        branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40);
        if (!branch || branch->type != OBJ_COMMIT)
index bfde2e2bbeffaed68b369b25cfe1b5ef4b108e12..daf3a081650b6b39fe18f0fab61fa8b3f6c8be0f 100644 (file)
@@ -833,16 +833,19 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
        int i, num_refs;
        const char *format = "%(objectname) %(objecttype)\t%(refname)";
        struct ref_sort *sort = NULL, **sort_tail = &sort;
-       int maxcount = 0, quote_style;
-       int quote_shell = 0, quote_perl = 0, quote_python = 0, quote_tcl = 0;
+       int maxcount = 0, quote_style = 0;
        struct refinfo **refs;
        struct grab_ref_cbdata cbdata;
 
        struct option opts[] = {
-               OPT_BOOLEAN('s', "shell", &quote_shell, "quote placeholders suitably for shells"),
-               OPT_BOOLEAN('p', "perl",  &quote_perl, "quote placeholders suitably for perl"),
-               OPT_BOOLEAN( 0 , "python", &quote_python, "quote placeholders suitably for python"),
-               OPT_BOOLEAN( 0 , "tcl",  &quote_tcl, "quote placeholders suitably for tcl"),
+               OPT_BIT('s', "shell", &quote_style,
+                       "quote placeholders suitably for shells", QUOTE_SHELL),
+               OPT_BIT('p', "perl",  &quote_style,
+                       "quote placeholders suitably for perl", QUOTE_PERL),
+               OPT_BIT(0 , "python", &quote_style,
+                       "quote placeholders suitably for python", QUOTE_PYTHON),
+               OPT_BIT(0 , "tcl",  &quote_style,
+                       "quote placeholders suitably for tcl", QUOTE_TCL),
 
                OPT_GROUP(""),
                OPT_INTEGER( 0 , "count", &maxcount, "show only <n> matched refs"),
@@ -857,15 +860,13 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
                error("invalid --count argument: `%d'", maxcount);
                usage_with_options(for_each_ref_usage, opts);
        }
-       if (quote_shell + quote_perl + quote_python + quote_tcl > 1) {
+       if (HAS_MULTI_BITS(quote_style)) {
                error("more than one quoting style ?");
                usage_with_options(for_each_ref_usage, opts);
        }
        if (verify_format(format))
                usage_with_options(for_each_ref_usage, opts);
 
-       quote_style = QUOTE_SHELL * quote_shell + QUOTE_PERL * quote_perl +
-               QUOTE_PYTHON * quote_python + QUOTE_TCL * quote_tcl;
        if (!sort)
                sort = default_sort();
        sort_atom_limit = used_atom_cnt;
index 185876b0a6dc191bb5adc22cd5c2f012cd70e479..bbf747fc7b66f6b4f19d9dc62a9ba10965199917 100644 (file)
@@ -294,7 +294,7 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
                        if (opt->pre_context) {
                                push_arg("-B");
                                len += snprintf(argptr, sizeof(randarg)-len,
-                                               "%u", opt->pre_context);
+                                               "%u", opt->pre_context) + 1;
                                if (sizeof(randarg) <= len)
                                        die("maximum length of args exceeded");
                                push_arg(argptr);
@@ -303,7 +303,7 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
                        if (opt->post_context) {
                                push_arg("-A");
                                len += snprintf(argptr, sizeof(randarg)-len,
-                                               "%u", opt->post_context);
+                                               "%u", opt->post_context) + 1;
                                if (sizeof(randarg) <= len)
                                        die("maximum length of args exceeded");
                                push_arg(argptr);
@@ -313,7 +313,7 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
                else {
                        push_arg("-C");
                        len += snprintf(argptr, sizeof(randarg)-len,
-                                       "%u", opt->post_context);
+                                       "%u", opt->post_context) + 1;
                        if (sizeof(randarg) <= len)
                                die("maximum length of args exceeded");
                        push_arg(argptr);
index 8b2bf632c534c5a9b5295884e517d70c7d2d9e86..e1f1cf67143721933010065130adaba8723b272b 100644 (file)
@@ -55,13 +55,13 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
        rev->abbrev = DEFAULT_ABBREV;
        rev->commit_format = CMIT_FMT_DEFAULT;
        rev->verbose_header = 1;
-       rev->diffopt.recursive = 1;
+       DIFF_OPT_SET(&rev->diffopt, RECURSIVE);
        rev->show_root_diff = default_show_root;
        rev->subject_prefix = fmt_patch_subject_prefix;
        argc = setup_revisions(argc, argv, rev, "HEAD");
        if (rev->diffopt.pickaxe || rev->diffopt.filter)
                rev->always_show_header = 0;
-       if (rev->diffopt.follow_renames) {
+       if (DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES)) {
                rev->always_show_header = 0;
                if (rev->diffopt.nr_paths != 1)
                        usage("git logs can only follow renames on one pathname at a time");
@@ -77,11 +77,134 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
        }
 }
 
+/*
+ * This gives a rough estimate for how many commits we
+ * will print out in the list.
+ */
+static int estimate_commit_count(struct rev_info *rev, struct commit_list *list)
+{
+       int n = 0;
+
+       while (list) {
+               struct commit *commit = list->item;
+               unsigned int flags = commit->object.flags;
+               list = list->next;
+               if (!(flags & (TREESAME | UNINTERESTING)))
+                       n++;
+       }
+       return n;
+}
+
+static void show_early_header(struct rev_info *rev, const char *stage, int nr)
+{
+       if (rev->shown_one) {
+               rev->shown_one = 0;
+               if (rev->commit_format != CMIT_FMT_ONELINE)
+                       putchar(rev->diffopt.line_termination);
+       }
+       printf("Final output: %d %s\n", nr, stage);
+}
+
+struct itimerval early_output_timer;
+
+static void log_show_early(struct rev_info *revs, struct commit_list *list)
+{
+       int i = revs->early_output;
+       int show_header = 1;
+
+       sort_in_topological_order(&list, revs->lifo);
+       while (list && i) {
+               struct commit *commit = list->item;
+               switch (simplify_commit(revs, commit)) {
+               case commit_show:
+                       if (show_header) {
+                               int n = estimate_commit_count(revs, list);
+                               show_early_header(revs, "incomplete", n);
+                               show_header = 0;
+                       }
+                       log_tree_commit(revs, commit);
+                       i--;
+                       break;
+               case commit_ignore:
+                       break;
+               case commit_error:
+                       return;
+               }
+               list = list->next;
+       }
+
+       /* Did we already get enough commits for the early output? */
+       if (!i)
+               return;
+
+       /*
+        * ..if no, then repeat it twice a second until we
+        * do.
+        *
+        * NOTE! We don't use "it_interval", because if the
+        * reader isn't listening, we want our output to be
+        * throttled by the writing, and not have the timer
+        * trigger every second even if we're blocked on a
+        * reader!
+        */
+       early_output_timer.it_value.tv_sec = 0;
+       early_output_timer.it_value.tv_usec = 500000;
+       setitimer(ITIMER_REAL, &early_output_timer, NULL);
+}
+
+static void early_output(int signal)
+{
+       show_early_output = log_show_early;
+}
+
+static void setup_early_output(struct rev_info *rev)
+{
+       struct sigaction sa;
+
+       /*
+        * Set up the signal handler, minimally intrusively:
+        * we only set a single volatile integer word (not
+        * using sigatomic_t - trying to avoid unnecessary
+        * system dependencies and headers), and using
+        * SA_RESTART.
+        */
+       memset(&sa, 0, sizeof(sa));
+       sa.sa_handler = early_output;
+       sigemptyset(&sa.sa_mask);
+       sa.sa_flags = SA_RESTART;
+       sigaction(SIGALRM, &sa, NULL);
+
+       /*
+        * If we can get the whole output in less than a
+        * tenth of a second, don't even bother doing the
+        * early-output thing..
+        *
+        * This is a one-time-only trigger.
+        */
+       early_output_timer.it_value.tv_sec = 0;
+       early_output_timer.it_value.tv_usec = 100000;
+       setitimer(ITIMER_REAL, &early_output_timer, NULL);
+}
+
+static void finish_early_output(struct rev_info *rev)
+{
+       int n = estimate_commit_count(rev, rev->commits);
+       signal(SIGALRM, SIG_IGN);
+       show_early_header(rev, "done", n);
+}
+
 static int cmd_log_walk(struct rev_info *rev)
 {
        struct commit *commit;
 
+       if (rev->early_output)
+               setup_early_output(rev);
+
        prepare_revision_walk(rev);
+
+       if (rev->early_output)
+               finish_early_output(rev);
+
        while ((commit = get_revision(rev)) != NULL) {
                log_tree_commit(rev, commit);
                if (!rev->reflog_info) {
@@ -185,11 +308,9 @@ int cmd_show(int argc, const char **argv, const char *prefix)
                        struct tag *t = (struct tag *)o;
 
                        printf("%stag %s%s\n\n",
-                                       diff_get_color(rev.diffopt.color_diff,
-                                               DIFF_COMMIT),
+                                       diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
                                        t->tag,
-                                       diff_get_color(rev.diffopt.color_diff,
-                                               DIFF_RESET));
+                                       diff_get_color_opt(&rev.diffopt, DIFF_RESET));
                        ret = show_object(o->sha1, 1);
                        objects[i].item = (struct object *)t->tagged;
                        i--;
@@ -197,11 +318,9 @@ int cmd_show(int argc, const char **argv, const char *prefix)
                }
                case OBJ_TREE:
                        printf("%stree %s%s\n\n",
-                                       diff_get_color(rev.diffopt.color_diff,
-                                               DIFF_COMMIT),
+                                       diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
                                        name,
-                                       diff_get_color(rev.diffopt.color_diff,
-                                               DIFF_RESET));
+                                       diff_get_color_opt(&rev.diffopt, DIFF_RESET));
                        read_tree_recursive((struct tree *)o, "", 0, 0, NULL,
                                        show_tree_object);
                        break;
@@ -273,6 +392,8 @@ static int istitlechar(char c)
 static char *extra_headers = NULL;
 static int extra_headers_size = 0;
 static const char *fmt_patch_suffix = ".patch";
+static int numbered = 0;
+static int auto_number = 0;
 
 static int git_format_config(const char *var, const char *value)
 {
@@ -297,6 +418,15 @@ static int git_format_config(const char *var, const char *value)
        if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) {
                return 0;
        }
+       if (!strcmp(var, "format.numbered")) {
+               if (!strcasecmp(value, "auto")) {
+                       auto_number = 1;
+                       return 0;
+               }
+
+               numbered = git_config_bool(var, value);
+               return 0;
+       }
 
        return git_log_config(var, value);
 }
@@ -466,7 +596,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        struct rev_info rev;
        int nr = 0, total, i, j;
        int use_stdout = 0;
-       int numbered = 0;
        int start_number = -1;
        int keep_subject = 0;
        int numbered_files = 0;         /* _just_ numbers */
@@ -487,7 +616,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        rev.combine_merges = 0;
        rev.ignore_merges = 1;
        rev.diffopt.msg_sep = "";
-       rev.diffopt.recursive = 1;
+       DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
 
        rev.subject_prefix = fmt_patch_subject_prefix;
        rev.extra_headers = extra_headers;
@@ -503,6 +632,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                else if (!strcmp(argv[i], "-n") ||
                                !strcmp(argv[i], "--numbered"))
                        numbered = 1;
+               else if (!strcmp(argv[i], "-N") ||
+                               !strcmp(argv[i], "--no-numbered")) {
+                       numbered = 0;
+                       auto_number = 0;
+               }
                else if (!prefixcmp(argv[i], "--start-number="))
                        start_number = strtol(argv[i] + 15, NULL, 10);
                else if (!strcmp(argv[i], "--numbered-files"))
@@ -590,8 +724,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        if (!rev.diffopt.output_format)
                rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_SUMMARY | DIFF_FORMAT_PATCH;
 
-       if (!rev.diffopt.text)
-               rev.diffopt.binary = 1;
+       if (!DIFF_OPT_TST(&rev.diffopt, TEXT))
+               DIFF_OPT_SET(&rev.diffopt, BINARY);
 
        if (!output_directory && !use_stdout)
                output_directory = prefix;
@@ -642,6 +776,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                list[nr - 1] = commit;
        }
        total = nr;
+       if (!keep_subject && auto_number && total > 1)
+               numbered = 1;
        if (numbered)
                rev.total = total + start_number - 1;
        rev.add_signoff = add_signoff;
@@ -747,7 +883,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
        revs.diff = 1;
        revs.combine_merges = 0;
        revs.ignore_merges = 1;
-       revs.diffopt.recursive = 1;
+       DIFF_OPT_SET(&revs.diffopt, RECURSIVE);
 
        if (add_pending_commit(head, &revs, 0))
                die("Unknown commit %s", head);
index e0b856f4328a4df945f3dd0c3f0e1dc14020238f..7f607098305fcf14c3e2a7634b6a5dc118445306 100644 (file)
@@ -387,8 +387,8 @@ static void overlay_tree(const char *tree_name, const char *prefix)
 static const char ls_files_usage[] =
        "git-ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified])* "
        "[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] "
-       "[ --exclude-per-directory=<filename> ] [--full-name] [--abbrev] "
-       "[--] [<file>]*";
+       "[ --exclude-per-directory=<filename> ] [--exclude-standard] "
+       "[--full-name] [--abbrev] [--] [<file>]*";
 
 int cmd_ls_files(int argc, const char **argv, const char *prefix)
 {
@@ -496,6 +496,11 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
                        dir.exclude_per_dir = arg + 24;
                        continue;
                }
+               if (!strcmp(arg, "--exclude-standard")) {
+                       exc_given = 1;
+                       setup_standard_excludes(&dir);
+                       continue;
+               }
                if (!strcmp(arg, "--full-name")) {
                        prefix_offset = 0;
                        continue;
index a62f06bb89aa6ef035c26c4aad05c0fdbf0512de..1923fb1914c910457d2a987d73915db365fef68d 100644 (file)
@@ -122,19 +122,13 @@ static char const * const pack_refs_usage[] = {
 
 int cmd_pack_refs(int argc, const char **argv, const char *prefix)
 {
-       int all = 0, prune = 1;
-       unsigned int flags = 0;
+       unsigned int flags = PACK_REFS_PRUNE;
        struct option opts[] = {
-               OPT_BOOLEAN(0, "all", &all, "pack everything"),
-               OPT_BOOLEAN(0, "prune", &prune, "prune loose refs (default)"),
+               OPT_BIT(0, "all",   &flags, "pack everything", PACK_REFS_ALL),
+               OPT_BIT(0, "prune", &flags, "prune loose refs (default)", PACK_REFS_PRUNE),
                OPT_END(),
        };
-
        if (parse_options(argc, argv, opts, pack_refs_usage, 0))
                usage_with_options(pack_refs_usage, opts);
-       if (prune)
-               flags |= PACK_REFS_PRUNE;
-       if (all)
-               flags |= PACK_REFS_ALL;
        return pack_refs(flags);
 }
index 697046723fc64f38ab4fb589c84f1c5d5934894a..1cb5f67119a37b8490c76f4846372ba28a316fbf 100644 (file)
@@ -26,6 +26,7 @@ static const char rev_list_usage[] =
 "    --remove-empty\n"
 "    --all\n"
 "    --stdin\n"
+"    --quiet\n"
 "  ordering output:\n"
 "    --topo-order\n"
 "    --date-order\n"
@@ -50,6 +51,7 @@ static int show_timestamp;
 static int hdr_termination;
 static const char *header_prefix;
 
+static void finish_commit(struct commit *commit);
 static void show_commit(struct commit *commit)
 {
        if (show_timestamp)
@@ -93,6 +95,11 @@ static void show_commit(struct commit *commit)
                strbuf_release(&buf);
        }
        maybe_flush_or_die(stdout, "stdout");
+       finish_commit(commit);
+}
+
+static void finish_commit(struct commit *commit)
+{
        if (commit->parents) {
                free_commit_list(commit->parents);
                commit->parents = NULL;
@@ -101,6 +108,12 @@ static void show_commit(struct commit *commit)
        commit->buffer = NULL;
 }
 
+static void finish_object(struct object_array_entry *p)
+{
+       if (p->item->type == OBJ_BLOB && !has_sha1_file(p->item->sha1))
+               die("missing blob object '%s'", sha1_to_hex(p->item->sha1));
+}
+
 static void show_object(struct object_array_entry *p)
 {
        /* An object with name "foo\n0000000..." can be used to
@@ -108,9 +121,7 @@ static void show_object(struct object_array_entry *p)
         */
        const char *ep = strchr(p->name, '\n');
 
-       if (p->item->type == OBJ_BLOB && !has_sha1_file(p->item->sha1))
-               die("missing blob object '%s'", sha1_to_hex(p->item->sha1));
-
+       finish_object(p);
        if (ep) {
                printf("%s %.*s\n", sha1_to_hex(p->item->sha1),
                       (int) (ep - p->name),
@@ -142,7 +153,7 @@ static int count_distance(struct commit_list *entry)
 
                if (commit->object.flags & (UNINTERESTING | COUNTED))
                        break;
-               if (!revs.prune_fn || (commit->object.flags & TREECHANGE))
+               if (!(commit->object.flags & TREESAME))
                        nr++;
                commit->object.flags |= COUNTED;
                p = commit->parents;
@@ -198,7 +209,7 @@ static inline int halfway(struct commit_list *p, int nr)
        /*
         * Don't short-cut something we are not going to return!
         */
-       if (revs.prune_fn && !(p->item->object.flags & TREECHANGE))
+       if (p->item->object.flags & TREESAME)
                return 0;
        if (DEBUG_BISECT)
                return 0;
@@ -234,7 +245,7 @@ static void show_list(const char *debug, int counted, int nr,
                char *ep, *sp;
 
                fprintf(stderr, "%c%c%c ",
-                       (flags & TREECHANGE) ? 'T' : ' ',
+                       (flags & TREESAME) ? ' ' : 'T',
                        (flags & UNINTERESTING) ? 'U' : ' ',
                        (flags & COUNTED) ? 'C' : ' ');
                if (commit->util)
@@ -268,7 +279,7 @@ static struct commit_list *best_bisection(struct commit_list *list, int nr)
                int distance;
                unsigned flags = p->item->object.flags;
 
-               if (revs.prune_fn && !(flags & TREECHANGE))
+               if (flags & TREESAME)
                        continue;
                distance = weight(p);
                if (nr - distance < distance)
@@ -308,7 +319,7 @@ static struct commit_list *best_bisection_sorted(struct commit_list *list, int n
                int distance;
                unsigned flags = p->item->object.flags;
 
-               if (revs.prune_fn && !(flags & TREECHANGE))
+               if (flags & TREESAME)
                        continue;
                distance = weight(p);
                if (nr - distance < distance)
@@ -362,7 +373,7 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
                p->item->util = &weights[n++];
                switch (count_interesting_parents(commit)) {
                case 0:
-                       if (!revs.prune_fn || (flags & TREECHANGE)) {
+                       if (!(flags & TREESAME)) {
                                weight_set(p, 1);
                                counted++;
                                show_list("bisection 2 count one",
@@ -435,7 +446,7 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
                         * add one for p itself if p is to be counted,
                         * otherwise inherit it from q directly.
                         */
-                       if (!revs.prune_fn || (flags & TREECHANGE)) {
+                       if (!(flags & TREESAME)) {
                                weight_set(p, weight(q)+1);
                                counted++;
                                show_list("bisection 2 count one",
@@ -482,7 +493,7 @@ static struct commit_list *find_bisection(struct commit_list *list,
                        continue;
                p->next = last;
                last = p;
-               if (!revs.prune_fn || (flags & TREECHANGE))
+               if (!(flags & TREESAME))
                        nr++;
                on_list++;
        }
@@ -527,6 +538,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
        int read_from_stdin = 0;
        int bisect_show_vars = 0;
        int bisect_find_all = 0;
+       int quiet = 0;
 
        git_config(git_default_config);
        init_revisions(&revs, prefix);
@@ -565,6 +577,10 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
                        read_revisions_from_stdin(&revs);
                        continue;
                }
+               if (!strcmp(arg, "--quiet")) {
+                       quiet = 1;
+                       continue;
+               }
                usage(rev_list_usage);
 
        }
@@ -640,7 +656,9 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
                }
        }
 
-       traverse_commit_list(&revs, show_commit, show_object);
+       traverse_commit_list(&revs,
+               quiet ? finish_commit : show_commit,
+               quiet ? finish_object : show_object);
 
        return 0;
 }
index 8d78b69c902a99738cfc337222ba71493ff45370..d1038a0e66edf728fbba9476b3b9f443647c612c 100644 (file)
@@ -8,6 +8,7 @@
 #include "refs.h"
 #include "quote.h"
 #include "builtin.h"
+#include "parse-options.h"
 
 #define DO_REVS                1
 #define DO_NOREV       2
@@ -209,13 +210,138 @@ static int try_difference(const char *arg)
        return 0;
 }
 
+static int parseopt_dump(const struct option *o, const char *arg, int unset)
+{
+       struct strbuf *parsed = o->value;
+       if (unset)
+               strbuf_addf(parsed, " --no-%s", o->long_name);
+       else if (o->short_name)
+               strbuf_addf(parsed, " -%c", o->short_name);
+       else
+               strbuf_addf(parsed, " --%s", o->long_name);
+       if (arg) {
+               strbuf_addch(parsed, ' ');
+               sq_quote_buf(parsed, arg);
+       }
+       return 0;
+}
+
+static const char *skipspaces(const char *s)
+{
+       while (isspace(*s))
+               s++;
+       return s;
+}
+
+static int cmd_parseopt(int argc, const char **argv, const char *prefix)
+{
+       static int keep_dashdash = 0;
+       static char const * const parseopt_usage[] = {
+               "git-rev-parse --parseopt [options] -- [<args>...]",
+               NULL
+       };
+       static struct option parseopt_opts[] = {
+               OPT_BOOLEAN(0, "keep-dashdash", &keep_dashdash,
+                                       "keep the `--` passed as an arg"),
+               OPT_END(),
+       };
+
+       struct strbuf sb, parsed;
+       const char **usage = NULL;
+       struct option *opts = NULL;
+       int onb = 0, osz = 0, unb = 0, usz = 0;
+
+       strbuf_init(&parsed, 0);
+       strbuf_addstr(&parsed, "set --");
+       argc = parse_options(argc, argv, parseopt_opts, parseopt_usage,
+                            PARSE_OPT_KEEP_DASHDASH);
+       if (argc < 1 || strcmp(argv[0], "--"))
+               usage_with_options(parseopt_usage, parseopt_opts);
+
+       strbuf_init(&sb, 0);
+       /* get the usage up to the first line with a -- on it */
+       for (;;) {
+               if (strbuf_getline(&sb, stdin, '\n') == EOF)
+                       die("premature end of input");
+               ALLOC_GROW(usage, unb + 1, usz);
+               if (!strcmp("--", sb.buf)) {
+                       if (unb < 1)
+                               die("no usage string given before the `--' separator");
+                       usage[unb] = NULL;
+                       break;
+               }
+               usage[unb++] = strbuf_detach(&sb, NULL);
+       }
+
+       /* parse: (<short>|<short>,<long>|<long>)[=?]? SP+ <help> */
+       while (strbuf_getline(&sb, stdin, '\n') != EOF) {
+               const char *s;
+               struct option *o;
+
+               if (!sb.len)
+                       continue;
+
+               ALLOC_GROW(opts, onb + 1, osz);
+               memset(opts + onb, 0, sizeof(opts[onb]));
+
+               o = &opts[onb++];
+               s = strchr(sb.buf, ' ');
+               if (!s || *sb.buf == ' ') {
+                       o->type = OPTION_GROUP;
+                       o->help = xstrdup(skipspaces(s));
+                       continue;
+               }
+
+               o->type = OPTION_CALLBACK;
+               o->help = xstrdup(skipspaces(s));
+               o->value = &parsed;
+               o->callback = &parseopt_dump;
+               switch (s[-1]) {
+               case '=':
+                       s--;
+                       break;
+               case '?':
+                       o->flags = PARSE_OPT_OPTARG;
+                       s--;
+                       break;
+               default:
+                       o->flags = PARSE_OPT_NOARG;
+                       break;
+               }
+
+               if (s - sb.buf == 1) /* short option only */
+                       o->short_name = *sb.buf;
+               else if (sb.buf[1] != ',') /* long option only */
+                       o->long_name = xmemdupz(sb.buf, s - sb.buf);
+               else {
+                       o->short_name = *sb.buf;
+                       o->long_name = xmemdupz(sb.buf + 2, s - sb.buf - 2);
+               }
+       }
+       strbuf_release(&sb);
+
+       /* put an OPT_END() */
+       ALLOC_GROW(opts, onb + 1, osz);
+       memset(opts + onb, 0, sizeof(opts[onb]));
+       argc = parse_options(argc, argv, opts, usage,
+                            keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0);
+
+       strbuf_addf(&parsed, " --");
+       sq_quote_argv(&parsed, argv, argc, 0);
+       puts(parsed.buf);
+       return 0;
+}
+
 int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 {
        int i, as_is = 0, verify = 0;
        unsigned char sha1[20];
 
-       git_config(git_default_config);
+       if (argc > 1 && !strcmp("--parseopt", argv[1]))
+               return cmd_parseopt(argc - 1, argv + 1, prefix);
 
+       prefix = setup_git_directory();
+       git_config(git_default_config);
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
 
index 4aca3dc79b2a3d28f158ff61c01363244bfd7637..cbb0f04e85627a5509bb2ba8cbf04a54d4d20c41 100644 (file)
@@ -246,9 +246,37 @@ static int git_tag_config(const char *var, const char *value)
        return git_default_config(var, value);
 }
 
+static void write_tag_body(int fd, const unsigned char *sha1)
+{
+       unsigned long size;
+       enum object_type type;
+       char *buf, *sp, *eob;
+       size_t len;
+
+       buf = read_sha1_file(sha1, &type, &size);
+       if (!buf)
+               return;
+       /* skip header */
+       sp = strstr(buf, "\n\n");
+
+       if (!sp || !size || type != OBJ_TAG) {
+               free(buf);
+               return;
+       }
+       sp += 2; /* skip the 2 LFs */
+       eob = strstr(sp, "\n" PGP_SIGNATURE "\n");
+       if (eob)
+               len = eob - sp;
+       else
+               len = buf + size - sp;
+       write_or_die(fd, sp, len);
+
+       free(buf);
+}
+
 static void create_tag(const unsigned char *object, const char *tag,
                       struct strbuf *buf, int message, int sign,
-                          unsigned char *result)
+                          unsigned char *prev, unsigned char *result)
 {
        enum object_type type;
        char header_buf[1024];
@@ -281,7 +309,11 @@ static void create_tag(const unsigned char *object, const char *tag,
                if (fd < 0)
                        die("could not create file '%s': %s",
                                                path, strerror(errno));
-               write_or_die(fd, tag_template, strlen(tag_template));
+
+               if (!is_null_sha1(prev))
+                       write_tag_body(fd, prev);
+               else
+                       write_or_die(fd, tag_template, strlen(tag_template));
                close(fd);
 
                launch_editor(path, buf);
@@ -418,7 +450,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
                die("tag '%s' already exists", tag);
 
        if (annotate)
-               create_tag(object, tag, &buf, message, sign, object);
+               create_tag(object, tag, &buf, message, sign, prev, object);
 
        lock = lock_any_ref_for_update(ref, prev, 0);
        if (!lock)
diff --git a/cache.h b/cache.h
index f0a25c7ffcd47d663f2d41cd29dbabc57c2cab93..33ebccf48d0d8963ab5b262bfb87312e6542ed75 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -175,8 +175,8 @@ extern struct index_state the_index;
 #define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))
 #define add_file_to_cache(path, verbose) add_file_to_index(&the_index, (path), (verbose))
 #define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL)
-#define ce_match_stat(ce, st, really) ie_match_stat(&the_index, (ce), (st), (really))
-#define ce_modified(ce, st, really) ie_modified(&the_index, (ce), (st), (really))
+#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))
 #endif
 
 enum object_type {
@@ -268,8 +268,14 @@ extern int remove_file_from_index(struct index_state *, const char *path);
 extern int add_file_to_index(struct index_state *, const char *path, int verbose);
 extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
 extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
-extern int ie_match_stat(struct index_state *, struct cache_entry *, struct stat *, int);
-extern int ie_modified(struct index_state *, struct cache_entry *, struct stat *, int);
+
+/* do stat comparison even if CE_VALID is true */
+#define CE_MATCH_IGNORE_VALID          01
+/* do not check the contents but report dirty on racily-clean entries */
+#define CE_MATCH_RACY_IS_DIRTY 02
+extern int ie_match_stat(struct index_state *, struct cache_entry *, struct stat *, unsigned int);
+extern int ie_modified(struct index_state *, struct cache_entry *, struct stat *, unsigned int);
+
 extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
 extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
 extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object);
@@ -575,6 +581,7 @@ extern int pager_in_use;
 extern int pager_use_color;
 
 extern char *editor_program;
+extern char *excludes_file;
 
 /* base85 */
 int decode_85(char *dst, const char *line, int linelen);
index d6a08b4a55273af1a5f2933f3b5c6cb818ba74c6..00d92a16631a80ff8ec4e995dafcd3e55434fad5 100644 (file)
@@ -18,7 +18,7 @@ int main(int ac, char **av)
 
                if (ce_match_stat(ce, &st, 0))
                        dirty++;
-               else if (ce_match_stat(ce, &st, 2))
+               else if (ce_match_stat(ce, &st, CE_MATCH_RACY_IS_DIRTY))
                        racy++;
                else
                        clean++;
index fe5a2a1953a06204ad6f1c045bd06dd984d3acc6..5a658dc0d54f91faee450e4f9ebacc1a6338478f 100644 (file)
@@ -664,7 +664,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
        int mode_differs = 0;
        int i, show_hunks;
        int working_tree_file = is_null_sha1(elem->sha1);
-       int abbrev = opt->full_index ? 40 : DEFAULT_ABBREV;
+       int abbrev = DIFF_OPT_TST(opt, FULL_INDEX) ? 40 : DEFAULT_ABBREV;
        mmfile_t result_file;
 
        context = opt->context;
@@ -784,7 +784,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
 
        if (show_hunks || mode_differs || working_tree_file) {
                const char *abb;
-               int use_color = opt->color_diff;
+               int use_color = DIFF_OPT_TST(opt, COLOR_DIFF);
                const char *c_meta = diff_get_color(use_color, DIFF_METAINFO);
                const char *c_reset = diff_get_color(use_color, DIFF_RESET);
                int added = 0;
@@ -836,7 +836,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
                        dump_quoted_path("+++ /dev/", "null", c_meta, c_reset);
                else
                        dump_quoted_path("+++ b/", elem->path, c_meta, c_reset);
-               dump_sline(sline, cnt, num_parent, opt->color_diff);
+               dump_sline(sline, cnt, num_parent, DIFF_OPT_TST(opt, COLOR_DIFF));
        }
        free(result);
 
@@ -929,8 +929,8 @@ void diff_tree_combined(const unsigned char *sha1,
 
        diffopts = *opt;
        diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
-       diffopts.recursive = 1;
-       diffopts.allow_external = 0;
+       DIFF_OPT_SET(&diffopts, RECURSIVE);
+       DIFF_OPT_CLR(&diffopts, ALLOW_EXTERNAL);
 
        show_log_first = !!rev->loginfo && !rev->no_commit_id;
        needsep = 0;
index b5092658724e2172abdf54a1af6d91bda0e176da..f074811edc8c5ba41351f50c48a6cda7614e8f8e 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -8,22 +8,6 @@
 
 int save_commit_buffer = 1;
 
-struct sort_node
-{
-       /*
-        * the number of children of the associated commit
-        * that also occur in the list being sorted.
-        */
-       unsigned int indegree;
-
-       /*
-        * reference to original list item that we will re-use
-        * on output.
-        */
-       struct commit_list * list_item;
-
-};
-
 const char *commit_type = "commit";
 
 static struct commit *check_commit(struct object *obj,
@@ -431,69 +415,38 @@ struct commit *pop_commit(struct commit_list **stack)
        return item;
 }
 
-void topo_sort_default_setter(struct commit *c, void *data)
-{
-       c->util = data;
-}
-
-void *topo_sort_default_getter(struct commit *c)
-{
-       return c->util;
-}
-
 /*
  * Performs an in-place topological sort on the list supplied.
  */
 void sort_in_topological_order(struct commit_list ** list, int lifo)
 {
-       sort_in_topological_order_fn(list, lifo, topo_sort_default_setter,
-                                    topo_sort_default_getter);
-}
-
-void sort_in_topological_order_fn(struct commit_list ** list, int lifo,
-                                 topo_sort_set_fn_t setter,
-                                 topo_sort_get_fn_t getter)
-{
-       struct commit_list * next = *list;
-       struct commit_list * work = NULL, **insert;
-       struct commit_list ** pptr = list;
-       struct sort_node * nodes;
-       struct sort_node * next_nodes;
-       int count = 0;
-
-       /* determine the size of the list */
-       while (next) {
-               next = next->next;
-               count++;
-       }
+       struct commit_list *next, *orig = *list;
+       struct commit_list *work, **insert;
+       struct commit_list **pptr;
 
-       if (!count)
+       if (!orig)
                return;
-       /* allocate an array to help sort the list */
-       nodes = xcalloc(count, sizeof(*nodes));
-       /* link the list to the array */
-       next_nodes = nodes;
-       next=*list;
-       while (next) {
-               next_nodes->list_item = next;
-               setter(next->item, next_nodes);
-               next_nodes++;
-               next = next->next;
+       *list = NULL;
+
+       /* Mark them and clear the indegree */
+       for (next = orig; next; next = next->next) {
+               struct commit *commit = next->item;
+               commit->object.flags |= TOPOSORT;
+               commit->indegree = 0;
        }
+
        /* update the indegree */
-       next=*list;
-       while (next) {
+       for (next = orig; next; next = next->next) {
                struct commit_list * parents = next->item->parents;
                while (parents) {
-                       struct commit * parent=parents->item;
-                       struct sort_node * pn = (struct sort_node *) getter(parent);
+                       struct commit *parent = parents->item;
 
-                       if (pn)
-                               pn->indegree++;
-                       parents=parents->next;
+                       if (parent->object.flags & TOPOSORT)
+                               parent->indegree++;
+                       parents = parents->next;
                }
-               next=next->next;
        }
+
        /*
         * find the tips
         *
@@ -501,55 +454,56 @@ void sort_in_topological_order_fn(struct commit_list ** list, int lifo,
         *
         * the tips serve as a starting set for the work queue.
         */
-       next=*list;
+       work = NULL;
        insert = &work;
-       while (next) {
-               struct sort_node * node = (struct sort_node *) getter(next->item);
+       for (next = orig; next; next = next->next) {
+               struct commit *commit = next->item;
 
-               if (node->indegree == 0) {
-                       insert = &commit_list_insert(next->item, insert)->next;
-               }
-               next=next->next;
+               if (!commit->indegree)
+                       insert = &commit_list_insert(commit, insert)->next;
        }
 
        /* process the list in topological order */
        if (!lifo)
                sort_by_date(&work);
+
+       pptr = list;
+       *list = NULL;
        while (work) {
-               struct commit * work_item = pop_commit(&work);
-               struct sort_node * work_node = (struct sort_node *) getter(work_item);
-               struct commit_list * parents = work_item->parents;
+               struct commit *commit;
+               struct commit_list *parents, *work_item;
 
-               while (parents) {
-                       struct commit * parent=parents->item;
-                       struct sort_node * pn = (struct sort_node *) getter(parent);
-
-                       if (pn) {
-                               /*
-                                * parents are only enqueued for emission
-                                * when all their children have been emitted thereby
-                                * guaranteeing topological order.
-                                */
-                               pn->indegree--;
-                               if (!pn->indegree) {
-                                       if (!lifo)
-                                               insert_by_date(parent, &work);
-                                       else
-                                               commit_list_insert(parent, &work);
-                               }
+               work_item = work;
+               work = work_item->next;
+               work_item->next = NULL;
+
+               commit = work_item->item;
+               for (parents = commit->parents; parents ; parents = parents->next) {
+                       struct commit *parent=parents->item;
+
+                       if (!(parent->object.flags & TOPOSORT))
+                               continue;
+
+                       /*
+                        * parents are only enqueued for emission
+                        * when all their children have been emitted thereby
+                        * guaranteeing topological order.
+                        */
+                       if (!--parent->indegree) {
+                               if (!lifo)
+                                       insert_by_date(parent, &work);
+                               else
+                                       commit_list_insert(parent, &work);
                        }
-                       parents=parents->next;
                }
                /*
                 * work_item is a commit all of whose children
                 * have already been emitted. we can emit it now.
                 */
-               *pptr = work_node->list_item;
-               pptr = &(*pptr)->next;
-               *pptr = NULL;
-               setter(work_item, NULL);
+               commit->object.flags &= ~TOPOSORT;
+               *pptr = work_item;
+               pptr = &work_item->next;
        }
-       free(nodes);
 }
 
 /* merge-base stuff */
index 13b537293df97ae503b993aeba15edc2dac09e2a..aa679867a9376496febd5105121b1f49f3ff96a4 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -14,6 +14,7 @@ struct commit_list {
 struct commit {
        struct object object;
        void *util;
+       unsigned int indegree;
        unsigned long date;
        struct commit_list *parents;
        struct tree *tree;
@@ -84,31 +85,12 @@ void clear_commit_marks(struct commit *commit, unsigned int mark);
 /*
  * Performs an in-place topological sort of list supplied.
  *
- * Pre-conditions for sort_in_topological_order:
- *   all commits in input list and all parents of those
- *   commits must have object.util == NULL
- *
- * Pre-conditions for sort_in_topological_order_fn:
- *   all commits in input list and all parents of those
- *   commits must have getter(commit) == NULL
- *
- * Post-conditions:
  *   invariant of resulting list is:
  *      a reachable from b => ord(b) < ord(a)
  *   in addition, when lifo == 0, commits on parallel tracks are
  *   sorted in the dates order.
  */
-
-typedef void (*topo_sort_set_fn_t)(struct commit*, void *data);
-typedef void* (*topo_sort_get_fn_t)(struct commit*);
-
-void topo_sort_default_setter(struct commit *c, void *data);
-void *topo_sort_default_getter(struct commit *c);
-
 void sort_in_topological_order(struct commit_list ** list, int lifo);
-void sort_in_topological_order_fn(struct commit_list ** list, int lifo,
-                                 topo_sort_set_fn_t setter,
-                                 topo_sort_get_fn_t getter);
 
 struct commit_graft {
        unsigned char sha1[20];
@@ -135,4 +117,9 @@ extern int interactive_add(void);
 extern void add_files_to_cache(int verbose, const char *prefix, const char **files);
 extern int rerere(void);
 
+static inline int single_parent(struct commit *commit)
+{
+       return commit->parents && !commit->parents->next;
+}
+
 #endif /* COMMIT_H */
index dc3148d4566205858869973804de1c2ddb19e981..56e99fc0f4750174299303b27237737e09549933 100644 (file)
--- a/config.c
+++ b/config.c
@@ -431,6 +431,13 @@ int git_default_config(const char *var, const char *value)
                return 0;
        }
 
+       if (!strcmp(var, "core.excludesfile")) {
+               if (!value)
+                       die("core.excludesfile without value");
+               excludes_file = xstrdup(value);
+               return 0;
+       }
+
        /* Add other config variables here and to Documentation/config.txt. */
        return 0;
 }
index c148b5ab7d139ea64fa7836f95be542dbbf69a45..c869bb88643d67a7954db026ce9ebb50c0f89be0 100755 (executable)
@@ -1207,6 +1207,15 @@ class P4Sync(Command):
         for branch in lostAndFoundBranches:
             self.knownBranches[branch] = branch
 
+    def getBranchMappingFromGitBranches(self):
+        branches = p4BranchesInGit(self.importIntoRemotes)
+        for branch in branches.keys():
+            if branch == "master":
+                branch = "main"
+            else:
+                branch = branch[len(self.projectName):]
+            self.knownBranches[branch] = branch
+
     def listExistingP4GitBranches(self):
         # branches holds mapping from name to commit
         branches = p4BranchesInGit(self.importIntoRemotes)
@@ -1541,8 +1550,10 @@ class P4Sync(Command):
             ## FIXME - what's a P4 projectName ?
             self.projectName = self.guessProjectName()
 
-            if not self.hasOrigin:
-                self.getBranchMapping();
+            if self.hasOrigin:
+                self.getBranchMappingFromGitBranches()
+            else:
+                self.getBranchMapping()
             if self.verbose:
                 print "p4-git branches: %s" % self.p4BranchesInGit
                 print "initial parents: %s" % self.initialParents
index 3729e73e19e18a78c15fb90dfc28133f541176ef..9728a9954129246b96713d2f3b8dbd52541c416b 100644 (file)
@@ -18,7 +18,8 @@ static void sha1flush(struct sha1file *f, unsigned int count)
        for (;;) {
                int ret = xwrite(f->fd, buf, count);
                if (ret > 0) {
-                       display_throughput(f->tp, ret);
+                       f->total += ret;
+                       display_throughput(f->tp, f->total);
                        buf = (char *) buf + ret;
                        count -= ret;
                        if (count)
@@ -87,21 +88,12 @@ struct sha1file *sha1fd(int fd, const char *name)
 
 struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp)
 {
-       struct sha1file *f;
-       unsigned len;
-
-       f = xmalloc(sizeof(*f));
-
-       len = strlen(name);
-       if (len >= PATH_MAX)
-               die("you wascally wabbit, you");
-       f->namelen = len;
-       memcpy(f->name, name, len+1);
-
+       struct sha1file *f = xmalloc(sizeof(*f));
        f->fd = fd;
-       f->error = 0;
        f->offset = 0;
+       f->total = 0;
        f->tp = tp;
+       f->name = name;
        f->do_crc = 0;
        SHA1_Init(&f->ctx);
        return f;
index 4d1b231292ad4cfc7996b73ea31fa74a5eff2687..1af76562f31da89e4cd2592079edb9c6a45736e3 100644 (file)
@@ -5,11 +5,12 @@ struct progress;
 
 /* A SHA1-protected file */
 struct sha1file {
-       int fd, error;
-       unsigned int offset, namelen;
+       int fd;
+       unsigned int offset;
        SHA_CTX ctx;
+       off_t total;
        struct progress *tp;
-       char name[PATH_MAX];
+       const char *name;
        int do_crc;
        uint32_t crc32;
        unsigned char buffer[8192];
index da5571302df6ed418874fd4d7423853a7de5b52c..f8e936ae1008fdb7ef8e1722afb839d84c724f6c 100644 (file)
@@ -121,7 +121,7 @@ static int queue_diff(struct diff_options *o,
        } else {
                struct diff_filespec *d1, *d2;
 
-               if (o->reverse_diff) {
+               if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
                        unsigned tmp;
                        const char *tmp_c;
                        tmp = mode1; mode1 = mode2; mode2 = tmp;
@@ -173,9 +173,10 @@ static int is_in_index(const char *path)
 }
 
 static int handle_diff_files_args(struct rev_info *revs,
-               int argc, const char **argv, int *silent)
+                                 int argc, const char **argv,
+                                 unsigned int *options)
 {
-       *silent = 0;
+       *options = 0;
 
        /* revs->max_count == -2 means --no-index */
        while (1 < argc && argv[1][0] == '-') {
@@ -188,11 +189,11 @@ static int handle_diff_files_args(struct rev_info *revs,
                else if (!strcmp(argv[1], "-n") ||
                                !strcmp(argv[1], "--no-index")) {
                        revs->max_count = -2;
-                       revs->diffopt.exit_with_status = 1;
-                       revs->diffopt.no_index = 1;
+                       DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
+                       DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
                }
                else if (!strcmp(argv[1], "-q"))
-                       *silent = 1;
+                       *options |= DIFF_SILENT_ON_REMOVED;
                else
                        return error("invalid option: %s", argv[1]);
                argv++; argc--;
@@ -207,7 +208,7 @@ static int handle_diff_files_args(struct rev_info *revs,
                if (!is_in_index(revs->diffopt.paths[0]) ||
                                        !is_in_index(revs->diffopt.paths[1])) {
                        revs->max_count = -2;
-                       revs->diffopt.no_index = 1;
+                       DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
                }
        }
 
@@ -258,7 +259,7 @@ int setup_diff_no_index(struct rev_info *revs,
                        break;
                } else if (i < argc - 3 && !strcmp(argv[i], "--no-index")) {
                        i = argc - 3;
-                       revs->diffopt.exit_with_status = 1;
+                       DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
                        break;
                }
        if (argc != i + 2 || (!is_outside_repo(argv[i + 1], nongit, prefix) &&
@@ -296,7 +297,7 @@ int setup_diff_no_index(struct rev_info *revs,
        else
                revs->diffopt.paths = argv + argc - 2;
        revs->diffopt.nr_paths = 2;
-       revs->diffopt.no_index = 1;
+       DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
        revs->max_count = -2;
        if (diff_setup_done(&revs->diffopt) < 0)
                die("diff_setup_done failed");
@@ -305,12 +306,12 @@ int setup_diff_no_index(struct rev_info *revs,
 
 int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv)
 {
-       int silent_on_removed;
+       unsigned int options;
 
-       if (handle_diff_files_args(revs, argc, argv, &silent_on_removed))
+       if (handle_diff_files_args(revs, argc, argv, &options))
                return -1;
 
-       if (revs->diffopt.no_index) {
+       if (DIFF_OPT_TST(&revs->diffopt, NO_INDEX)) {
                if (revs->diffopt.nr_paths != 2)
                        return error("need two files/directories with --no-index");
                if (queue_diff(&revs->diffopt, revs->diffopt.paths[0],
@@ -329,13 +330,16 @@ int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv)
                perror("read_cache");
                return -1;
        }
-       return run_diff_files(revs, silent_on_removed);
+       return run_diff_files(revs, options);
 }
 
-int run_diff_files(struct rev_info *revs, int silent_on_removed)
+int run_diff_files(struct rev_info *revs, unsigned int option)
 {
        int entries, i;
        int diff_unmerged_stage = revs->max_count;
+       int silent_on_removed = option & DIFF_SILENT_ON_REMOVED;
+       unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
+                             ? CE_MATCH_RACY_IS_DIRTY : 0);
 
        if (diff_unmerged_stage < 0)
                diff_unmerged_stage = 2;
@@ -346,7 +350,8 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
                struct cache_entry *ce = active_cache[i];
                int changed;
 
-               if (revs->diffopt.quiet && revs->diffopt.has_changes)
+               if (DIFF_OPT_TST(&revs->diffopt, QUIET) &&
+                       DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES))
                        break;
 
                if (!ce_path_match(ce, revs->prune_data))
@@ -441,8 +446,8 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
                                       ce->sha1, ce->name, NULL);
                        continue;
                }
-               changed = ce_match_stat(ce, &st, 0);
-               if (!changed && !revs->diffopt.find_copies_harder)
+               changed = ce_match_stat(ce, &st, ce_option);
+               if (!changed && !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
                        continue;
                oldmode = ntohl(ce->ce_mode);
                newmode = ntohl(ce_mode_from_stat(ce, st.st_mode));
@@ -561,7 +566,7 @@ static int show_modified(struct rev_info *revs,
 
        oldmode = old->ce_mode;
        if (mode == oldmode && !hashcmp(sha1, old->sha1) &&
-           !revs->diffopt.find_copies_harder)
+           !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
                return 0;
 
        mode = ntohl(mode);
@@ -581,7 +586,8 @@ static int diff_cache(struct rev_info *revs,
                struct cache_entry *ce = *ac;
                int same = (entries > 1) && ce_same_name(ce, ac[1]);
 
-               if (revs->diffopt.quiet && revs->diffopt.has_changes)
+               if (DIFF_OPT_TST(&revs->diffopt, QUIET) &&
+                       DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES))
                        break;
 
                if (!ce_path_match(ce, pathspec))
diff --git a/diff.c b/diff.c
index a6aaaf7e5a91f3e5ad5f85341429c80a3452504e..b08d28a5780cf242a4de78e0f5c4007b7041f392 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -814,10 +814,10 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
        }
 
        /* Find the longest filename and max number of changes */
-       reset = diff_get_color(options->color_diff, DIFF_RESET);
-       set = diff_get_color(options->color_diff, DIFF_PLAIN);
-       add_c = diff_get_color(options->color_diff, DIFF_FILE_NEW);
-       del_c = diff_get_color(options->color_diff, DIFF_FILE_OLD);
+       reset = diff_get_color_opt(options, DIFF_RESET);
+       set   = diff_get_color_opt(options, DIFF_PLAIN);
+       add_c = diff_get_color_opt(options, DIFF_FILE_NEW);
+       del_c = diff_get_color_opt(options, DIFF_FILE_OLD);
 
        for (i = 0; i < data->nr; i++) {
                struct diffstat_file *file = data->files[i];
@@ -1243,8 +1243,8 @@ static void builtin_diff(const char *name_a,
        mmfile_t mf1, mf2;
        const char *lbl[2];
        char *a_one, *b_two;
-       const char *set = diff_get_color(o->color_diff, DIFF_METAINFO);
-       const char *reset = diff_get_color(o->color_diff, DIFF_RESET);
+       const char *set = diff_get_color_opt(o, DIFF_METAINFO);
+       const char *reset = diff_get_color_opt(o, DIFF_RESET);
 
        a_one = quote_two("a/", name_a + (*name_a == '/'));
        b_two = quote_two("b/", name_b + (*name_b == '/'));
@@ -1277,7 +1277,7 @@ static void builtin_diff(const char *name_a,
                        goto free_ab_and_return;
                if (complete_rewrite) {
                        emit_rewrite_diff(name_a, name_b, one, two,
-                                       o->color_diff);
+                                       DIFF_OPT_TST(o, COLOR_DIFF));
                        o->found_changes = 1;
                        goto free_ab_and_return;
                }
@@ -1286,13 +1286,13 @@ static void builtin_diff(const char *name_a,
        if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
                die("unable to read files to diff");
 
-       if (!o->text &&
+       if (!DIFF_OPT_TST(o, TEXT) &&
            (diff_filespec_is_binary(one) || diff_filespec_is_binary(two))) {
                /* Quite common confusing case */
                if (mf1.size == mf2.size &&
                    !memcmp(mf1.ptr, mf2.ptr, mf1.size))
                        goto free_ab_and_return;
-               if (o->binary)
+               if (DIFF_OPT_TST(o, BINARY))
                        emit_binary_diff(&mf1, &mf2);
                else
                        printf("Binary files %s and %s differ\n",
@@ -1315,7 +1315,7 @@ static void builtin_diff(const char *name_a,
                memset(&xecfg, 0, sizeof(xecfg));
                memset(&ecbdata, 0, sizeof(ecbdata));
                ecbdata.label_path = lbl;
-               ecbdata.color_diff = o->color_diff;
+               ecbdata.color_diff = DIFF_OPT_TST(o, COLOR_DIFF);
                ecbdata.found_changesp = &o->found_changes;
                xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
                xecfg.ctxlen = o->context;
@@ -1331,11 +1331,11 @@ static void builtin_diff(const char *name_a,
                ecb.outf = xdiff_outf;
                ecb.priv = &ecbdata;
                ecbdata.xm.consume = fn_out_consume;
-               if (o->color_diff_words)
+               if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS))
                        ecbdata.diff_words =
                                xcalloc(1, sizeof(struct diff_words_data));
                xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
-               if (o->color_diff_words)
+               if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS))
                        free_diff_words_data(&ecbdata);
        }
 
@@ -1409,7 +1409,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
        data.xm.consume = checkdiff_consume;
        data.filename = name_b ? name_b : name_a;
        data.lineno = 0;
-       data.color_diff = o->color_diff;
+       data.color_diff = DIFF_OPT_TST(o, COLOR_DIFF);
 
        if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
                die("unable to read files to diff");
@@ -1853,7 +1853,7 @@ static void run_diff_cmd(const char *pgm,
                         struct diff_options *o,
                         int complete_rewrite)
 {
-       if (!o->allow_external)
+       if (!DIFF_OPT_TST(o, ALLOW_EXTERNAL))
                pgm = NULL;
        else {
                const char *cmd = external_diff_attr(name);
@@ -1951,9 +1951,9 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o)
        }
 
        if (hashcmp(one->sha1, two->sha1)) {
-               int abbrev = o->full_index ? 40 : DEFAULT_ABBREV;
+               int abbrev = DIFF_OPT_TST(o, FULL_INDEX) ? 40 : DEFAULT_ABBREV;
 
-               if (o->binary) {
+               if (DIFF_OPT_TST(o, BINARY)) {
                        mmfile_t mf;
                        if ((!fill_mmfile(&mf, one) && diff_filespec_is_binary(one)) ||
                            (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two)))
@@ -2045,7 +2045,10 @@ void diff_setup(struct diff_options *options)
 
        options->change = diff_change;
        options->add_remove = diff_addremove;
-       options->color_diff = diff_use_color_default;
+       if (diff_use_color_default)
+               DIFF_OPT_SET(options, COLOR_DIFF);
+       else
+               DIFF_OPT_CLR(options, COLOR_DIFF);
        options->detect_rename = diff_detect_rename_default;
 }
 
@@ -2064,7 +2067,7 @@ int diff_setup_done(struct diff_options *options)
        if (count > 1)
                die("--name-only, --name-status, --check and -s are mutually exclusive");
 
-       if (options->find_copies_harder)
+       if (DIFF_OPT_TST(options, FIND_COPIES_HARDER))
                options->detect_rename = DIFF_DETECT_COPY;
 
        if (options->output_format & (DIFF_FORMAT_NAME |
@@ -2088,12 +2091,12 @@ int diff_setup_done(struct diff_options *options)
                                      DIFF_FORMAT_SHORTSTAT |
                                      DIFF_FORMAT_SUMMARY |
                                      DIFF_FORMAT_CHECKDIFF))
-               options->recursive = 1;
+               DIFF_OPT_SET(options, RECURSIVE);
        /*
         * Also pickaxe would not work very well if you do not say recursive
         */
        if (options->pickaxe)
-               options->recursive = 1;
+               DIFF_OPT_SET(options, RECURSIVE);
 
        if (options->detect_rename && options->rename_limit < 0)
                options->rename_limit = diff_rename_limit_default;
@@ -2115,9 +2118,9 @@ int diff_setup_done(struct diff_options *options)
         * to have found.  It does not make sense not to return with
         * exit code in such a case either.
         */
-       if (options->quiet) {
+       if (DIFF_OPT_TST(options, QUIET)) {
                options->output_format = DIFF_FORMAT_NO_OUTPUT;
-               options->exit_with_status = 1;
+               DIFF_OPT_SET(options, EXIT_WITH_STATUS);
        }
 
        /*
@@ -2125,7 +2128,7 @@ int diff_setup_done(struct diff_options *options)
         * upon the first hit.  We need to run diff as usual.
         */
        if (options->pickaxe || options->filter)
-               options->quiet = 0;
+               DIFF_OPT_CLR(options, QUIET);
 
        return 0;
 }
@@ -2182,21 +2185,32 @@ static int diff_scoreopt_parse(const char *opt);
 int diff_opt_parse(struct diff_options *options, const char **av, int ac)
 {
        const char *arg = av[0];
+
+       /* Output format options */
        if (!strcmp(arg, "-p") || !strcmp(arg, "-u"))
                options->output_format |= DIFF_FORMAT_PATCH;
        else if (opt_arg(arg, 'U', "unified", &options->context))
                options->output_format |= DIFF_FORMAT_PATCH;
        else if (!strcmp(arg, "--raw"))
                options->output_format |= DIFF_FORMAT_RAW;
-       else if (!strcmp(arg, "--patch-with-raw")) {
+       else if (!strcmp(arg, "--patch-with-raw"))
                options->output_format |= DIFF_FORMAT_PATCH | DIFF_FORMAT_RAW;
-       }
-       else if (!strcmp(arg, "--numstat")) {
+       else if (!strcmp(arg, "--numstat"))
                options->output_format |= DIFF_FORMAT_NUMSTAT;
-       }
-       else if (!strcmp(arg, "--shortstat")) {
+       else if (!strcmp(arg, "--shortstat"))
                options->output_format |= DIFF_FORMAT_SHORTSTAT;
-       }
+       else if (!strcmp(arg, "--check"))
+               options->output_format |= DIFF_FORMAT_CHECKDIFF;
+       else if (!strcmp(arg, "--summary"))
+               options->output_format |= DIFF_FORMAT_SUMMARY;
+       else if (!strcmp(arg, "--patch-with-stat"))
+               options->output_format |= DIFF_FORMAT_PATCH | DIFF_FORMAT_DIFFSTAT;
+       else if (!strcmp(arg, "--name-only"))
+               options->output_format |= DIFF_FORMAT_NAME;
+       else if (!strcmp(arg, "--name-status"))
+               options->output_format |= DIFF_FORMAT_NAME_STATUS;
+       else if (!strcmp(arg, "-s"))
+               options->output_format |= DIFF_FORMAT_NO_OUTPUT;
        else if (!prefixcmp(arg, "--stat")) {
                char *end;
                int width = options->stat_width;
@@ -2224,99 +2238,89 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                options->stat_name_width = name_width;
                options->stat_width = width;
        }
-       else if (!strcmp(arg, "--check"))
-               options->output_format |= DIFF_FORMAT_CHECKDIFF;
-       else if (!strcmp(arg, "--summary"))
-               options->output_format |= DIFF_FORMAT_SUMMARY;
-       else if (!strcmp(arg, "--patch-with-stat")) {
-               options->output_format |= DIFF_FORMAT_PATCH | DIFF_FORMAT_DIFFSTAT;
-       }
-       else if (!strcmp(arg, "-z"))
-               options->line_termination = 0;
-       else if (!prefixcmp(arg, "-l"))
-               options->rename_limit = strtoul(arg+2, NULL, 10);
-       else if (!strcmp(arg, "--full-index"))
-               options->full_index = 1;
-       else if (!strcmp(arg, "--binary")) {
-               options->output_format |= DIFF_FORMAT_PATCH;
-               options->binary = 1;
-       }
-       else if (!strcmp(arg, "-a") || !strcmp(arg, "--text")) {
-               options->text = 1;
-       }
-       else if (!strcmp(arg, "--name-only"))
-               options->output_format |= DIFF_FORMAT_NAME;
-       else if (!strcmp(arg, "--name-status"))
-               options->output_format |= DIFF_FORMAT_NAME_STATUS;
-       else if (!strcmp(arg, "-R"))
-               options->reverse_diff = 1;
-       else if (!prefixcmp(arg, "-S"))
-               options->pickaxe = arg + 2;
-       else if (!strcmp(arg, "-s")) {
-               options->output_format |= DIFF_FORMAT_NO_OUTPUT;
-       }
-       else if (!prefixcmp(arg, "-O"))
-               options->orderfile = arg + 2;
-       else if (!prefixcmp(arg, "--diff-filter="))
-               options->filter = arg + 14;
-       else if (!strcmp(arg, "--pickaxe-all"))
-               options->pickaxe_opts = DIFF_PICKAXE_ALL;
-       else if (!strcmp(arg, "--pickaxe-regex"))
-               options->pickaxe_opts = DIFF_PICKAXE_REGEX;
+
+       /* renames options */
        else if (!prefixcmp(arg, "-B")) {
-               if ((options->break_opt =
-                    diff_scoreopt_parse(arg)) == -1)
+               if ((options->break_opt = diff_scoreopt_parse(arg)) == -1)
                        return -1;
        }
        else if (!prefixcmp(arg, "-M")) {
-               if ((options->rename_score =
-                    diff_scoreopt_parse(arg)) == -1)
+               if ((options->rename_score = diff_scoreopt_parse(arg)) == -1)
                        return -1;
                options->detect_rename = DIFF_DETECT_RENAME;
        }
        else if (!prefixcmp(arg, "-C")) {
                if (options->detect_rename == DIFF_DETECT_COPY)
-                       options->find_copies_harder = 1;
-               if ((options->rename_score =
-                    diff_scoreopt_parse(arg)) == -1)
+                       DIFF_OPT_SET(options, FIND_COPIES_HARDER);
+               if ((options->rename_score = diff_scoreopt_parse(arg)) == -1)
                        return -1;
                options->detect_rename = DIFF_DETECT_COPY;
        }
-       else if (!strcmp(arg, "--find-copies-harder"))
-               options->find_copies_harder = 1;
-       else if (!strcmp(arg, "--follow"))
-               options->follow_renames = 1;
-       else if (!strcmp(arg, "--abbrev"))
-               options->abbrev = DEFAULT_ABBREV;
-       else if (!prefixcmp(arg, "--abbrev=")) {
-               options->abbrev = strtoul(arg + 9, NULL, 10);
-               if (options->abbrev < MINIMUM_ABBREV)
-                       options->abbrev = MINIMUM_ABBREV;
-               else if (40 < options->abbrev)
-                       options->abbrev = 40;
-       }
-       else if (!strcmp(arg, "--color"))
-               options->color_diff = 1;
-       else if (!strcmp(arg, "--no-color"))
-               options->color_diff = 0;
+       else if (!strcmp(arg, "--no-renames"))
+               options->detect_rename = 0;
+
+       /* xdiff options */
        else if (!strcmp(arg, "-w") || !strcmp(arg, "--ignore-all-space"))
                options->xdl_opts |= XDF_IGNORE_WHITESPACE;
        else if (!strcmp(arg, "-b") || !strcmp(arg, "--ignore-space-change"))
                options->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE;
        else if (!strcmp(arg, "--ignore-space-at-eol"))
                options->xdl_opts |= XDF_IGNORE_WHITESPACE_AT_EOL;
+
+       /* flags options */
+       else if (!strcmp(arg, "--binary")) {
+               options->output_format |= DIFF_FORMAT_PATCH;
+               DIFF_OPT_SET(options, BINARY);
+       }
+       else if (!strcmp(arg, "--full-index"))
+               DIFF_OPT_SET(options, FULL_INDEX);
+       else if (!strcmp(arg, "-a") || !strcmp(arg, "--text"))
+               DIFF_OPT_SET(options, TEXT);
+       else if (!strcmp(arg, "-R"))
+               DIFF_OPT_SET(options, REVERSE_DIFF);
+       else if (!strcmp(arg, "--find-copies-harder"))
+               DIFF_OPT_SET(options, FIND_COPIES_HARDER);
+       else if (!strcmp(arg, "--follow"))
+               DIFF_OPT_SET(options, FOLLOW_RENAMES);
+       else if (!strcmp(arg, "--color"))
+               DIFF_OPT_SET(options, COLOR_DIFF);
+       else if (!strcmp(arg, "--no-color"))
+               DIFF_OPT_CLR(options, COLOR_DIFF);
        else if (!strcmp(arg, "--color-words"))
-               options->color_diff = options->color_diff_words = 1;
-       else if (!strcmp(arg, "--no-renames"))
-               options->detect_rename = 0;
+               options->flags |= DIFF_OPT_COLOR_DIFF | DIFF_OPT_COLOR_DIFF_WORDS;
        else if (!strcmp(arg, "--exit-code"))
-               options->exit_with_status = 1;
+               DIFF_OPT_SET(options, EXIT_WITH_STATUS);
        else if (!strcmp(arg, "--quiet"))
-               options->quiet = 1;
+               DIFF_OPT_SET(options, QUIET);
        else if (!strcmp(arg, "--ext-diff"))
-               options->allow_external = 1;
+               DIFF_OPT_SET(options, ALLOW_EXTERNAL);
        else if (!strcmp(arg, "--no-ext-diff"))
-               options->allow_external = 0;
+               DIFF_OPT_CLR(options, ALLOW_EXTERNAL);
+
+       /* misc options */
+       else if (!strcmp(arg, "-z"))
+               options->line_termination = 0;
+       else if (!prefixcmp(arg, "-l"))
+               options->rename_limit = strtoul(arg+2, NULL, 10);
+       else if (!prefixcmp(arg, "-S"))
+               options->pickaxe = arg + 2;
+       else if (!strcmp(arg, "--pickaxe-all"))
+               options->pickaxe_opts = DIFF_PICKAXE_ALL;
+       else if (!strcmp(arg, "--pickaxe-regex"))
+               options->pickaxe_opts = DIFF_PICKAXE_REGEX;
+       else if (!prefixcmp(arg, "-O"))
+               options->orderfile = arg + 2;
+       else if (!prefixcmp(arg, "--diff-filter="))
+               options->filter = arg + 14;
+       else if (!strcmp(arg, "--abbrev"))
+               options->abbrev = DEFAULT_ABBREV;
+       else if (!prefixcmp(arg, "--abbrev=")) {
+               options->abbrev = strtoul(arg + 9, NULL, 10);
+               if (options->abbrev < MINIMUM_ABBREV)
+                       options->abbrev = MINIMUM_ABBREV;
+               else if (40 < options->abbrev)
+                       options->abbrev = 40;
+       }
        else
                return 0;
        return 1;
@@ -3071,7 +3075,7 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
                         * to determine how many paths were dirty only
                         * due to stat info mismatch.
                         */
-                       if (!diffopt->no_index)
+                       if (!DIFF_OPT_TST(diffopt, NO_INDEX))
                                diffopt->skip_stat_unmatch++;
                        diff_free_filepair(p);
                }
@@ -3082,10 +3086,10 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
 
 void diffcore_std(struct diff_options *options)
 {
-       if (options->quiet)
+       if (DIFF_OPT_TST(options, QUIET))
                return;
 
-       if (options->skip_stat_unmatch && !options->find_copies_harder)
+       if (options->skip_stat_unmatch && !DIFF_OPT_TST(options, FIND_COPIES_HARDER))
                diffcore_skip_stat_unmatch(options);
        if (options->break_opt != -1)
                diffcore_break(options->break_opt);
@@ -3100,7 +3104,10 @@ void diffcore_std(struct diff_options *options)
        diff_resolve_rename_copy();
        diffcore_apply_filter(options->filter);
 
-       options->has_changes = !!diff_queued_diff.nr;
+       if (diff_queued_diff.nr)
+               DIFF_OPT_SET(options, HAS_CHANGES);
+       else
+               DIFF_OPT_CLR(options, HAS_CHANGES);
 }
 
 
@@ -3124,7 +3131,7 @@ void diff_addremove(struct diff_options *options,
         * Before the final output happens, they are pruned after
         * merged into rename/copy pairs as appropriate.
         */
-       if (options->reverse_diff)
+       if (DIFF_OPT_TST(options, REVERSE_DIFF))
                addremove = (addremove == '+' ? '-' :
                             addremove == '-' ? '+' : addremove);
 
@@ -3139,7 +3146,7 @@ void diff_addremove(struct diff_options *options,
                fill_filespec(two, sha1, mode);
 
        diff_queue(&diff_queued_diff, one, two);
-       options->has_changes = 1;
+       DIFF_OPT_SET(options, HAS_CHANGES);
 }
 
 void diff_change(struct diff_options *options,
@@ -3151,7 +3158,7 @@ void diff_change(struct diff_options *options,
        char concatpath[PATH_MAX];
        struct diff_filespec *one, *two;
 
-       if (options->reverse_diff) {
+       if (DIFF_OPT_TST(options, REVERSE_DIFF)) {
                unsigned tmp;
                const unsigned char *tmp_c;
                tmp = old_mode; old_mode = new_mode; new_mode = tmp;
@@ -3165,7 +3172,7 @@ void diff_change(struct diff_options *options,
        fill_filespec(two, new_sha1, new_mode);
 
        diff_queue(&diff_queued_diff, one, two);
-       options->has_changes = 1;
+       DIFF_OPT_SET(options, HAS_CHANGES);
 }
 
 void diff_unmerge(struct diff_options *options,
diff --git a/diff.h b/diff.h
index 4546aad219742e4ad878937dbd05436c93d298b9..a52496a1086ccbe8ea90acd6800dd355b1d7ff68 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -43,26 +43,32 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
 
 #define DIFF_FORMAT_CALLBACK   0x1000
 
+#define DIFF_OPT_RECURSIVE           (1 <<  0)
+#define DIFF_OPT_TREE_IN_RECURSIVE   (1 <<  1)
+#define DIFF_OPT_BINARY              (1 <<  2)
+#define DIFF_OPT_TEXT                (1 <<  3)
+#define DIFF_OPT_FULL_INDEX          (1 <<  4)
+#define DIFF_OPT_SILENT_ON_REMOVE    (1 <<  5)
+#define DIFF_OPT_FIND_COPIES_HARDER  (1 <<  6)
+#define DIFF_OPT_FOLLOW_RENAMES      (1 <<  7)
+#define DIFF_OPT_COLOR_DIFF          (1 <<  8)
+#define DIFF_OPT_COLOR_DIFF_WORDS    (1 <<  9)
+#define DIFF_OPT_HAS_CHANGES         (1 << 10)
+#define DIFF_OPT_QUIET               (1 << 11)
+#define DIFF_OPT_NO_INDEX            (1 << 12)
+#define DIFF_OPT_ALLOW_EXTERNAL      (1 << 13)
+#define DIFF_OPT_EXIT_WITH_STATUS    (1 << 14)
+#define DIFF_OPT_REVERSE_DIFF        (1 << 15)
+#define DIFF_OPT_TST(opts, flag)    ((opts)->flags & DIFF_OPT_##flag)
+#define DIFF_OPT_SET(opts, flag)    ((opts)->flags |= DIFF_OPT_##flag)
+#define DIFF_OPT_CLR(opts, flag)    ((opts)->flags &= ~DIFF_OPT_##flag)
+
 struct diff_options {
        const char *filter;
        const char *orderfile;
        const char *pickaxe;
        const char *single_follow;
-       unsigned recursive:1,
-                tree_in_recursive:1,
-                binary:1,
-                text:1,
-                full_index:1,
-                silent_on_remove:1,
-                find_copies_harder:1,
-                follow_renames:1,
-                color_diff:1,
-                color_diff_words:1,
-                has_changes:1,
-                quiet:1,
-                no_index:1,
-                allow_external:1,
-                exit_with_status:1;
+       unsigned flags;
        int context;
        int break_opt;
        int detect_rename;
@@ -71,7 +77,6 @@ struct diff_options {
        int output_format;
        int pickaxe_opts;
        int rename_score;
-       int reverse_diff;
        int rename_limit;
        int setup;
        int abbrev;
@@ -105,6 +110,9 @@ enum color_diff {
        DIFF_WHITESPACE = 7,
 };
 const char *diff_get_color(int diff_use_color, enum color_diff ix);
+#define diff_get_color_opt(o, ix) \
+       diff_get_color(DIFF_OPT_TST((o), COLOR_DIFF), ix)
+
 
 extern const char mime_boundary_leader[];
 
@@ -224,7 +232,11 @@ extern void diff_flush(struct diff_options*);
 
 extern const char *diff_unique_abbrev(const unsigned char *, int);
 
-extern int run_diff_files(struct rev_info *revs, int silent_on_removed);
+/* do not report anything on removed paths */
+#define DIFF_SILENT_ON_REMOVED 01
+/* report racily-clean paths as modified */
+#define DIFF_RACY_IS_MODIFIED 02
+extern int run_diff_files(struct rev_info *revs, unsigned int option);
 extern int setup_diff_no_index(struct rev_info *revs,
                int argc, const char ** argv, int nongit, const char *prefix);
 extern int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv);
diff --git a/dir.c b/dir.c
index 01790ab27d25f63ea9f0816668a822d8f059664a..225fdfb52c432b7af1af1cdf9aa9a31f8022e3ec 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -654,6 +654,7 @@ static void free_simplify(struct path_simplify *simplify)
 int read_directory(struct dir_struct *dir, const char *path, const char *base, int baselen, const char **pathspec)
 {
        struct path_simplify *simplify = create_simplify(pathspec);
+       char *pp = NULL;
 
        /*
         * Make sure to do the per-directory exclude for all the
@@ -661,7 +662,8 @@ int read_directory(struct dir_struct *dir, const char *path, const char *base, i
         */
        if (baselen) {
                if (dir->exclude_per_dir) {
-                       char *p, *pp = xmalloc(baselen+1);
+                       char *p;
+                       pp = xmalloc(baselen+1);
                        memcpy(pp, base, baselen+1);
                        p = pp;
                        while (1) {
@@ -677,12 +679,12 @@ int read_directory(struct dir_struct *dir, const char *path, const char *base, i
                                else
                                        p = pp + baselen;
                        }
-                       free(pp);
                }
        }
 
        read_directory_recursive(dir, path, base, baselen, 0, simplify);
        free_simplify(simplify);
+       free(pp);
        qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);
        qsort(dir->ignored, dir->ignored_nr, sizeof(struct dir_entry *), cmp_name);
        return dir->nr;
@@ -778,3 +780,15 @@ int remove_dir_recursively(struct strbuf *path, int only_empty)
                ret = rmdir(path->buf);
        return ret;
 }
+
+void setup_standard_excludes(struct dir_struct *dir)
+{
+       const char *path;
+
+       dir->exclude_per_dir = ".gitignore";
+       path = git_path("info/exclude");
+       if (!access(path, R_OK))
+               add_excludes_from_file(dir, path);
+       if (excludes_file && !access(excludes_file, R_OK))
+               add_excludes_from_file(dir, excludes_file);
+}
diff --git a/dir.h b/dir.h
index aaa247b2569fc5ae923f12dcd3cdede5c2dccd8d..82009dc13e4b685bc6f4f6e9206d621c7d361c65 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -71,6 +71,7 @@ extern struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathna
 extern char *get_relative_cwd(char *buffer, int size, const char *dir);
 extern int is_inside_dir(const char *dir);
 
+extern void setup_standard_excludes(struct dir_struct *dir);
 extern int remove_dir_recursively(struct strbuf *path, int only_empty);
 
 #endif
diff --git a/entry.c b/entry.c
index cfadc6a292033d349f6b1efff75d2c4f9f2525fe..257ab46e943f1f8b7445f01c10d949224c17112f 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -203,7 +203,7 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
        strcpy(path + len, ce->name);
 
        if (!lstat(path, &st)) {
-               unsigned changed = ce_match_stat(ce, &st, 1);
+               unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID);
                if (!changed)
                        return 0;
                if (!state->force) {
index b5a6c69f7c1d214daa2556d04dd35e0976fc6e5e..1dab72ec1525ca6dd15ca20666cd91506b85890c 100644 (file)
@@ -34,6 +34,7 @@ char *pager_program;
 int pager_in_use;
 int pager_use_color = 1;
 char *editor_program;
+char *excludes_file;
 int auto_crlf = 0;     /* 1: both ways, -1: only when adding git objects */
 
 /* This is set by setup_git_dir_gently() and/or git_default_config() */
index ac598f88e62fc8f48aaaac8376ccde63cb3e2643..0317ad9127b374a9ded536e6fb2c825a3b13828c 100755 (executable)
@@ -37,10 +37,7 @@ sub list_untracked {
                chomp $_;
                $_;
        }
-       run_cmd_pipe(qw(git ls-files --others
-                       --exclude-per-directory=.gitignore),
-                    "--exclude-from=$GIT_DIR/info/exclude",
-                    '--', @_);
+       run_cmd_pipe(qw(git ls-files --others --exclude-standard --), @_);
 }
 
 my $status_fmt = '%12s %12s %s';
index 2514d07de2ea89598499a35e3e4a2fcc9096bbec..4126f0e857bad273d6f44cabe34565de860bd119 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -2,11 +2,26 @@
 #
 # Copyright (c) 2005, 2006 Junio C Hamano
 
-USAGE='[--signoff] [--dotest=<dir>] [--keep] [--utf8 | --no-utf8]
-  [--3way] [--interactive] [--binary]
-  [--whitespace=<option>] [-C<n>] [-p<n>]
-  <mbox>|<Maildir>...
-  or, when resuming [--skip | --resolved]'
+OPTIONS_KEEPDASHDASH=
+OPTIONS_SPEC="\
+git-am [options] <mbox>|<Maildir>...
+git-am [options] --resolved
+git-am [options] --skip
+--
+d,dotest=       use <dir> and not .dotest
+i,interactive   run interactively
+b,binary        pass --allo-binary-replacement to git-apply
+3,3way          allow fall back on 3way merging if needed
+s,signoff       add a Signed-off-by line to the commit message
+u,utf8          recode into utf8 (default)
+k,keep          pass -k flagg to git-mailinfo
+whitespace=     pass it through git-apply
+C=              pass it through git-apply
+p=              pass it through git-apply
+resolvemsg=     override error message when patch failure occurs
+r,resolved      to be used after a patch failure
+skip            skip the current patch"
+
 . git-sh-setup
 set_reflog_action am
 require_work_tree
@@ -110,49 +125,38 @@ git_apply_opt=
 while test $# != 0
 do
        case "$1" in
-       -d=*|--d=*|--do=*|--dot=*|--dote=*|--dotes=*|--dotest=*)
-       dotest=`expr "z$1" : 'z-[^=]*=\(.*\)'`; shift ;;
-       -d|--d|--do|--dot|--dote|--dotes|--dotest)
-       case "$#" in 1) usage ;; esac; shift
-       dotest="$1"; shift;;
-
-       -i|--i|--in|--int|--inte|--inter|--intera|--interac|--interact|\
-       --interacti|--interactiv|--interactive)
-       interactive=t; shift ;;
-
-       -b|--b|--bi|--bin|--bina|--binar|--binary)
-       binary=t; shift ;;
-
-       -3|--3|--3w|--3wa|--3way)
-       threeway=t; shift ;;
-       -s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
-       sign=t; shift ;;
-       -u|--u|--ut|--utf|--utf8)
-       utf8=t; shift ;; # this is now default
-       --no-u|--no-ut|--no-utf|--no-utf8)
-       utf8=; shift ;;
-       -k|--k|--ke|--kee|--keep)
-       keep=t; shift ;;
-
-       -r|--r|--re|--res|--reso|--resol|--resolv|--resolve|--resolved)
-       resolved=t; shift ;;
-
-       --sk|--ski|--skip)
-       skip=t; shift ;;
-
-       --whitespace=*|-C*|-p*)
-       git_apply_opt="$git_apply_opt $1"; shift ;;
-
-       --resolvemsg=*)
-       resolvemsg=${1#--resolvemsg=}; shift ;;
-
+       -i|--interactive)
+               interactive=t ;;
+       -b|--binary)
+               binary=t ;;
+       -3|--3way)
+               threeway=t ;;
+       -s|--signoff)
+               sign=t ;;
+       -u|--utf8)
+               utf8=t ;; # this is now default
+       --no-utf8)
+               utf8= ;;
+       -k|--keep)
+               keep=t ;;
+       -r|--resolved)
+               resolved=t ;;
+       --skip)
+               skip=t ;;
+       -d|--dotest)
+               shift; dotest=$1;;
+       --resolvemsg)
+               shift; resolvemsg=$1 ;;
+       --whitespace)
+               git_apply_opt="$git_apply_opt $1=$2"; shift ;;
+       -C|-p)
+               git_apply_opt="$git_apply_opt $1$2"; shift ;;
        --)
-       shift; break ;;
-       -*)
-       usage ;;
+               shift; break ;;
        *)
-       break ;;
+               usage ;;
        esac
+       shift
 done
 
 # If the dotest directory exists, but we have finished applying all the
index 1ed44e56ad5021a74b2a0ec3e91849e55d4a67ce..3aac8164c62c1f4af8df76832322df9f25a05b38 100755 (executable)
@@ -22,6 +22,7 @@ git bisect log
 git bisect run <cmd>...
         use <cmd>... to automatically bisect.'
 
+OPTIONS_SPEC=
 . git-sh-setup
 require_work_tree
 
index 89939206732849e968fabaf9128597c87f18f5c7..aa724ac1a3859791187d257da6445d2b4adc1de8 100755 (executable)
@@ -1,6 +1,16 @@
 #!/bin/sh
 
-USAGE='[-q] [-f] [-b <new_branch>] [-m] [<branch>] [<paths>...]'
+OPTIONS_KEEPDASHDASH=t
+OPTIONS_SPEC="\
+git-branch [options] [<branch>] [<paths>...]
+--
+b=          create a new branch started at <branch>
+l           create the new branchs reflog
+track       tells if the new branch should track the remote branch
+f           proceed even if the index or working tree is not HEAD
+m           performa  three-way merge on local modifications if needed
+q,quiet     be quiet
+"
 SUBDIRECTORY_OK=Sometimes
 . git-sh-setup
 require_work_tree
@@ -20,13 +30,12 @@ quiet=
 v=-v
 LF='
 '
-while [ "$#" != "0" ]; do
-    arg="$1"
-    shift
-    case "$arg" in
-       "-b")
-               newbranch="$1"
+
+while test $# != 0; do
+       case "$1" in
+       -b)
                shift
+               newbranch="$1"
                [ -z "$newbranch" ] &&
                        die "git checkout: -b needs a branch name"
                git show-ref --verify --quiet -- "refs/heads/$newbranch" &&
@@ -34,64 +43,54 @@ while [ "$#" != "0" ]; do
                git check-ref-format "heads/$newbranch" ||
                        die "git checkout: we do not like '$newbranch' as a branch name."
                ;;
-       "-l")
+       -l)
                newbranch_log=-l
                ;;
-       "--track"|"--no-track")
-               track="$arg"
+       --track|--no-track)
+               track="$1"
                ;;
-       "-f")
+       -f)
                force=1
                ;;
        -m)
                merge=1
                ;;
-       "-q")
+       -q|--quiet)
                quiet=1
                v=
                ;;
        --)
+               shift
                break
                ;;
-       -*)
-               usage
-               ;;
        *)
-               if rev=$(git rev-parse --verify "$arg^0" 2>/dev/null)
-               then
-                       if [ -z "$rev" ]; then
-                               echo "unknown flag $arg"
-                               exit 1
-                       fi
-                       new_name="$arg"
-                       if git show-ref --verify --quiet -- "refs/heads/$arg"
-                       then
-                               rev=$(git rev-parse --verify "refs/heads/$arg^0")
-                               branch="$arg"
-                       fi
-                       new="$rev"
-               elif rev=$(git rev-parse --verify "$arg^{tree}" 2>/dev/null)
-               then
-                       # checking out selected paths from a tree-ish.
-                       new="$rev"
-                       new_name="$arg^{tree}"
-                       branch=
-               else
-                       new=
-                       new_name=
-                       branch=
-                       set x "$arg" "$@"
-                       shift
-               fi
-               case "$1" in
-               --)
-                       shift ;;
-               esac
-               break
+               usage
                ;;
-    esac
+       esac
+       shift
 done
 
+arg="$1"
+if rev=$(git rev-parse --verify "$arg^0" 2>/dev/null)
+then
+       [ -z "$rev" ] && die "unknown flag $arg"
+       new_name="$arg"
+       if git show-ref --verify --quiet -- "refs/heads/$arg"
+       then
+               rev=$(git rev-parse --verify "refs/heads/$arg^0")
+               branch="$arg"
+       fi
+       new="$rev"
+       shift
+elif rev=$(git rev-parse --verify "$arg^{tree}" 2>/dev/null)
+then
+       # checking out selected paths from a tree-ish.
+       new="$rev"
+       new_name="$arg^{tree}"
+       shift
+fi
+[ "$1" = "--" ] && shift
+
 case "$newbranch,$track" in
 ,--*)
        die "git checkout: --track and --no-track require -b"
@@ -134,12 +133,12 @@ Did you intend to checkout '$@' which can not be resolved as commit?"
        fi
 
        # Make sure the request is about existing paths.
-       git ls-files --error-unmatch -- "$@" >/dev/null || exit
-       git ls-files -- "$@" |
-       git checkout-index -f -u --stdin
+       git ls-files --full-name --error-unmatch -- "$@" >/dev/null || exit
+       git ls-files --full-name -- "$@" |
+               (cd_to_toplevel && git checkout-index -f -u --stdin)
 
-        # Run a post-checkout hook -- the HEAD does not change so the
-        # current HEAD is passed in for both args
+       # Run a post-checkout hook -- the HEAD does not change so the
+       # current HEAD is passed in for both args
        if test -x "$GIT_DIR"/hooks/post-checkout; then
            "$GIT_DIR"/hooks/post-checkout $old $old 0
        fi
@@ -294,5 +293,5 @@ fi
 
 # Run a post-checkout hook
 if test -x "$GIT_DIR"/hooks/post-checkout; then
-        "$GIT_DIR"/hooks/post-checkout $old $new 1
+       "$GIT_DIR"/hooks/post-checkout $old $new 1
 fi
index ad68595fbf313c1cab7de565e6d44f2c87aff384..01c95e9fe8a19afcf331ed5ffd47eea478886213 100755 (executable)
@@ -3,16 +3,22 @@
 # Copyright (c) 2005-2006 Pavel Roskin
 #
 
-USAGE="[-d] [-f] [-n] [-q] [-x | -X] [--] <paths>..."
-LONG_USAGE='Clean untracked files from the working directory
-       -d      remove directories as well
-       -f      override clean.requireForce and clean anyway
-       -n      don'\''t remove anything, just show what would be done
-       -q      be quiet, only report errors
-       -x      remove ignored files as well
-       -X      remove only ignored files
+OPTIONS_KEEPDASHDASH=
+OPTIONS_SPEC="\
+git-clean [options] <paths>...
+
+Clean untracked files from the working directory
+
 When optional <paths>... arguments are given, the paths
-affected are further limited to those that match them.'
+affected are further limited to those that match them.
+--
+d remove directories as well
+f override clean.requireForce and clean anyway
+n don't remove anything, just show what would be done
+q be quiet, only report errors
+x remove ignored files as well
+X remove only ignored files"
+
 SUBDIRECTORY_OK=Yes
 . git-sh-setup
 require_work_tree
@@ -56,11 +62,9 @@ do
                shift
                break
                ;;
-       -*)
-               usage
-               ;;
        *)
-               break
+               usage # should not happen
+               ;;
        esac
        shift
 done
@@ -77,9 +81,9 @@ case "$disabled" in
        ;;
 esac
 
-case "$ignored,$ignoredonly" in
-       1,1) usage;;
-esac
+if [ "$ignored,$ignoredonly" = "1,1" ]; then
+       die "-x and -X cannot be set together"
+fi
 
 if [ -z "$ignored" ]; then
        excl="--exclude-per-directory=.gitignore"
index 3f006936085cedcdca436455643b05d2198e3606..24ad179bbda69ecf68e49896c3c018425b645461 100755 (executable)
@@ -8,15 +8,36 @@
 # See git-sh-setup why.
 unset CDPATH
 
+OPTIONS_SPEC="\
+git-clone [options] [--] <repo> [<dir>]
+--
+n,no-checkout        don't create a checkout
+bare                 create a bare repository
+naked                create a bare repository
+l,local              to clone from a local repository
+no-hardlinks         don't use local hardlinks, always copy
+s,shared             setup as a shared repository
+template=            path to the template directory
+q,quiet              be quiet
+reference=           reference repository
+o,origin=            use <name> instead of 'origin' to track upstream
+u,upload-pack=       path to git-upload-pack on the remote
+depth=               create a shallow clone of that depth
+
+use-separate-remote  compatibility, do not use
+no-separate-remote   compatibility, do not use"
+
 die() {
        echo >&2 "$@"
        exit 1
 }
 
 usage() {
-       die "Usage: $0 [--template=<template_directory>] [--reference <reference-repo>] [--bare] [-l [-s]] [-q] [-u <upload-pack>] [--origin <name>] [--depth <n>] [-n] [--] <repo> [<dir>]"
+       exec "$0" -h
 }
 
+eval "$(echo "$OPTIONS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
+
 get_repo_base() {
        (
                cd "`/bin/pwd`" &&
@@ -106,67 +127,57 @@ depth=
 no_progress=
 local_explicitly_asked_for=
 test -t 1 || no_progress=--no-progress
-while
-       case "$#,$1" in
-       0,*) break ;;
-       *,-n|*,--no|*,--no-|*,--no-c|*,--no-ch|*,--no-che|*,--no-chec|\
-       *,--no-check|*,--no-checko|*,--no-checkou|*,--no-checkout)
-         no_checkout=yes ;;
-       *,--na|*,--nak|*,--nake|*,--naked|\
-       *,-b|*,--b|*,--ba|*,--bar|*,--bare) bare=yes ;;
-       *,-l|*,--l|*,--lo|*,--loc|*,--loca|*,--local)
-         local_explicitly_asked_for=yes
-         use_local_hardlink=yes ;;
-       *,--no-h|*,--no-ha|*,--no-har|*,--no-hard|*,--no-hardl|\
-       *,--no-hardli|*,--no-hardlin|*,--no-hardlink|*,--no-hardlinks)
-         use_local_hardlink=no ;;
-        *,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared)
-          local_shared=yes; ;;
-       1,--template) usage ;;
-       *,--template)
+
+while test $# != 0
+do
+       case "$1" in
+       -n|--no-checkout)
+               no_checkout=yes ;;
+       --naked|--bare)
+               bare=yes ;;
+       -l|--local)
+               local_explicitly_asked_for=yes
+               use_local_hardlink=yes
+               ;;
+       --no-hardlinks)
+               use_local_hardlink=no ;;
+       -s|--shared)
+               local_shared=yes ;;
+       --template)
                shift; template="--template=$1" ;;
-       *,--template=*)
-         template="$1" ;;
-       *,-q|*,--quiet) quiet=-q ;;
-       *,--use-separate-remote) ;;
-       *,--no-separate-remote)
+       -q|--quiet)
+               quiet=-q ;;
+       --use-separate-remote|--no-separate-remote)
                die "clones are always made with separate-remote layout" ;;
-       1,--reference) usage ;;
-       *,--reference)
+       --reference)
                shift; reference="$1" ;;
-       *,--reference=*)
-               reference=`expr "z$1" : 'z--reference=\(.*\)'` ;;
-       *,-o|*,--or|*,--ori|*,--orig|*,--origi|*,--origin)
-               case "$2" in
+       -o,--origin)
+               shift;
+               case "$1" in
                '')
                    usage ;;
                */*)
-                   die "'$2' is not suitable for an origin name"
+                   die "'$1' is not suitable for an origin name"
                esac
-               git check-ref-format "heads/$2" ||
-                   die "'$2' is not suitable for a branch name"
+               git check-ref-format "heads/$1" ||
+                   die "'$1' is not suitable for a branch name"
                test -z "$origin_override" ||
                    die "Do not give more than one --origin options."
                origin_override=yes
-               origin="$2"; shift
+               origin="$1"
                ;;
-       1,-u|1,--upload-pack) usage ;;
-       *,-u|*,--upload-pack)
+       -u|--upload-pack)
                shift
                upload_pack="--upload-pack=$1" ;;
-       *,--upload-pack=*)
-               upload_pack=--upload-pack=$(expr "z$1" : 'z-[^=]*=\(.*\)') ;;
-       1,--depth) usage;;
-       *,--depth)
+       --depth)
                shift
-               depth="--depth=$1";;
-       *,--)
+               depth="--depth=$1" ;;
+       --)
                shift
                break ;;
-       *,-*) usage ;;
-       *) break ;;
+       *)
+               usage ;;
        esac
-do
        shift
 done
 
index fcb8443bdfa2a87a436ae79471d91c89e944fffd..485339754ca3567c86b824af656700654c68e173 100755 (executable)
@@ -5,6 +5,7 @@
 
 USAGE='[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [--template <file>] [[-i | -o] <path>...]'
 SUBDIRECTORY_OK=Yes
+OPTIONS_SPEC=
 . git-sh-setup
 require_work_tree
 
@@ -26,7 +27,7 @@ refuse_partial () {
 }
 
 TMP_INDEX=
-THIS_INDEX="$GIT_DIR/index"
+THIS_INDEX="${GIT_INDEX_FILE:-$GIT_DIR/index}"
 NEXT_INDEX="$GIT_DIR/next-index$$"
 rm -f "$NEXT_INDEX"
 save_index () {
@@ -282,9 +283,9 @@ unset only
 case "$all,$interactive,$also,$#" in
 *t,*t,*)
        die "Cannot use -a, --interactive or -i at the same time." ;;
-t,,[1-9]*)
+t,,,[1-9]*)
        die "Paths with -a does not make sense." ;;
-,t,[1-9]*)
+,t,,[1-9]*)
        die "Paths with --interactive does not make sense." ;;
 ,,t,0)
        die "No paths with -i does not make sense." ;;
index 7b29d1b905c618a50704a7b2c38041f71c942e71..276a43724d91781a6c6d79b283ef526e09917c87 100644 (file)
@@ -20,6 +20,7 @@
 #endif
 
 #define MSB(x, bits) ((x) & TYPEOF(x)(~0ULL << (sizeof(x) * 8 - (bits))))
+#define HAS_MULTI_BITS(i)  ((i) & ((i) - 1))  /* checks if an integer has more than 1 bit set */
 
 /* Approximation of the length of the decimal representation of this type. */
 #define decimal_length(x)      ((int)(sizeof(x) * 2.56 + 0.5) + 1)
@@ -183,6 +184,22 @@ void *gitmemmem(const void *haystack, size_t haystacklen,
                 const void *needle, size_t needlelen);
 #endif
 
+#ifdef __GLIBC_PREREQ
+#if __GLIBC_PREREQ(2, 1)
+#define HAVE_STRCHRNUL
+#endif
+#endif
+
+#ifndef HAVE_STRCHRNUL
+#define strchrnul gitstrchrnul
+static inline char *gitstrchrnul(const char *s, int c)
+{
+       while (*s && *s != c)
+               s++;
+       return (char *)s;
+}
+#endif
+
 extern void release_pack_memory(size_t, int);
 
 static inline char* xstrdup(const char *str)
index 26844af4390b8b0902ad853f40e4d9f60b75fd23..92e41620fd2a998e765a47c2c2ca7085834b14cc 100755 (executable)
@@ -1,28 +1,42 @@
 #!/usr/bin/perl -w
 
-# Known limitations:
-# - does not propagate permissions
-# - error handling has not been extensively tested
-#
-
 use strict;
 use Getopt::Std;
 use File::Temp qw(tempdir);
 use Data::Dumper;
 use File::Basename qw(basename dirname);
 
-unless ($ENV{GIT_DIR} && -r $ENV{GIT_DIR}){
-    die "GIT_DIR is not defined or is unreadable";
-}
-
-our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m, $opt_d, $opt_u);
+our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m, $opt_d, $opt_u, $opt_w);
 
-getopts('uhPpvcfam:d:');
+getopts('uhPpvcfam:d:w:');
 
 $opt_h && usage();
 
 die "Need at least one commit identifier!" unless @ARGV;
 
+if ($opt_w) {
+       unless ($ENV{GIT_DIR}) {
+               # Remember where our GIT_DIR is before changing to CVS checkout
+               my $gd =`git-rev-parse --git-dir`;
+               chomp($gd);
+               if ($gd eq '.git') {
+                       my $wd = `pwd`;
+                       chomp($wd);
+                       $gd = $wd."/.git"       ;
+               }
+               $ENV{GIT_DIR} = $gd;
+       }
+
+       if (! -d $opt_w."/CVS" ) {
+               die "$opt_w is not a CVS checkout";
+       }
+       chdir $opt_w or die "Cannot change to CVS checkout at $opt_w";
+}
+unless ($ENV{GIT_DIR} && -r $ENV{GIT_DIR}){
+    die "GIT_DIR is not defined or is unreadable";
+}
+
+
 my @cvs;
 if ($opt_d) {
        @cvs = ('cvs', '-d', $opt_d);
     print "You'll need to apply the patch in .cvsexportcommit.diff manually\n";
     print "using a patch program. After applying the patch and resolving the\n";
     print "problems you may commit using:";
+    print "\n    cd \"$opt_w\"" if $opt_w;
     print "\n    $cmd\n\n";
     exit(1);
 }
 
 sub usage {
        print STDERR <<END;
-Usage: GIT_DIR=/path/to/.git ${\basename $0} [-h] [-p] [-v] [-c] [-f] [-m msgprefix] [ parent ] commit
+Usage: GIT_DIR=/path/to/.git ${\basename $0} [-h] [-p] [-v] [-c] [-f] [-u] [-w cvsworkdir] [-m msgprefix] [ parent ] commit
 END
        exit(1);
 }
index e4bc2b54f68930df217751975e32b4224f8d765c..efa6a0c41ad5a253047789e8ac2a30bf57f8646d 100755 (executable)
@@ -223,7 +223,8 @@ sub conn {
                        }
                }
 
-               $user="anonymous" unless defined $user;
+               # if username is not explicit in CVSROOT, then use current user, as cvs would
+               $user=(getlogin() || $ENV{'LOGNAME'} || $ENV{'USER'} || "anonymous") unless $user;
                my $rr2 = "-";
                unless ($port) {
                        $rr2 = ":pserver:$user\@$serv:$repo";
index ffcc408ee5217d7a8f6179a0404ffe387e0dab0f..c9f515d0ee0f36fc44f667f17674462ced7c2c9e 100755 (executable)
@@ -92,6 +92,7 @@ USAGE="[--env-filter <command>] [--tree-filter <command>] \
 [--original <namespace>] [-d <directory>] [-f | --force] \
 [<rev-list options>...]"
 
+OPTIONS_SPEC=
 . git-sh-setup
 
 git diff-files --quiet &&
index ada1180528b08607858efbcce9b2afc6d1b0e061..8503ae40309e6c8b1547289c9950d99f4bf736b5 100755 (executable)
@@ -2,9 +2,21 @@
 #
 # Copyright (c) 2006 Eric Wong
 #
-USAGE='[--start] [--stop] [--restart]
-  [--local] [--httpd=<httpd>] [--port=<port>] [--browser=<browser>]
-  [--module-path=<path> (for Apache2 only)]'
+
+OPTIONS_KEEPDASHDASH=
+OPTIONS_SPEC="\
+git-instaweb [options] (--start | --stop | --restart)
+--
+l,local        only bind on 127.0.0.1
+p,port=        the port to bind to
+d,httpd=       the command to launch
+b,browser=     the browser to launch
+m,module-path= the module path (only needed for apache2)
+ Action
+stop           stop the web server
+start          start the web server
+restart        restart the web server
+"
 
 . git-sh-setup
 
@@ -78,52 +90,26 @@ do
                start_httpd
                exit 0
                ;;
-       --local|-l)
+       -l|--local)
                local=true
                ;;
-       -d|--httpd|--httpd=*)
-               case "$#,$1" in
-               *,*=*)
-                       httpd=`expr "$1" : '-[^=]*=\(.*\)'` ;;
-               1,*)
-                       usage ;;
-               *)
-                       httpd="$2"
-                       shift ;;
-               esac
+       -d|--httpd)
+               shift
+               httpd="$1"
+               ;;
+       -b|--browser)
+               shift
+               browser="$1"
                ;;
-       -b|--browser|--browser=*)
-               case "$#,$1" in
-               *,*=*)
-                       browser=`expr "$1" : '-[^=]*=\(.*\)'` ;;
-               1,*)
-                       usage ;;
-               *)
-                       browser="$2"
-                       shift ;;
-               esac
+       -p|--port)
+               shift
+               port="$1"
                ;;
-       -p|--port|--port=*)
-               case "$#,$1" in
-               *,*=*)
-                       port=`expr "$1" : '-[^=]*=\(.*\)'` ;;
-               1,*)
-                       usage ;;
-               *)
-                       port="$2"
-                       shift ;;
-               esac
+       -m|--module-path)
+               shift
+               module_path="$1"
                ;;
-       -m|--module-path=*|--module-path)
-               case "$#,$1" in
-               *,*=*)
-                       module_path=`expr "$1" : '-[^=]*=\(.*\)'` ;;
-               1,*)
-                       usage ;;
-               *)
-                       module_path="$2"
-                       shift ;;
-               esac
+       --)
                ;;
        *)
                usage
index f2ec5d147a56136b8c3aff8b693912a7c792da63..9cedaf80ceac1d4100adf3cfb152c76c7f945e4d 100755 (executable)
@@ -2,6 +2,7 @@
 
 USAGE=''
 SUBDIRECTORY_OK='Yes'
+OPTIONS_SPEC=
 . git-sh-setup
 
 echo "WARNING: '$0' is deprecated in favor of 'git fsck --lost-found'" >&2
index c2092a204035ad0315a3d37ed2f70097e68ed052..1c123a37e6941b6727c6101bb29cbc485a380c20 100755 (executable)
@@ -3,7 +3,19 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-USAGE='[-n] [--summary] [--[no-]commit] [--[no-]squash] [--[no-]ff] [-s <strategy>] [-m=<merge-message>] <commit>+'
+OPTIONS_KEEPDASHDASH=
+OPTIONS_SPEC="\
+git-merge [options] <remote>...
+git-merge [options] <msg> HEAD <remote>
+--
+summary              show a diffstat at the end of the merge
+n,no-summary         don't show a diffstat at the end of the merge
+squash               create a single commit instead of doing a merge
+commit               perform a commit if the merge sucesses (default)
+ff                   allow fast forward (default)
+s,strategy=          merge strategy to use
+m,message=           message to be used for the merge commit (if any)
+"
 
 SUBDIRECTORY_OK=Yes
 . git-sh-setup
@@ -28,20 +40,19 @@ allow_trivial_merge=t
 
 dropsave() {
        rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" \
-                "$GIT_DIR/MERGE_SAVE" || exit 1
+                "$GIT_DIR/MERGE_STASH" || exit 1
 }
 
 savestate() {
        # Stash away any local modifications.
-       git diff-index -z --name-only $head |
-       cpio -0 -o >"$GIT_DIR/MERGE_SAVE"
+       git stash create >"$GIT_DIR/MERGE_STASH"
 }
 
 restorestate() {
-        if test -f "$GIT_DIR/MERGE_SAVE"
+        if test -f "$GIT_DIR/MERGE_STASH"
        then
                git reset --hard $head >/dev/null
-               cpio -iuv <"$GIT_DIR/MERGE_SAVE"
+               git stash apply $(cat "$GIT_DIR/MERGE_STASH")
                git update-index --refresh >/dev/null
        fi
 }
@@ -133,72 +144,47 @@ merge_name () {
        fi
 }
 
-parse_option () {
-       case "$1" in
-       -n|--n|--no|--no-|--no-s|--no-su|--no-sum|--no-summ|\
-               --no-summa|--no-summar|--no-summary)
-               show_diffstat=false ;;
-       --summary)
-               show_diffstat=t ;;
-       --sq|--squ|--squa|--squas|--squash)
-               allow_fast_forward=t squash=t no_commit=t ;;
-       --no-sq|--no-squ|--no-squa|--no-squas|--no-squash)
-               allow_fast_forward=t squash= no_commit= ;;
-       --c|--co|--com|--comm|--commi|--commit)
-               allow_fast_forward=t squash= no_commit= ;;
-       --no-c|--no-co|--no-com|--no-comm|--no-commi|--no-commit)
-               allow_fast_forward=t squash= no_commit=t ;;
-       --ff)
-               allow_fast_forward=t squash= no_commit= ;;
-       --no-ff)
-               allow_fast_forward=false squash= no_commit= ;;
-       -s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\
-               --strateg=*|--strategy=*|\
-       -s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy)
-               case "$#,$1" in
-               *,*=*)
-                       strategy=`expr "z$1" : 'z-[^=]*=\(.*\)'` ;;
-               1,*)
-                       usage ;;
-               *)
-                       strategy="$2"
-                       shift ;;
-               esac
-               case " $all_strategies " in
-               *" $strategy "*)
-                       use_strategies="$use_strategies$strategy " ;;
-               *)
-                       die "available strategies are: $all_strategies" ;;
-               esac
-               ;;
-       -m=*|--m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
-               merge_msg=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-               have_message=t
-               ;;
-       -m|--m|--me|--mes|--mess|--messa|--messag|--message)
-               shift
-               case "$#" in
-               1)      usage ;;
-               esac
-               merge_msg="$1"
-               have_message=t
-               ;;
-       -*)     usage ;;
-       *)      return 1 ;;
-       esac
-       shift
-       args_left=$#
-}
-
 parse_config () {
-       while test $# -gt 0
-       do
-               parse_option "$@" || usage
-               while test $args_left -lt $#
-               do
+       while test $# != 0; do
+               case "$1" in
+               -n|--no-summary)
+                       show_diffstat=false ;;
+               --summary)
+                       show_diffstat=t ;;
+               --squash)
+                       allow_fast_forward=t squash=t no_commit=t ;;
+               --no-squash)
+                       allow_fast_forward=t squash= no_commit= ;;
+               --commit)
+                       allow_fast_forward=t squash= no_commit= ;;
+               --no-commit)
+                       allow_fast_forward=t squash= no_commit=t ;;
+               --ff)
+                       allow_fast_forward=t squash= no_commit= ;;
+               --no-ff)
+                       allow_fast_forward=false squash= no_commit= ;;
+               -s|--strategy)
+                       shift
+                       case " $all_strategies " in
+                       *" $1 "*)
+                               use_strategies="$use_strategies$1 " ;;
+                       *)
+                               die "available strategies are: $all_strategies" ;;
+                       esac
+                       ;;
+               -m|--message)
                        shift
-               done
+                       merge_msg="$1"
+                       have_message=t
+                       ;;
+               --)
+                       shift
+                       break ;;
+               *)      usage ;;
+               esac
+               shift
        done
+       args_left=$#
 }
 
 test $# != 0 || usage
@@ -210,17 +196,12 @@ then
        mergeopts=$(git config "branch.${branch#refs/heads/}.mergeoptions")
        if test -n "$mergeopts"
        then
-               parse_config $mergeopts
+               parse_config $mergeopts --
        fi
 fi
 
-while parse_option "$@"
-do
-       while test $args_left -lt $#
-       do
-               shift
-       done
-done
+parse_config "$@"
+while test $args_left -lt $#; do shift; done
 
 if test -z "$show_diffstat"; then
     test "$(git config --bool merge.diffstat)" = false && show_diffstat=false
@@ -437,7 +418,7 @@ case "$use_strategies" in
     single_strategy=no
     ;;
 *)
-    rm -f "$GIT_DIR/MERGE_SAVE"
+    rm -f "$GIT_DIR/MERGE_STASH"
     single_strategy=yes
     ;;
 esac
index a68b40386bde1c47c33a19514ec3a22db7fb0e4b..5587c5ecea0f6a97f2715636890c9e2f89845d52 100755 (executable)
@@ -10,6 +10,7 @@
 
 USAGE='[--tool=tool] [file to merge] ...'
 SUBDIRECTORY_OK=Yes
+OPTIONS_SPEC=
 . git-sh-setup
 require_work_tree
 prefix=$(git rev-parse --show-prefix)
index 75ec011969f7cd84979911b917b886696a077c5e..30fdc57310897207f2e931396d184e94b48ad2ef 100755 (executable)
@@ -7,6 +7,7 @@
 USAGE='[-n | --no-summary] [--[no-]commit] [--[no-]squash] [--[no-]ff] [-s strategy]... [<fetch-options>] <repo> <head>...'
 LONG_USAGE='Fetch one or more remote refs and merge it/them into the current HEAD.'
 SUBDIRECTORY_OK=Yes
+OPTIONS_SPEC=
 . git-sh-setup
 set_reflog_action "pull $*"
 require_work_tree
index 880c81d121bfb9555c729bc299f8ae8baf1db32c..6b0c4d2f279cf9e567e8c317c21e59d352ce3ff6 100755 (executable)
@@ -1,5 +1,12 @@
 #!/bin/sh
-USAGE='--dry-run --author <author> --patches </path/to/quilt/patch/directory>'
+OPTIONS_KEEPDASHDASH=
+OPTIONS_SPEC="\
+git-quiltimport [options]
+--
+n,dry-run     dry run
+author=       author name and email address for patches without any
+patches=      path to the quilt series and patches
+"
 SUBDIRECTORY_ON=Yes
 . git-sh-setup
 
@@ -8,39 +15,25 @@ quilt_author=""
 while test $# != 0
 do
        case "$1" in
-       --au=*|--aut=*|--auth=*|--autho=*|--author=*)
-               quilt_author=$(expr "z$1" : 'z-[^=]*\(.*\)')
-               shift
-               ;;
-
-       --au|--aut|--auth|--autho|--author)
-               case "$#" in 1) usage ;; esac
+       --author)
                shift
                quilt_author="$1"
-               shift
                ;;
-
-       --dry-run)
-               shift
+       -n|--dry-run)
                dry_run=1
                ;;
-
-       --pa=*|--pat=*|--patc=*|--patch=*|--patche=*|--patches=*)
-               QUILT_PATCHES=$(expr "z$1" : 'z-[^=]*\(.*\)')
-               shift
-               ;;
-
-       --pa|--pat|--patc|--patch|--patche|--patches)
-               case "$#" in 1) usage ;; esac
+       --patches)
                shift
                QUILT_PATCHES="$1"
-               shift
                ;;
-
+       --)
+               shift
+               break;;
        *)
-               break
+               usage
                ;;
        esac
+       shift
 done
 
 # Quilt Author
index 51063776d2540ed4ad6537e3578916b40d46c81a..66c80d4e16e3217b93b9de12a4b02d107a2eeb71 100755 (executable)
@@ -13,6 +13,7 @@
 USAGE='(--continue | --abort | --skip | [--preserve-merges] [--verbose]
        [--onto <branch>] <upstream> [<branch>])'
 
+OPTIONS_SPEC=
 . git-sh-setup
 require_work_tree
 
index 224cca98eea324cabf30885f7c92c254b184410b..df5fd65d56bde3ed046c9ed40e62e8a17ede2e8e 100755 (executable)
@@ -29,6 +29,7 @@ Example:       git-rebase master~1 topic
 '
 
 SUBDIRECTORY_OK=Yes
+OPTIONS_SPEC=
 . git-sh-setup
 set_reflog_action rebase
 require_work_tree
@@ -87,7 +88,7 @@ call_merge () {
        cmt="$(cat "$dotest/cmt.$1")"
        echo "$cmt" > "$dotest/current"
        hd=$(git rev-parse --verify HEAD)
-       cmt_name=$(git symbolic-ref HEAD)
+       cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD)
        msgnum=$(cat "$dotest/msgnum")
        end=$(cat "$dotest/end")
        eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
@@ -115,7 +116,24 @@ call_merge () {
        esac
 }
 
+move_to_original_branch () {
+       test -z "$head_name" &&
+               head_name="$(cat "$dotest"/head-name)" &&
+               onto="$(cat "$dotest"/onto)" &&
+               orig_head="$(cat "$dotest"/orig-head)"
+       case "$head_name" in
+       refs/*)
+               message="rebase finished: $head_name onto $onto"
+               git update-ref -m "$message" \
+                       $head_name $(git rev-parse HEAD) $orig_head &&
+               git symbolic-ref HEAD $head_name ||
+               die "Could not move back to $head_name"
+               ;;
+       esac
+}
+
 finish_rb_merge () {
+       move_to_original_branch
        rm -r "$dotest"
        echo "All done."
 }
@@ -153,7 +171,11 @@ do
                        finish_rb_merge
                        exit
                fi
-               git am --resolved --3way --resolvemsg="$RESOLVEMSG"
+               head_name=$(cat .dotest/head-name) &&
+               onto=$(cat .dotest/onto) &&
+               orig_head=$(cat .dotest/orig-head) &&
+               git am --resolved --3way --resolvemsg="$RESOLVEMSG" &&
+               move_to_original_branch
                exit
                ;;
        --skip)
@@ -173,16 +195,23 @@ do
                        finish_rb_merge
                        exit
                fi
-               git am -3 --skip --resolvemsg="$RESOLVEMSG"
+               head_name=$(cat .dotest/head-name) &&
+               onto=$(cat .dotest/onto) &&
+               orig_head=$(cat .dotest/orig-head) &&
+               git am -3 --skip --resolvemsg="$RESOLVEMSG" &&
+               move_to_original_branch
                exit
                ;;
        --abort)
                git rerere clear
                if test -d "$dotest"
                then
+                       move_to_original_branch
                        rm -r "$dotest"
                elif test -d .dotest
                then
+                       dotest=.dotest
+                       move_to_original_branch
                        rm -r .dotest
                else
                        die "No rebase in progress?"
@@ -318,6 +347,19 @@ then
        GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
 fi
 
+# move to a detached HEAD
+orig_head=$(git rev-parse HEAD^0)
+head_name=$(git symbolic-ref HEAD 2> /dev/null)
+case "$head_name" in
+'')
+       head_name="detached HEAD"
+       ;;
+*)
+       git checkout "$orig_head" > /dev/null 2>&1 ||
+               die "could not detach HEAD"
+       ;;
+esac
+
 # Rewind the head to "$onto"; this saves our current head in ORIG_HEAD.
 echo "First, rewinding head to replay your work on top of it..."
 git-reset --hard "$onto"
@@ -327,14 +369,21 @@ git-reset --hard "$onto"
 if test "$mb" = "$branch"
 then
        echo >&2 "Fast-forwarded $branch_name to $onto_name."
+       move_to_original_branch
        exit 0
 fi
 
 if test -z "$do_merge"
 then
        git format-patch -k --stdout --full-index --ignore-if-in-upstream "$upstream"..ORIG_HEAD |
-       git am $git_am_opt --binary -3 -k --resolvemsg="$RESOLVEMSG"
-       exit $?
+       git am $git_am_opt --binary -3 -k --resolvemsg="$RESOLVEMSG" &&
+       move_to_original_branch
+       ret=$?
+       test 0 != $ret -a -d .dotest &&
+               echo $head_name > .dotest/head-name &&
+               echo $onto > .dotest/onto &&
+               echo $orig_head > .dotest/orig-head
+       exit $ret
 fi
 
 # start doing a rebase with git-merge
@@ -343,8 +392,10 @@ fi
 mkdir -p "$dotest"
 echo "$onto" > "$dotest/onto"
 echo "$onto_name" > "$dotest/onto_name"
-prev_head=`git rev-parse HEAD^0`
+prev_head=$orig_head
 echo "$prev_head" > "$dotest/prev_head"
+echo "$orig_head" > "$dotest/orig-head"
+echo "$head_name" > "$dotest/head-name"
 
 msgnum=0
 for cmt in `git rev-list --reverse --no-merges "$upstream"..ORIG_HEAD`
index 7220635c96a75a17634297b33bac8322647b8270..e18eb3f5dcf42abfbd125594877ececf92c3d9b6 100755 (executable)
@@ -3,7 +3,22 @@
 # Copyright (c) 2005 Linus Torvalds
 #
 
-USAGE='[-a|-A] [-d] [-f] [-l] [-n] [-q] [--max-pack-size=N] [--window=N] [--window-memory=N] [--depth=N]'
+OPTIONS_KEEPDASHDASH=
+OPTIONS_SPEC="\
+git-repack [options]
+--
+a               pack everything in a single pack
+A               same as -a, and keep unreachable objects too
+d               remove redundant packs, and run git-prune-packed
+f               pass --no-reuse-delta to git-pack-objects
+q,quiet         be quiet
+l               pass --local to git-pack-objects
+ Packing constraints
+window=         size of the window used for delta compression
+window-memory=  same as the above, but limit memory size instead of entries count
+depth=          limits the maximum delta depth
+max-pack-size=  maximum size of each packfile
+"
 SUBDIRECTORY_OK='Yes'
 . git-sh-setup
 
@@ -20,10 +35,9 @@ do
        -q)     quiet=-q ;;
        -f)     no_reuse=--no-reuse-object ;;
        -l)     local=--local ;;
-       --max-pack-size=*) extra="$extra $1" ;;
-       --window=*) extra="$extra $1" ;;
-       --window-memory=*) extra="$extra $1" ;;
-       --depth=*) extra="$extra $1" ;;
+       --max-pack-size|--window|--window-memory|--depth)
+               extra="$extra $1=$2"; shift ;;
+       --) shift; break;;
        *)      usage ;;
        esac
        shift
index 95ad66630f39effead53598a650dec0ab7b90289..068f5e0fc7308db601141bc3e70475ec2145ef67 100755 (executable)
@@ -8,6 +8,7 @@ USAGE='<commit> <url> [<head>]'
 LONG_USAGE='Summarizes the changes since <commit> to the standard output,
 and includes <url> in the message generated.'
 SUBDIRECTORY_OK='Yes'
+OPTIONS_SPEC=
 . git-sh-setup
 . git-parse-remote
 
index f9bd2e5a9176ccf7dd8e2ce15233d2d93f9222ec..fd0a4ad0c24dfedd2fea278733d8f6cff59b2eb5 100755 (executable)
@@ -514,11 +514,13 @@ sub make_message_id
 
 sub unquote_rfc2047 {
        local ($_) = @_;
-       if (s/=\?utf-8\?q\?(.*)\?=/$1/g) {
+       my $encoding;
+       if (s/=\?([^?]+)\?q\?(.*)\?=/$2/g) {
+               $encoding = $1;
                s/_/ /g;
                s/=([0-9A-F]{2})/chr(hex($1))/eg;
        }
-       return "$_";
+       return wantarray ? ($_, $encoding) : $_;
 }
 
 # use the simplest quoting being able to handle the recipient
@@ -667,6 +669,9 @@ sub send_message
        open(F,"<",$t) or die "can't open file $t";
 
        my $author = undef;
+       my $author_encoding;
+       my $has_content_type;
+       my $body_encoding;
        @cc = @initial_cc;
        @xh = ();
        my $input_format = undef;
@@ -692,12 +697,20 @@ sub send_message
                                                next if ($suppress_from);
                                        }
                                        elsif ($1 eq 'From') {
-                                               $author = unquote_rfc2047($2);
+                                               ($author, $author_encoding)
+                                                 = unquote_rfc2047($2);
                                        }
                                        printf("(mbox) Adding cc: %s from line '%s'\n",
                                                $2, $_) unless $quiet;
                                        push @cc, $2;
                                }
+                               elsif (/^Content-type:/i) {
+                                       $has_content_type = 1;
+                                       if (/charset="?[^ "]+/) {
+                                               $body_encoding = $1;
+                                       }
+                                       push @xh, $_;
+                               }
                                elsif (!/^Date:\s/ && /^[-A-Za-z]+:\s+\S/) {
                                        push @xh, $_;
                                }
@@ -756,6 +769,21 @@ sub send_message
 
        if (defined $author) {
                $message = "From: $author\n\n$message";
+               if (defined $author_encoding) {
+                       if ($has_content_type) {
+                               if ($body_encoding eq $author_encoding) {
+                                       # ok, we already have the right encoding
+                               }
+                               else {
+                                       # uh oh, we should re-encode
+                               }
+                       }
+                       else {
+                               push @xh,
+                                 'MIME-Version: 1.0',
+                                 "Content-Type: text/plain; charset=$author_encoding";
+                       }
+               }
        }
 
        send_message();
index 86d7d4c4e742c80e936d5f1c9f2037327eba7287..5aa62dda15d1c24d0b01845ded4c8bc15e98bf8a 100755 (executable)
@@ -16,9 +16,40 @@ die() {
        exit 1
 }
 
-usage() {
-       die "Usage: $0 $USAGE"
-}
+if test -n "$OPTIONS_SPEC"; then
+       usage() {
+               exec "$0" -h
+       }
+
+       parseopt_extra=
+       [ -n "$OPTIONS_KEEPDASHDASH" ] &&
+               parseopt_extra="--keep-dashdash"
+
+       eval "$(
+               echo "$OPTIONS_SPEC" |
+                       git rev-parse --parseopt $parseopt_extra -- "$@" ||
+               echo exit $?
+       )"
+else
+       usage() {
+               die "Usage: $0 $USAGE"
+       }
+
+       if [ -z "$LONG_USAGE" ]
+       then
+               LONG_USAGE="Usage: $0 $USAGE"
+       else
+               LONG_USAGE="Usage: $0 $USAGE
+
+$LONG_USAGE"
+       fi
+
+       case "$1" in
+               -h|--h|--he|--hel|--help)
+               echo "$LONG_USAGE"
+               exit
+       esac
+fi
 
 set_reflog_action() {
        if [ -z "${GIT_REFLOG_ACTION:+set}" ]
@@ -91,21 +122,6 @@ get_author_ident_from_commit () {
        LANG=C LC_ALL=C sed -ne "$pick_author_script"
 }
 
-if [ -z "$LONG_USAGE" ]
-then
-       LONG_USAGE="Usage: $0 $USAGE"
-else
-       LONG_USAGE="Usage: $0 $USAGE
-
-$LONG_USAGE"
-fi
-
-case "$1" in
-       -h|--h|--he|--hel|--help)
-       echo "$LONG_USAGE"
-       exit
-esac
-
 # Make sure we are in a valid repository of a vintage we understand.
 if [ -z "$SUBDIRECTORY_OK" ]
 then
index 5bbda47b7b6e286e7e8e5d002d7ed461a831b579..534eb168abf8b0b8ae5c2195bf85b66d9cb6b21e 100755 (executable)
@@ -4,6 +4,7 @@
 USAGE='[ | list | show | apply | clear]'
 
 SUBDIRECTORY_OK=Yes
+OPTIONS_SPEC=
 . git-sh-setup
 require_work_tree
 cd_to_toplevel
@@ -21,23 +22,17 @@ no_changes () {
 clear_stash () {
        if current=$(git rev-parse --verify $ref_stash 2>/dev/null)
        then
-               git update-ref -d refs/stash $current
+               git update-ref -d $ref_stash $current
        fi
 }
 
-save_stash () {
+create_stash () {
        stash_msg="$1"
 
        if no_changes
        then
-               echo >&2 'No local changes to save'
                exit 0
        fi
-       test -f "$GIT_DIR/logs/$ref_stash" ||
-               clear_stash || die "Cannot initialize stash"
-
-       # Make sure the reflog for stash is kept.
-       : >>"$GIT_DIR/logs/$ref_stash"
 
        # state of the base commit
        if b_commit=$(git rev-parse --verify HEAD)
@@ -84,6 +79,23 @@ save_stash () {
        w_commit=$(printf '%s\n' "$stash_msg" |
                git commit-tree $w_tree -p $b_commit -p $i_commit) ||
                die "Cannot record working tree state"
+}
+
+save_stash () {
+       stash_msg="$1"
+
+       if no_changes
+       then
+               echo >&2 'No local changes to save'
+               exit 0
+       fi
+       test -f "$GIT_DIR/logs/$ref_stash" ||
+               clear_stash || die "Cannot initialize stash"
+
+       create_stash "$stash_msg"
+
+       # Make sure the reflog for stash is kept.
+       : >>"$GIT_DIR/logs/$ref_stash"
 
        git update-ref -m "$stash_msg" $ref_stash $w_commit ||
                die "Cannot save the current status"
@@ -202,6 +214,13 @@ apply)
 clear)
        clear_stash
        ;;
+create)
+       if test $# -gt 0 && test "$1" = create
+       then
+               shift
+       fi
+       create_stash "$*" && echo "$w_commit"
+       ;;
 help | usage)
        usage
        ;;
index 5af28ecd58de8c46f194280887ef9c27c784e606..82ac28fa27dc41b821905f1a83155994d56c4f3b 100755 (executable)
@@ -5,6 +5,7 @@
 # Copyright (c) 2007 Lars Hjemli
 
 USAGE='[--quiet] [--cached] [add <repo> [-b branch]|status|init|update] [--] [<path>...]'
+OPTIONS_SPEC=
 . git-sh-setup
 require_work_tree
 
index e3e00fdcc5f4b0ad1d06cc026a5efe62ff0be0fe..5b1deeab942aa2a63a6cbe6a92792dbbe6f17d01 100755 (executable)
@@ -391,7 +391,7 @@ sub cmd_set_tree {
 sub cmd_dcommit {
        my $head = shift;
        git_cmd_try { command_oneline(qw/diff-index --quiet HEAD/) }
-               'Cannot dcommit with a dirty index.  Commit your changes first'
+               'Cannot dcommit with a dirty index.  Commit your changes first'
                . "or stash them with `git stash'.\n";
        $head ||= 'HEAD';
        my @refs;
@@ -425,6 +425,9 @@ sub cmd_dcommit {
                        my %ed_opts = ( r => $last_rev,
                                        log => get_commit_entry($d)->{log},
                                        ra => Git::SVN::Ra->new($gs->full_url),
+                                       config => SVN::Core::config_get_config(
+                                               $Git::SVN::Ra::config_dir
+                                       ),
                                        tree_a => "$d~1",
                                        tree_b => $d,
                                        editor_cb => sub {
@@ -2396,10 +2399,15 @@ sub rev_db_get {
        $ret;
 }
 
+# Finds the first svn revision that exists on (if $eq_ok is true) or
+# before $rev for the current branch.  It will not search any lower
+# than $min_rev.  Returns the git commit hash and svn revision number
+# if found, else (undef, undef).
 sub find_rev_before {
-       my ($self, $rev, $eq_ok) = @_;
+       my ($self, $rev, $eq_ok, $min_rev) = @_;
        --$rev unless $eq_ok;
-       while ($rev > 0) {
+       $min_rev ||= 1;
+       while ($rev >= $min_rev) {
                if (my $c = $self->rev_db_get($rev)) {
                        return ($rev, $c);
                }
@@ -2408,6 +2416,23 @@ sub find_rev_before {
        return (undef, undef);
 }
 
+# Finds the first svn revision that exists on (if $eq_ok is true) or
+# after $rev for the current branch.  It will not search any higher
+# than $max_rev.  Returns the git commit hash and svn revision number
+# if found, else (undef, undef).
+sub find_rev_after {
+       my ($self, $rev, $eq_ok, $max_rev) = @_;
+       ++$rev unless $eq_ok;
+       $max_rev ||= $self->rev_db_max();
+       while ($rev <= $max_rev) {
+               if (my $c = $self->rev_db_get($rev)) {
+                       return ($rev, $c);
+               }
+               ++$rev;
+       }
+       return (undef, undef);
+}
+
 sub _new {
        my ($class, $repo_id, $ref_id, $path) = @_;
        unless (defined $repo_id && length $repo_id) {
@@ -3698,6 +3723,7 @@ package Git::SVN::Log;
 use strict;
 use warnings;
 use POSIX qw/strftime/;
+use constant commit_log_separator => ('-' x 72) . "\n";
 use vars qw/$TZ $limit $color $pager $non_recursive $verbose $oneline
             %rusers $show_commit $incremental/;
 my $l_fmt;
@@ -3791,19 +3817,19 @@ sub git_svn_log_cmd {
                        push @cmd, $c;
                }
        } elsif (defined $r_max) {
-               my ($c_min, $c_max);
-               $c_max = $gs->rev_db_get($r_max);
-               $c_min = $gs->rev_db_get($r_min);
-               if (defined $c_min && defined $c_max) {
-                       if ($r_max > $r_max) {
-                               push @cmd, "$c_min..$c_max";
-                       } else {
-                               push @cmd, "$c_max..$c_min";
-                       }
-               } elsif ($r_max > $r_min) {
-                       push @cmd, $c_max;
+               if ($r_max < $r_min) {
+                       ($r_min, $r_max) = ($r_max, $r_min);
+               }
+               my (undef, $c_max) = $gs->find_rev_before($r_max, 1, $r_min);
+               my (undef, $c_min) = $gs->find_rev_after($r_min, 1, $r_max);
+               # If there are no commits in the range, both $c_max and $c_min
+               # will be undefined.  If there is at least 1 commit in the
+               # range, both will be defined.
+               return () if !defined $c_min || !defined $c_max;
+               if ($c_min eq $c_max) {
+                       push @cmd, '--max-count=1', $c_min;
                } else {
-                       push @cmd, $c_min;
+                       push @cmd, '--boundary', "$c_min..$c_max";
                }
        }
        return (@cmd, @files);
@@ -3911,7 +3937,7 @@ sub show_commit_changed_paths {
 
 sub show_commit_normal {
        my ($c) = @_;
-       print '-' x72, "\nr$c->{r} | ";
+       print commit_log_separator, "r$c->{r} | ";
        print "$c->{c} | " if $show_commit;
        print "$c->{a} | ", strftime("%Y-%m-%d %H:%M:%S %z (%a, %d %b %Y)",
                                 localtime($c->{t_utc})), ' | ';
@@ -3972,12 +3998,16 @@ sub cmd_show_log {
 
        config_pager();
        @args = git_svn_log_cmd($r_min, $r_max, @args);
+       if (!@args) {
+               print commit_log_separator unless $incremental || $oneline;
+               return;
+       }
        my $log = command_output_pipe(@args);
        run_pager();
        my (@k, $c, $d, $stat);
        my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/;
        while (<$log>) {
-               if (/^${esc_color}commit ($::sha1_short)/o) {
+               if (/^${esc_color}commit -?($::sha1_short)/o) {
                        my $cmt = $1;
                        if ($c && cmt_showable($c) && $c->{r} != $r_last) {
                                $r_last = $c->{r};
@@ -4020,14 +4050,12 @@ sub cmd_show_log {
                process_commit($c, $r_min, $r_max, \@k);
        }
        if (@k) {
-               my $swap = $r_max;
-               $r_max = $r_min;
-               $r_min = $swap;
+               ($r_min, $r_max) = ($r_max, $r_min);
                process_commit($_, $r_min, $r_max) foreach reverse @k;
        }
 out:
        close $log;
-       print '-' x72,"\n" unless $incremental || $oneline;
+       print commit_log_separator unless $incremental || $oneline;
 }
 
 package Git::SVN::Migration;
diff --git a/git.c b/git.c
index 4a250f7e8b84f2334c84daaf93baa0fe1f0ca344..7604319b5a9e8c12b2f00b4d5e6480445e02daa6 100644 (file)
--- a/git.c
+++ b/git.c
@@ -338,7 +338,7 @@ static void handle_internal_command(int argc, const char **argv)
                { "rerere", cmd_rerere, RUN_SETUP },
                { "reset", cmd_reset, RUN_SETUP },
                { "rev-list", cmd_rev_list, RUN_SETUP },
-               { "rev-parse", cmd_rev_parse, RUN_SETUP },
+               { "rev-parse", cmd_rev_parse },
                { "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
                { "rm", cmd_rm, RUN_SETUP },
                { "runstatus", cmd_runstatus, RUN_SETUP | NEED_WORK_TREE },
index 3c99a1fce97c387ec1dfc76649699a8095e76d81..9fd6982a979a40e701dcb6bcaf117eafbf6ff161 100644 (file)
@@ -87,9 +87,9 @@ static void *fill(int min)
                                die("early EOF");
                        die("read error on input: %s", strerror(errno));
                }
-               if (from_stdin)
-                       display_throughput(progress, ret);
                input_len += ret;
+               if (from_stdin)
+                       display_throughput(progress, consumed_bytes + input_len);
        } while (input_len < min);
        return input_buffer;
 }
@@ -792,6 +792,7 @@ int main(int argc, char **argv)
                flush();
        } else {
                if (fix_thin_pack) {
+                       char msg[48];
                        int nr_unresolved = nr_deltas - nr_resolved_deltas;
                        int nr_objects_initial = nr_objects;
                        if (nr_unresolved <= 0)
@@ -800,12 +801,11 @@ int main(int argc, char **argv)
                                           (nr_objects + nr_unresolved + 1)
                                           * sizeof(*objects));
                        fix_unresolved_deltas(nr_unresolved);
-                       stop_progress(&progress);
-                       if (verbose)
-                               fprintf(stderr, "%d objects were added to complete this thin pack.\n",
-                                       nr_objects - nr_objects_initial);
+                       sprintf(msg, "completed with %d local objects",
+                               nr_objects - nr_objects_initial);
+                       stop_progress_msg(&progress, msg);
                        fixup_pack_header_footer(output_fd, sha1,
-                               curr_pack, nr_objects);
+                                                curr_pack, nr_objects);
                }
                if (nr_deltas != nr_resolved_deltas)
                        die("pack has %d unresolved deltas",
index a34beb0b027eaec59fa75d1fa18324a8f24eb13d..1f3fcf16ad7a101eb9eab53da84bd2640f97ab00 100644 (file)
@@ -245,8 +245,7 @@ void show_log(struct rev_info *opt, const char *sep)
                        opt->diffopt.stat_sep = buffer;
                }
        } else if (opt->commit_format != CMIT_FMT_USERFORMAT) {
-               fputs(diff_get_color(opt->diffopt.color_diff, DIFF_COMMIT),
-                     stdout);
+               fputs(diff_get_color_opt(&opt->diffopt, DIFF_COMMIT), stdout);
                if (opt->commit_format != CMIT_FMT_ONELINE)
                        fputs("commit ", stdout);
                if (commit->object.flags & BOUNDARY)
@@ -266,8 +265,7 @@ void show_log(struct rev_info *opt, const char *sep)
                               diff_unique_abbrev(parent->object.sha1,
                                                  abbrev_commit));
                show_decorations(commit);
-               printf("%s",
-                      diff_get_color(opt->diffopt.color_diff, DIFF_RESET));
+               printf("%s", diff_get_color_opt(&opt->diffopt, DIFF_RESET));
                putchar(opt->commit_format == CMIT_FMT_ONELINE ? ' ' : '\n');
                if (opt->reflog_info) {
                        show_reflog_message(opt->reflog_info,
index 6c6f595fbc7da09a41228e09cd2c5ef48b91f3f0..9a1e2f269dc5eff3b7544507a1e483948cc1254d 100644 (file)
@@ -366,7 +366,7 @@ static struct path_list *get_renames(struct tree *tree,
 
        renames = xcalloc(1, sizeof(struct path_list));
        diff_setup(&opts);
-       opts.recursive = 1;
+       DIFF_OPT_SET(&opts, RECURSIVE);
        opts.detect_rename = DIFF_DETECT_RENAME;
        opts.rename_limit = rename_limit;
        opts.output_format = DIFF_FORMAT_NO_OUTPUT;
index 15b32f741b6b8bf47321b9ce78da43e9378f22b3..d3e608ac45e2a0c6accb9d27ed8d407619cb70d2 100644 (file)
@@ -40,24 +40,53 @@ static int get_value(struct optparse_t *p,
                      const struct option *opt, int flags)
 {
        const char *s, *arg;
-       arg = p->opt ? p->opt : (p->argc > 1 ? p->argv[1] : NULL);
+       const int unset = flags & OPT_UNSET;
 
-       if (p->opt && (flags & OPT_UNSET))
+       if (unset && p->opt)
                return opterror(opt, "takes no value", flags);
+       if (unset && (opt->flags & PARSE_OPT_NONEG))
+               return opterror(opt, "isn't available", flags);
 
-       switch (opt->type) {
-       case OPTION_BOOLEAN:
-               if (!(flags & OPT_SHORT) && p->opt)
+       if (!(flags & OPT_SHORT) && p->opt) {
+               switch (opt->type) {
+               case OPTION_CALLBACK:
+                       if (!(opt->flags & PARSE_OPT_NOARG))
+                               break;
+                       /* FALLTHROUGH */
+               case OPTION_BOOLEAN:
+               case OPTION_BIT:
+               case OPTION_SET_INT:
+               case OPTION_SET_PTR:
                        return opterror(opt, "takes no value", flags);
-               if (flags & OPT_UNSET)
-                       *(int *)opt->value = 0;
+               default:
+                       break;
+               }
+       }
+
+       arg = p->opt ? p->opt : (p->argc > 1 ? p->argv[1] : NULL);
+       switch (opt->type) {
+       case OPTION_BIT:
+               if (unset)
+                       *(int *)opt->value &= ~opt->defval;
                else
-                       (*(int *)opt->value)++;
+                       *(int *)opt->value |= opt->defval;
+               return 0;
+
+       case OPTION_BOOLEAN:
+               *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
+               return 0;
+
+       case OPTION_SET_INT:
+               *(int *)opt->value = unset ? 0 : opt->defval;
+               return 0;
+
+       case OPTION_SET_PTR:
+               *(void **)opt->value = unset ? NULL : (void *)opt->defval;
                return 0;
 
        case OPTION_STRING:
-               if (flags & OPT_UNSET) {
-                       *(const char **)opt->value = (const char *)NULL;
+               if (unset) {
+                       *(const char **)opt->value = NULL;
                        return 0;
                }
                if (opt->flags & PARSE_OPT_OPTARG && (!arg || *arg == '-')) {
@@ -70,13 +99,10 @@ static int get_value(struct optparse_t *p,
                return 0;
 
        case OPTION_CALLBACK:
-               if (flags & OPT_UNSET)
+               if (unset)
                        return (*opt->callback)(opt, NULL, 1);
-               if (opt->flags & PARSE_OPT_NOARG) {
-                       if (p->opt && !(flags & OPT_SHORT))
-                               return opterror(opt, "takes no value", flags);
+               if (opt->flags & PARSE_OPT_NOARG)
                        return (*opt->callback)(opt, NULL, 0);
-               }
                if (opt->flags & PARSE_OPT_OPTARG && (!arg || *arg == '-'))
                        return (*opt->callback)(opt, NULL, 0);
                if (!arg)
@@ -84,7 +110,7 @@ static int get_value(struct optparse_t *p,
                return (*opt->callback)(opt, get_arg(p), 0);
 
        case OPTION_INTEGER:
-               if (flags & OPT_UNSET) {
+               if (unset) {
                        *(int *)opt->value = 0;
                        return 0;
                }
@@ -292,7 +318,7 @@ void usage_with_options(const char * const *usagestr,
                                        pos += fprintf(stderr, " ...");
                        }
                        break;
-               default:
+               default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */
                        break;
                }
 
@@ -311,6 +337,7 @@ void usage_with_options(const char * const *usagestr,
 
 /*----- some often used options -----*/
 #include "cache.h"
+
 int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset)
 {
        int v;
index 65bce6eafd19bfedd7d3b0b31ad81625842a7c0b..a8760ac4b288a44d6404d0550b9640b49789d39d 100644 (file)
@@ -2,9 +2,15 @@
 #define PARSE_OPTIONS_H
 
 enum parse_opt_type {
+       /* special types */
        OPTION_END,
        OPTION_GROUP,
-       OPTION_BOOLEAN,
+       /* options with no arguments */
+       OPTION_BIT,
+       OPTION_BOOLEAN, /* _INCR would have been a better name */
+       OPTION_SET_INT,
+       OPTION_SET_PTR,
+       /* options with arguments (usually) */
        OPTION_STRING,
        OPTION_INTEGER,
        OPTION_CALLBACK,
@@ -17,6 +23,7 @@ enum parse_opt_flags {
 enum parse_opt_option_flags {
        PARSE_OPT_OPTARG  = 1,
        PARSE_OPT_NOARG   = 2,
+       PARSE_OPT_NONEG   = 4,
 };
 
 struct option;
@@ -49,12 +56,15 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
  *   mask of parse_opt_option_flags.
  *   PARSE_OPT_OPTARG: says that the argument is optionnal (not for BOOLEANs)
  *   PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs
+ *   PARSE_OPT_NONEG: says that this option cannot be negated
  *
  * `callback`::
  *   pointer to the callback to use for OPTION_CALLBACK.
  *
  * `defval`::
  *   default value to fill (*->value) with for PARSE_OPT_OPTARG.
+ *   OPTION_{BIT,SET_INT,SET_PTR} store the {mask,integer,pointer} to put in
+ *   the value when met.
  *   CALLBACKS can use it like they want.
  */
 struct option {
@@ -72,7 +82,10 @@ struct option {
 
 #define OPT_END()                   { OPTION_END }
 #define OPT_GROUP(h)                { OPTION_GROUP, 0, NULL, NULL, NULL, (h) }
+#define OPT_BIT(s, l, v, h, b)      { OPTION_BIT, (s), (l), (v), NULL, (h), 0, NULL, (b) }
 #define OPT_BOOLEAN(s, l, v, h)     { OPTION_BOOLEAN, (s), (l), (v), NULL, (h) }
+#define OPT_SET_INT(s, l, v, h, i)  { OPTION_SET_INT, (s), (l), (v), NULL, (h), 0, NULL, (i) }
+#define OPT_SET_PTR(s, l, v, h, p)  { OPTION_SET_PTR, (s), (l), (v), NULL, (h), 0, NULL, (p) }
 #define OPT_INTEGER(s, l, v, h)     { OPTION_INTEGER, (s), (l), (v), NULL, (h) }
 #define OPT_STRING(s, l, v, a, h)   { OPTION_STRING,  (s), (l), (v), (a), (h) }
 #define OPT_CALLBACK(s, l, v, a, h, f) \
index a288fac9923a84cd05e8e7378f580ea3774e2a03..3be5d3165e0009761a0ca69e15e4a9132c6cfaff 100644 (file)
@@ -121,7 +121,7 @@ int init_patch_ids(struct patch_ids *ids)
 {
        memset(ids, 0, sizeof(*ids));
        diff_setup(&ids->diffopts);
-       ids->diffopts.recursive = 1;
+       DIFF_OPT_SET(&ids->diffopts, RECURSIVE);
        if (diff_setup_done(&ids->diffopts) < 0)
                return error("diff_setup_done failed");
        return 0;
index 490cede263020dc15f4d48af06faf8d77552883f..9db75b4e4f24b28ca44d65750ec6ebb4feb99eee 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -1,6 +1,5 @@
 #include "cache.h"
 #include "commit.h"
-#include "interpolate.h"
 #include "utf8.h"
 #include "diff.h"
 #include "revision.h"
@@ -283,7 +282,8 @@ static char *logmsg_reencode(const struct commit *commit,
        return out;
 }
 
-static void fill_person(struct interp *table, const char *msg, int len)
+static void format_person_part(struct strbuf *sb, char part,
+                               const char *msg, int len)
 {
        int start, end, tz = 0;
        unsigned long date;
@@ -295,7 +295,10 @@ static void fill_person(struct interp *table, const char *msg, int len)
        start = end + 1;
        while (end > 0 && isspace(msg[end - 1]))
                end--;
-       table[0].value = xmemdupz(msg, end);
+       if (part == 'n') {      /* name */
+               strbuf_add(sb, msg, end);
+               return;
+       }
 
        if (start >= len)
                return;
@@ -307,7 +310,10 @@ static void fill_person(struct interp *table, const char *msg, int len)
        if (end >= len)
                return;
 
-       table[1].value = xmemdupz(msg + start, end - start);
+       if (part == 'e') {      /* email */
+               strbuf_add(sb, msg + start, end - start);
+               return;
+       }
 
        /* parse date */
        for (start = end + 1; start < len && isspace(msg[start]); start++)
@@ -318,7 +324,10 @@ static void fill_person(struct interp *table, const char *msg, int len)
        if (msg + start == ep)
                return;
 
-       table[5].value = xmemdupz(msg + start, ep - (msg + start));
+       if (part == 't') {      /* date, UNIX timestamp */
+               strbuf_add(sb, msg + start, ep - (msg + start));
+               return;
+       }
 
        /* parse tz */
        for (start = ep - msg + 1; start < len && isspace(msg[start]); start++)
@@ -329,115 +338,66 @@ static void fill_person(struct interp *table, const char *msg, int len)
                        tz = -tz;
        }
 
-       interp_set_entry(table, 2, show_date(date, tz, DATE_NORMAL));
-       interp_set_entry(table, 3, show_date(date, tz, DATE_RFC2822));
-       interp_set_entry(table, 4, show_date(date, tz, DATE_RELATIVE));
-       interp_set_entry(table, 6, show_date(date, tz, DATE_ISO8601));
+       switch (part) {
+       case 'd':       /* date */
+               strbuf_addstr(sb, show_date(date, tz, DATE_NORMAL));
+               return;
+       case 'D':       /* date, RFC2822 style */
+               strbuf_addstr(sb, show_date(date, tz, DATE_RFC2822));
+               return;
+       case 'r':       /* date, relative */
+               strbuf_addstr(sb, show_date(date, tz, DATE_RELATIVE));
+               return;
+       case 'i':       /* date, ISO 8601 */
+               strbuf_addstr(sb, show_date(date, tz, DATE_ISO8601));
+               return;
+       }
 }
 
-void format_commit_message(const struct commit *commit,
-                           const void *format, struct strbuf *sb)
-{
-       struct interp table[] = {
-               { "%H" },       /* commit hash */
-               { "%h" },       /* abbreviated commit hash */
-               { "%T" },       /* tree hash */
-               { "%t" },       /* abbreviated tree hash */
-               { "%P" },       /* parent hashes */
-               { "%p" },       /* abbreviated parent hashes */
-               { "%an" },      /* author name */
-               { "%ae" },      /* author email */
-               { "%ad" },      /* author date */
-               { "%aD" },      /* author date, RFC2822 style */
-               { "%ar" },      /* author date, relative */
-               { "%at" },      /* author date, UNIX timestamp */
-               { "%ai" },      /* author date, ISO 8601 */
-               { "%cn" },      /* committer name */
-               { "%ce" },      /* committer email */
-               { "%cd" },      /* committer date */
-               { "%cD" },      /* committer date, RFC2822 style */
-               { "%cr" },      /* committer date, relative */
-               { "%ct" },      /* committer date, UNIX timestamp */
-               { "%ci" },      /* committer date, ISO 8601 */
-               { "%e" },       /* encoding */
-               { "%s" },       /* subject */
-               { "%b" },       /* body */
-               { "%Cred" },    /* red */
-               { "%Cgreen" },  /* green */
-               { "%Cblue" },   /* blue */
-               { "%Creset" },  /* reset color */
-               { "%n" },       /* newline */
-               { "%m" },       /* left/right/bottom */
-       };
-       enum interp_index {
-               IHASH = 0, IHASH_ABBREV,
-               ITREE, ITREE_ABBREV,
-               IPARENTS, IPARENTS_ABBREV,
-               IAUTHOR_NAME, IAUTHOR_EMAIL,
-               IAUTHOR_DATE, IAUTHOR_DATE_RFC2822, IAUTHOR_DATE_RELATIVE,
-               IAUTHOR_TIMESTAMP, IAUTHOR_ISO8601,
-               ICOMMITTER_NAME, ICOMMITTER_EMAIL,
-               ICOMMITTER_DATE, ICOMMITTER_DATE_RFC2822,
-               ICOMMITTER_DATE_RELATIVE, ICOMMITTER_TIMESTAMP,
-               ICOMMITTER_ISO8601,
-               IENCODING,
-               ISUBJECT,
-               IBODY,
-               IRED, IGREEN, IBLUE, IRESET_COLOR,
-               INEWLINE,
-               ILEFT_RIGHT,
-       };
-       struct commit_list *p;
-       char parents[1024];
-       unsigned long len;
-       int i;
-       enum { HEADER, SUBJECT, BODY } state;
-       const char *msg = commit->buffer;
+struct chunk {
+       size_t off;
+       size_t len;
+};
 
-       if (ILEFT_RIGHT + 1 != ARRAY_SIZE(table))
-               die("invalid interp table!");
+struct format_commit_context {
+       const struct commit *commit;
+
+       /* These offsets are relative to the start of the commit message. */
+       int commit_header_parsed;
+       struct chunk subject;
+       struct chunk author;
+       struct chunk committer;
+       struct chunk encoding;
+       size_t body_off;
+
+       /* The following ones are relative to the result struct strbuf. */
+       struct chunk abbrev_commit_hash;
+       struct chunk abbrev_tree_hash;
+       struct chunk abbrev_parent_hashes;
+};
 
-       /* these are independent of the commit */
-       interp_set_entry(table, IRED, "\033[31m");
-       interp_set_entry(table, IGREEN, "\033[32m");
-       interp_set_entry(table, IBLUE, "\033[34m");
-       interp_set_entry(table, IRESET_COLOR, "\033[m");
-       interp_set_entry(table, INEWLINE, "\n");
+static int add_again(struct strbuf *sb, struct chunk *chunk)
+{
+       if (chunk->len) {
+               strbuf_adddup(sb, chunk->off, chunk->len);
+               return 1;
+       }
 
-       /* these depend on the commit */
-       if (!commit->object.parsed)
-               parse_object(commit->object.sha1);
-       interp_set_entry(table, IHASH, sha1_to_hex(commit->object.sha1));
-       interp_set_entry(table, IHASH_ABBREV,
-                       find_unique_abbrev(commit->object.sha1,
-                               DEFAULT_ABBREV));
-       interp_set_entry(table, ITREE, sha1_to_hex(commit->tree->object.sha1));
-       interp_set_entry(table, ITREE_ABBREV,
-                       find_unique_abbrev(commit->tree->object.sha1,
-                               DEFAULT_ABBREV));
-       interp_set_entry(table, ILEFT_RIGHT,
-                        (commit->object.flags & BOUNDARY)
-                        ? "-"
-                        : (commit->object.flags & SYMMETRIC_LEFT)
-                        ? "<"
-                        : ">");
-
-       parents[1] = 0;
-       for (i = 0, p = commit->parents;
-                       p && i < sizeof(parents) - 1;
-                       p = p->next)
-               i += snprintf(parents + i, sizeof(parents) - i - 1, " %s",
-                       sha1_to_hex(p->item->object.sha1));
-       interp_set_entry(table, IPARENTS, parents + 1);
-
-       parents[1] = 0;
-       for (i = 0, p = commit->parents;
-                       p && i < sizeof(parents) - 1;
-                       p = p->next)
-               i += snprintf(parents + i, sizeof(parents) - i - 1, " %s",
-                       find_unique_abbrev(p->item->object.sha1,
-                               DEFAULT_ABBREV));
-       interp_set_entry(table, IPARENTS_ABBREV, parents + 1);
+       /*
+        * We haven't seen this chunk before.  Our caller is surely
+        * going to add it the hard way now.  Remember the most likely
+        * start of the to-be-added chunk: the current end of the
+        * struct strbuf.
+        */
+       chunk->off = sb->len;
+       return 0;
+}
+
+static void parse_commit_header(struct format_commit_context *context)
+{
+       const char *msg = context->commit->buffer;
+       int i;
+       enum { HEADER, SUBJECT, BODY } state;
 
        for (i = 0, state = HEADER; msg[i] && state < BODY; i++) {
                int eol;
@@ -445,7 +405,8 @@ void format_commit_message(const struct commit *commit,
                        ; /* do nothing */
 
                if (state == SUBJECT) {
-                       table[ISUBJECT].value = xmemdupz(msg + i, eol - i);
+                       context->subject.off = i;
+                       context->subject.len = eol - i;
                        i = eol;
                }
                if (i == eol) {
@@ -453,29 +414,170 @@ void format_commit_message(const struct commit *commit,
                        /* strip empty lines */
                        while (msg[eol + 1] == '\n')
                                eol++;
-               } else if (!prefixcmp(msg + i, "author "))
-                       fill_person(table + IAUTHOR_NAME,
-                                       msg + i + 7, eol - i - 7);
-               else if (!prefixcmp(msg + i, "committer "))
-                       fill_person(table + ICOMMITTER_NAME,
-                                       msg + i + 10, eol - i - 10);
-               else if (!prefixcmp(msg + i, "encoding "))
-                       table[IENCODING].value =
-                               xmemdupz(msg + i + 9, eol - i - 9);
+               } else if (!prefixcmp(msg + i, "author ")) {
+                       context->author.off = i + 7;
+                       context->author.len = eol - i - 7;
+               } else if (!prefixcmp(msg + i, "committer ")) {
+                       context->committer.off = i + 10;
+                       context->committer.len = eol - i - 10;
+               } else if (!prefixcmp(msg + i, "encoding ")) {
+                       context->encoding.off = i + 9;
+                       context->encoding.len = eol - i - 9;
+               }
                i = eol;
        }
-       if (msg[i])
-               table[IBODY].value = xstrdup(msg + i);
+       context->body_off = i;
+       context->commit_header_parsed = 1;
+}
+
+static void format_commit_item(struct strbuf *sb, const char *placeholder,
+                               void *context)
+{
+       struct format_commit_context *c = context;
+       const struct commit *commit = c->commit;
+       const char *msg = commit->buffer;
+       struct commit_list *p;
+
+       /* these are independent of the commit */
+       switch (placeholder[0]) {
+       case 'C':
+               switch (placeholder[3]) {
+               case 'd':       /* red */
+                       strbuf_addstr(sb, "\033[31m");
+                       return;
+               case 'e':       /* green */
+                       strbuf_addstr(sb, "\033[32m");
+                       return;
+               case 'u':       /* blue */
+                       strbuf_addstr(sb, "\033[34m");
+                       return;
+               case 's':       /* reset color */
+                       strbuf_addstr(sb, "\033[m");
+                       return;
+               }
+       case 'n':               /* newline */
+               strbuf_addch(sb, '\n');
+               return;
+       }
 
-       len = interpolate(sb->buf + sb->len, strbuf_avail(sb),
-                               format, table, ARRAY_SIZE(table));
-       if (len > strbuf_avail(sb)) {
-               strbuf_grow(sb, len);
-               interpolate(sb->buf + sb->len, strbuf_avail(sb) + 1,
-                                       format, table, ARRAY_SIZE(table));
+       /* these depend on the commit */
+       if (!commit->object.parsed)
+               parse_object(commit->object.sha1);
+
+       switch (placeholder[0]) {
+       case 'H':               /* commit hash */
+               strbuf_addstr(sb, sha1_to_hex(commit->object.sha1));
+               return;
+       case 'h':               /* abbreviated commit hash */
+               if (add_again(sb, &c->abbrev_commit_hash))
+                       return;
+               strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1,
+                                                    DEFAULT_ABBREV));
+               c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
+               return;
+       case 'T':               /* tree hash */
+               strbuf_addstr(sb, sha1_to_hex(commit->tree->object.sha1));
+               return;
+       case 't':               /* abbreviated tree hash */
+               if (add_again(sb, &c->abbrev_tree_hash))
+                       return;
+               strbuf_addstr(sb, find_unique_abbrev(commit->tree->object.sha1,
+                                                    DEFAULT_ABBREV));
+               c->abbrev_tree_hash.len = sb->len - c->abbrev_tree_hash.off;
+               return;
+       case 'P':               /* parent hashes */
+               for (p = commit->parents; p; p = p->next) {
+                       if (p != commit->parents)
+                               strbuf_addch(sb, ' ');
+                       strbuf_addstr(sb, sha1_to_hex(p->item->object.sha1));
+               }
+               return;
+       case 'p':               /* abbreviated parent hashes */
+               if (add_again(sb, &c->abbrev_parent_hashes))
+                       return;
+               for (p = commit->parents; p; p = p->next) {
+                       if (p != commit->parents)
+                               strbuf_addch(sb, ' ');
+                       strbuf_addstr(sb, find_unique_abbrev(
+                                       p->item->object.sha1, DEFAULT_ABBREV));
+               }
+               c->abbrev_parent_hashes.len = sb->len -
+                                             c->abbrev_parent_hashes.off;
+               return;
+       case 'm':               /* left/right/bottom */
+               strbuf_addch(sb, (commit->object.flags & BOUNDARY)
+                                ? '-'
+                                : (commit->object.flags & SYMMETRIC_LEFT)
+                                ? '<'
+                                : '>');
+               return;
+       }
+
+       /* For the rest we have to parse the commit header. */
+       if (!c->commit_header_parsed)
+               parse_commit_header(c);
+
+       switch (placeholder[0]) {
+       case 's':
+               strbuf_add(sb, msg + c->subject.off, c->subject.len);
+               return;
+       case 'a':
+               format_person_part(sb, placeholder[1],
+                                  msg + c->author.off, c->author.len);
+               return;
+       case 'c':
+               format_person_part(sb, placeholder[1],
+                                  msg + c->committer.off, c->committer.len);
+               return;
+       case 'e':
+               strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
+               return;
+       case 'b':
+               strbuf_addstr(sb, msg + c->body_off);
+               return;
        }
-       strbuf_setlen(sb, sb->len + len);
-       interp_clear_table(table, ARRAY_SIZE(table));
+}
+
+void format_commit_message(const struct commit *commit,
+                           const void *format, struct strbuf *sb)
+{
+       const char *placeholders[] = {
+               "H",            /* commit hash */
+               "h",            /* abbreviated commit hash */
+               "T",            /* tree hash */
+               "t",            /* abbreviated tree hash */
+               "P",            /* parent hashes */
+               "p",            /* abbreviated parent hashes */
+               "an",           /* author name */
+               "ae",           /* author email */
+               "ad",           /* author date */
+               "aD",           /* author date, RFC2822 style */
+               "ar",           /* author date, relative */
+               "at",           /* author date, UNIX timestamp */
+               "ai",           /* author date, ISO 8601 */
+               "cn",           /* committer name */
+               "ce",           /* committer email */
+               "cd",           /* committer date */
+               "cD",           /* committer date, RFC2822 style */
+               "cr",           /* committer date, relative */
+               "ct",           /* committer date, UNIX timestamp */
+               "ci",           /* committer date, ISO 8601 */
+               "e",            /* encoding */
+               "s",            /* subject */
+               "b",            /* body */
+               "Cred",         /* red */
+               "Cgreen",       /* green */
+               "Cblue",        /* blue */
+               "Creset",       /* reset color */
+               "n",            /* newline */
+               "m",            /* left/right/bottom */
+               NULL
+       };
+       struct format_commit_context context;
+
+       memset(&context, 0, sizeof(context));
+       context.commit = commit;
+       strbuf_expand(sb, format, placeholders, format_commit_item, &context);
 }
 
 static void pp_header(enum cmit_fmt fmt,
index 3f6a602a534a7bd5dfea2fca4239af6f9ed5ceca..4bd650f9ba496786029791bc8a0a40b611bdeb63 100644 (file)
 #define TP_IDX_MAX      8
 
 struct throughput {
+       off_t curr_total;
+       off_t prev_total;
        struct timeval prev_tv;
-       off_t total;
-       unsigned long count;
-       unsigned long avg_bytes;
-       unsigned long last_bytes[TP_IDX_MAX];
+       unsigned int avg_bytes;
        unsigned int avg_misecs;
+       unsigned int last_bytes[TP_IDX_MAX];
        unsigned int last_misecs[TP_IDX_MAX];
        unsigned int idx;
        char display[32];
@@ -69,9 +69,9 @@ static void clear_progress_signal(void)
        progress_update = 0;
 }
 
-static int display(struct progress *progress, unsigned n, int done)
+static int display(struct progress *progress, unsigned n, const char *done)
 {
-       char *eol, *tp;
+       const char *eol, *tp;
 
        if (progress->delay) {
                if (!progress_update || --progress->delay)
@@ -90,7 +90,7 @@ static int display(struct progress *progress, unsigned n, int done)
 
        progress->last_value = n;
        tp = (progress->throughput) ? progress->throughput->display : "";
-       eol = done ? ", done.   \n" : "   \r";
+       eol = done ? done : "   \r";
        if (progress->total) {
                unsigned percent = n * 100 / progress->total;
                if (percent != progress->last_percent || progress_update) {
@@ -110,7 +110,31 @@ static int display(struct progress *progress, unsigned n, int done)
        return 0;
 }
 
-void display_throughput(struct progress *progress, unsigned long n)
+static void throughput_string(struct throughput *tp, off_t total,
+                             unsigned int rate)
+{
+       int l = sizeof(tp->display);
+       if (total > 1 << 30) {
+               l -= snprintf(tp->display, l, ", %u.%2.2u GiB",
+                             (int)(total >> 30),
+                             (int)(total & ((1 << 30) - 1)) / 10737419);
+       } else if (total > 1 << 20) {
+               l -= snprintf(tp->display, l, ", %u.%2.2u MiB",
+                             (int)(total >> 20),
+                             ((int)(total & ((1 << 20) - 1)) * 100) >> 20);
+       } else if (total > 1 << 10) {
+               l -= snprintf(tp->display, l, ", %u.%2.2u KiB",
+                             (int)(total >> 10),
+                             ((int)(total & ((1 << 10) - 1)) * 100) >> 10);
+       } else {
+               l -= snprintf(tp->display, l, ", %u bytes", (int)total);
+       }
+       if (rate)
+               snprintf(tp->display + sizeof(tp->display) - l, l,
+                        " | %u KiB/s", rate);
+}
+
+void display_throughput(struct progress *progress, off_t total)
 {
        struct throughput *tp;
        struct timeval tv;
@@ -124,13 +148,13 @@ void display_throughput(struct progress *progress, unsigned long n)
 
        if (!tp) {
                progress->throughput = tp = calloc(1, sizeof(*tp));
-               if (tp)
+               if (tp) {
+                       tp->prev_total = tp->curr_total = total;
                        tp->prev_tv = tv;
+               }
                return;
        }
-
-       tp->total += n;
-       tp->count += n;
+       tp->curr_total = total;
 
        /*
         * We have x = bytes and y = microsecs.  We want z = KiB/s:
@@ -151,47 +175,29 @@ void display_throughput(struct progress *progress, unsigned long n)
        misecs += (int)(tv.tv_usec - tp->prev_tv.tv_usec) / 977;
 
        if (misecs > 512) {
-               int l = sizeof(tp->display);
+               unsigned int count, rate;
+
+               count = total - tp->prev_total;
+               tp->prev_total = total;
                tp->prev_tv = tv;
-               tp->avg_bytes += tp->count;
+               tp->avg_bytes += count;
                tp->avg_misecs += misecs;
-
-               if (tp->total > 1 << 30) {
-                       l -= snprintf(tp->display, l, ", %u.%2.2u GiB",
-                                     (int)(tp->total >> 30),
-                                     (int)(tp->total & ((1 << 30) - 1)) / 10737419);
-               } else if (tp->total > 1 << 20) {
-                       l -= snprintf(tp->display, l, ", %u.%2.2u MiB",
-                                     (int)(tp->total >> 20),
-                                     ((int)(tp->total & ((1 << 20) - 1))
-                                      * 100) >> 20);
-               } else if (tp->total > 1 << 10) {
-                       l -= snprintf(tp->display, l, ", %u.%2.2u KiB",
-                                     (int)(tp->total >> 10),
-                                     ((int)(tp->total & ((1 << 10) - 1))
-                                      * 100) >> 10);
-               } else {
-                       l -= snprintf(tp->display, l, ", %u bytes",
-                                     (int)tp->total);
-               }
-               snprintf(tp->display + sizeof(tp->display) - l, l,
-                        " | %lu KiB/s", tp->avg_bytes / tp->avg_misecs);
-
+               rate = tp->avg_bytes / tp->avg_misecs;
                tp->avg_bytes -= tp->last_bytes[tp->idx];
                tp->avg_misecs -= tp->last_misecs[tp->idx];
-               tp->last_bytes[tp->idx] = tp->count;
+               tp->last_bytes[tp->idx] = count;
                tp->last_misecs[tp->idx] = misecs;
                tp->idx = (tp->idx + 1) % TP_IDX_MAX;
-               tp->count = 0;
 
+               throughput_string(tp, total, rate);
                if (progress->last_value != -1 && progress_update)
-                       display(progress, progress->last_value, 0);
+                       display(progress, progress->last_value, NULL);
        }
 }
 
 int display_progress(struct progress *progress, unsigned n)
 {
-       return progress ? display(progress, n, 0) : 0;
+       return progress ? display(progress, n, NULL) : 0;
 }
 
 struct progress *start_progress_delay(const char *title, unsigned total,
@@ -220,6 +226,11 @@ struct progress *start_progress(const char *title, unsigned total)
 }
 
 void stop_progress(struct progress **p_progress)
+{
+       stop_progress_msg(p_progress, "done");
+}
+
+void stop_progress_msg(struct progress **p_progress, const char *msg)
 {
        struct progress *progress = *p_progress;
        if (!progress)
@@ -227,8 +238,16 @@ void stop_progress(struct progress **p_progress)
        *p_progress = NULL;
        if (progress->last_value != -1) {
                /* Force the last update */
+               char buf[strlen(msg) + 5];
+               struct throughput *tp = progress->throughput;
+               if (tp) {
+                       unsigned int rate = !tp->avg_misecs ? 0 :
+                                       tp->avg_bytes / tp->avg_misecs;
+                       throughput_string(tp, tp->curr_total, rate);
+               }
                progress_update = 1;
-               display(progress, progress->last_value, 1);
+               sprintf(buf, ", %s.\n", msg);
+               display(progress, progress->last_value, buf);
        }
        clear_progress_signal();
        free(progress->throughput);
index 61cb68dfa512bb3668d7e6060262041937aa82d3..611e4c4d42d8d1164add09f926ad5b2ce088db5e 100644 (file)
@@ -3,11 +3,12 @@
 
 struct progress;
 
-void display_throughput(struct progress *progress, unsigned long n);
+void display_throughput(struct progress *progress, off_t total);
 int display_progress(struct progress *progress, unsigned n);
 struct progress *start_progress(const char *title, unsigned total);
 struct progress *start_progress_delay(const char *title, unsigned total,
                                       unsigned percent_treshold, unsigned delay);
 void stop_progress(struct progress **progress);
+void stop_progress_msg(struct progress **progress, const char *msg);
 
 #endif
index 056b322fb0c83aeda378f548e13f84d4a65c1e29..7db55883d65fd28c2eaa291b5688273532988d88 100644 (file)
@@ -194,11 +194,12 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
 }
 
 int ie_match_stat(struct index_state *istate,
-                 struct cache_entry *ce, struct stat *st, int options)
+                 struct cache_entry *ce, struct stat *st,
+                 unsigned int options)
 {
        unsigned int changed;
-       int ignore_valid = options & 01;
-       int assume_racy_is_modified = options & 02;
+       int ignore_valid = options & CE_MATCH_IGNORE_VALID;
+       int assume_racy_is_modified = options & CE_MATCH_RACY_IS_DIRTY;
 
        /*
         * If it's marked as always valid in the index, it's
@@ -238,10 +239,11 @@ int ie_match_stat(struct index_state *istate,
 }
 
 int ie_modified(struct index_state *istate,
-               struct cache_entry *ce, struct stat *st, int really)
+               struct cache_entry *ce, struct stat *st, unsigned int options)
 {
        int changed, changed_fs;
-       changed = ie_match_stat(istate, ce, st, really);
+
+       changed = ie_match_stat(istate, ce, st, options);
        if (!changed)
                return 0;
        /*
@@ -387,6 +389,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose)
        int size, namelen, pos;
        struct stat st;
        struct cache_entry *ce;
+       unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY;
 
        if (lstat(path, &st))
                die("%s: unable to stat (%s)", path, strerror(errno));
@@ -421,7 +424,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose)
        pos = index_name_pos(istate, ce->name, namelen);
        if (0 <= pos &&
            !ce_stage(istate->cache[pos]) &&
-           !ie_modified(istate, istate->cache[pos], &st, 1)) {
+           !ie_match_stat(istate, istate->cache[pos], &st, ce_option)) {
                /* Nothing changed, really */
                free(ce);
                return 0;
@@ -783,11 +786,13 @@ int add_index_entry(struct index_state *istate, struct cache_entry *ce, int opti
  * to link up the stat cache details with the proper files.
  */
 static struct cache_entry *refresh_cache_ent(struct index_state *istate,
-                                            struct cache_entry *ce, int really, int *err)
+                                            struct cache_entry *ce,
+                                            unsigned int options, int *err)
 {
        struct stat st;
        struct cache_entry *updated;
        int changed, size;
+       int ignore_valid = options & CE_MATCH_IGNORE_VALID;
 
        if (lstat(ce->name, &st) < 0) {
                if (err)
@@ -795,16 +800,23 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
                return NULL;
        }
 
-       changed = ie_match_stat(istate, ce, &st, really);
+       changed = ie_match_stat(istate, ce, &st, options);
        if (!changed) {
-               if (really && assume_unchanged &&
+               /*
+                * The path is unchanged.  If we were told to ignore
+                * valid bit, then we did the actual stat check and
+                * found that the entry is unmodified.  If the entry
+                * is not marked VALID, this is the place to mark it
+                * valid again, under "assume unchanged" mode.
+                */
+               if (ignore_valid && assume_unchanged &&
                    !(ce->ce_flags & htons(CE_VALID)))
                        ; /* mark this one VALID again */
                else
                        return ce;
        }
 
-       if (ie_modified(istate, ce, &st, really)) {
+       if (ie_modified(istate, ce, &st, options)) {
                if (err)
                        *err = EINVAL;
                return NULL;
@@ -815,13 +827,14 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
        memcpy(updated, ce, size);
        fill_stat_cache_info(updated, &st);
 
-       /* In this case, if really is not set, we should leave
-        * CE_VALID bit alone.  Otherwise, paths marked with
-        * --no-assume-unchanged (i.e. things to be edited) will
-        * reacquire CE_VALID bit automatically, which is not
-        * really what we want.
+       /*
+        * If ignore_valid is not set, we should leave CE_VALID bit
+        * alone.  Otherwise, paths marked with --no-assume-unchanged
+        * (i.e. things to be edited) will reacquire CE_VALID bit
+        * automatically, which is not really what we want.
         */
-       if (!really && assume_unchanged && !(ce->ce_flags & htons(CE_VALID)))
+       if (!ignore_valid && assume_unchanged &&
+           !(ce->ce_flags & htons(CE_VALID)))
                updated->ce_flags &= ~htons(CE_VALID);
 
        return updated;
@@ -835,6 +848,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
        int allow_unmerged = (flags & REFRESH_UNMERGED) != 0;
        int quiet = (flags & REFRESH_QUIET) != 0;
        int not_new = (flags & REFRESH_IGNORE_MISSING) != 0;
+       unsigned int options = really ? CE_MATCH_IGNORE_VALID : 0;
 
        for (i = 0; i < istate->cache_nr; i++) {
                struct cache_entry *ce, *new;
@@ -856,7 +870,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
                if (pathspec && !match_pathspec(pathspec, ce->name, strlen(ce->name), 0, seen))
                        continue;
 
-               new = refresh_cache_ent(istate, ce, really, &cache_errno);
+               new = refresh_cache_ent(istate, ce, options, &cache_errno);
                if (new == ce)
                        continue;
                if (!new) {
diff --git a/refs.c b/refs.c
index aff02cd09d4e40b04f6764a6f6ab43240b736a08..ae532540cf2592aee2be7610ac811082c3a9b6be 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -580,18 +580,6 @@ int for_each_remote_ref(each_ref_fn fn, void *cb_data)
        return do_for_each_ref("refs/remotes/", fn, 13, cb_data);
 }
 
-/* NEEDSWORK: This is only used by ssh-upload and it should go; the
- * caller should do resolve_ref or read_ref like everybody else.  Or
- * maybe everybody else should use get_ref_sha1() instead of doing
- * read_ref().
- */
-int get_ref_sha1(const char *ref, unsigned char *sha1)
-{
-       if (check_ref_format(ref))
-               return -1;
-       return read_ref(mkpath("refs/%s", ref), sha1);
-}
-
 /*
  * Make sure "ref" is something reasonable to have under ".git/refs/";
  * We do not like it if:
diff --git a/refs.h b/refs.h
index 6eb98a4caf150776c26fb04699133b1a976d0122..9dc8aa01d181dbdbf1c8f643a1bd7de1d311ffa3 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -26,9 +26,6 @@ extern int for_each_remote_ref(each_ref_fn, void *);
 
 extern int peel_ref(const char *, unsigned char *);
 
-/** Reads the refs file specified into sha1 **/
-extern int get_ref_sha1(const char *ref, unsigned char *sha1);
-
 /** Locks a "refs/" ref returning the lock on success and NULL on failure. **/
 extern struct ref_lock *lock_ref_sha1(const char *ref, const unsigned char *old_sha1);
 
index e8650c35a7e48a24d185e123eedb9b336d6bc799..2a59035192baec8265acccf8b5d00aa7b2db4dd7 100644 (file)
@@ -10,6 +10,8 @@
 #include "reflog-walk.h"
 #include "patch-ids.h"
 
+volatile show_early_output_fn_t show_early_output;
+
 static char *path_name(struct name_path *path, const char *name)
 {
        struct name_path *p;
@@ -257,7 +259,7 @@ static void file_add_remove(struct diff_options *options,
        }
        tree_difference = diff;
        if (tree_difference == REV_TREE_DIFFERENT)
-               options->has_changes = 1;
+               DIFF_OPT_SET(options, HAS_CHANGES);
 }
 
 static void file_change(struct diff_options *options,
@@ -267,7 +269,7 @@ static void file_change(struct diff_options *options,
                 const char *base, const char *path)
 {
        tree_difference = REV_TREE_DIFFERENT;
-       options->has_changes = 1;
+       DIFF_OPT_SET(options, HAS_CHANGES);
 }
 
 static int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree *t2)
@@ -277,7 +279,7 @@ static int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree
        if (!t2)
                return REV_TREE_DIFFERENT;
        tree_difference = REV_TREE_SAME;
-       revs->pruning.has_changes = 0;
+       DIFF_OPT_CLR(&revs->pruning, HAS_CHANGES);
        if (diff_tree_sha1(t1->object.sha1, t2->object.sha1, "",
                           &revs->pruning) < 0)
                return REV_TREE_DIFFERENT;
@@ -301,7 +303,7 @@ static int rev_same_tree_as_empty(struct rev_info *revs, struct tree *t1)
        init_tree_desc(&empty, "", 0);
 
        tree_difference = REV_TREE_SAME;
-       revs->pruning.has_changes = 0;
+       DIFF_OPT_CLR(&revs->pruning, HAS_CHANGES);
        retval = diff_tree(&empty, &real, "", &revs->pruning);
        free(tree);
 
@@ -313,15 +315,28 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
        struct commit_list **pp, *parent;
        int tree_changed = 0, tree_same = 0;
 
+       /*
+        * If we don't do pruning, everything is interesting
+        */
+       if (!revs->prune)
+               return;
+
        if (!commit->tree)
                return;
 
        if (!commit->parents) {
-               if (!rev_same_tree_as_empty(revs, commit->tree))
-                       commit->object.flags |= TREECHANGE;
+               if (rev_same_tree_as_empty(revs, commit->tree))
+                       commit->object.flags |= TREESAME;
                return;
        }
 
+       /*
+        * Normal non-merge commit? If we don't want to make the
+        * history dense, we consider it always to be a change..
+        */
+       if (!revs->dense && !commit->parents->next)
+               return;
+
        pp = &commit->parents;
        while ((parent = *pp) != NULL) {
                struct commit *p = parent->item;
@@ -345,6 +360,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
                        }
                        parent->next = NULL;
                        commit->parents = parent;
+                       commit->object.flags |= TREESAME;
                        return;
 
                case REV_TREE_NEW:
@@ -373,7 +389,8 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
                die("bad tree compare for commit %s", sha1_to_hex(commit->object.sha1));
        }
        if (tree_changed && !tree_same)
-               commit->object.flags |= TREECHANGE;
+               return;
+       commit->object.flags |= TREESAME;
 }
 
 static int add_parents_to_list(struct rev_info *revs, struct commit *commit, struct commit_list **list)
@@ -420,8 +437,7 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit, str
         * simplify the commit history and find the parent
         * that has no differences in the path set if one exists.
         */
-       if (revs->prune_fn)
-               revs->prune_fn(revs, commit);
+       try_to_simplify_commit(revs, commit);
 
        if (revs->no_walk)
                return 0;
@@ -540,6 +556,7 @@ static int limit_list(struct rev_info *revs)
                struct commit_list *entry = list;
                struct commit *commit = list->item;
                struct object *obj = &commit->object;
+               show_early_output_fn_t show;
 
                list = list->next;
                free(entry);
@@ -557,6 +574,13 @@ static int limit_list(struct rev_info *revs)
                if (revs->min_age != -1 && (commit->date > revs->min_age))
                        continue;
                p = &commit_list_insert(commit, p)->next;
+
+               show = show_early_output;
+               if (!show)
+                       continue;
+
+               show(revs, newlist);
+               show_early_output = NULL;
        }
        if (revs->cherry_pick)
                cherry_pick_list(newlist, revs);
@@ -669,8 +693,8 @@ void init_revisions(struct rev_info *revs, const char *prefix)
        revs->abbrev = DEFAULT_ABBREV;
        revs->ignore_merges = 1;
        revs->simplify_history = 1;
-       revs->pruning.recursive = 1;
-       revs->pruning.quiet = 1;
+       DIFF_OPT_SET(&revs->pruning, RECURSIVE);
+       DIFF_OPT_SET(&revs->pruning, QUIET);
        revs->pruning.add_remove = file_add_remove;
        revs->pruning.change = file_change;
        revs->lifo = 1;
@@ -681,12 +705,6 @@ void init_revisions(struct rev_info *revs, const char *prefix)
        revs->skip_count = -1;
        revs->max_count = -1;
 
-       revs->prune_fn = NULL;
-       revs->prune_data = NULL;
-
-       revs->topo_setter = topo_sort_default_setter;
-       revs->topo_getter = topo_sort_default_getter;
-
        revs->commit_format = CMIT_FMT_DEFAULT;
 
        diff_setup(&revs->diffopt);
@@ -1001,6 +1019,18 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
                                revs->topo_order = 1;
                                continue;
                        }
+                       if (!prefixcmp(arg, "--early-output")) {
+                               int count = 100;
+                               switch (arg[14]) {
+                               case '=':
+                                       count = atoi(arg+15);
+                                       /* Fallthrough */
+                               case 0:
+                                       revs->topo_order = 1;
+                                       revs->early_output = count;
+                                       continue;
+                               }
+                       }
                        if (!strcmp(arg, "--parents")) {
                                revs->parents = 1;
                                continue;
@@ -1061,13 +1091,13 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
                        }
                        if (!strcmp(arg, "-r")) {
                                revs->diff = 1;
-                               revs->diffopt.recursive = 1;
+                               DIFF_OPT_SET(&revs->diffopt, RECURSIVE);
                                continue;
                        }
                        if (!strcmp(arg, "-t")) {
                                revs->diff = 1;
-                               revs->diffopt.recursive = 1;
-                               revs->diffopt.tree_in_recursive = 1;
+                               DIFF_OPT_SET(&revs->diffopt, RECURSIVE);
+                               DIFF_OPT_SET(&revs->diffopt, TREE_IN_RECURSIVE);
                                continue;
                        }
                        if (!strcmp(arg, "-m")) {
@@ -1249,7 +1279,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
                revs->diff = 1;
 
        /* Pickaxe and rename following needs diffs */
-       if (revs->diffopt.pickaxe || revs->diffopt.follow_renames)
+       if (revs->diffopt.pickaxe || DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES))
                revs->diff = 1;
 
        if (revs->topo_order)
@@ -1258,8 +1288,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
        if (revs->prune_data) {
                diff_tree_setup_paths(revs->prune_data, &revs->pruning);
                /* Can't prune commits with rename following: the paths change.. */
-               if (!revs->diffopt.follow_renames)
-                       revs->prune_fn = try_to_simplify_commit;
+               if (!DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES))
+                       revs->prune = 1;
                if (!revs->full_diff)
                        diff_tree_setup_paths(revs->prune_data, &revs->diffopt);
        }
@@ -1310,9 +1340,7 @@ int prepare_revision_walk(struct rev_info *revs)
                if (limit_list(revs) < 0)
                        return -1;
        if (revs->topo_order)
-               sort_in_topological_order_fn(&revs->commits, revs->lifo,
-                                            revs->topo_setter,
-                                            revs->topo_getter);
+               sort_in_topological_order(&revs->commits, revs->lifo);
        return 0;
 }
 
@@ -1331,7 +1359,9 @@ static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp
                                return rewrite_one_error;
                if (p->parents && p->parents->next)
                        return rewrite_one_ok;
-               if (p->object.flags & (TREECHANGE | UNINTERESTING))
+               if (p->object.flags & UNINTERESTING)
+                       return rewrite_one_ok;
+               if (!(p->object.flags & TREESAME))
                        return rewrite_one_ok;
                if (!p->parents)
                        return rewrite_one_noparents;
@@ -1388,6 +1418,36 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
                           commit->buffer, strlen(commit->buffer));
 }
 
+enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit)
+{
+       if (commit->object.flags & SHOWN)
+               return commit_ignore;
+       if (revs->unpacked && has_sha1_pack(commit->object.sha1, revs->ignore_packed))
+               return commit_ignore;
+       if (commit->object.flags & UNINTERESTING)
+               return commit_ignore;
+       if (revs->min_age != -1 && (commit->date > revs->min_age))
+               return commit_ignore;
+       if (revs->no_merges && commit->parents && commit->parents->next)
+               return commit_ignore;
+       if (!commit_match(commit, revs))
+               return commit_ignore;
+       if (revs->prune && revs->dense) {
+               /* Commit without changes? */
+               if (commit->object.flags & TREESAME) {
+                       /* drop merges unless we want parenthood */
+                       if (!revs->parents)
+                               return commit_ignore;
+                       /* non-merge - always ignore it */
+                       if (!commit->parents || !commit->parents->next)
+                               return commit_ignore;
+               }
+               if (revs->parents && rewrite_parents(revs, commit) < 0)
+                       return commit_error;
+       }
+       return commit_show;
+}
+
 static struct commit *get_revision_1(struct rev_info *revs)
 {
        if (!revs->commits)
@@ -1415,36 +1475,15 @@ static struct commit *get_revision_1(struct rev_info *revs)
                        if (add_parents_to_list(revs, commit, &revs->commits) < 0)
                                return NULL;
                }
-               if (commit->object.flags & SHOWN)
-                       continue;
 
-               if (revs->unpacked && has_sha1_pack(commit->object.sha1,
-                                                   revs->ignore_packed))
-                   continue;
-
-               if (commit->object.flags & UNINTERESTING)
-                       continue;
-               if (revs->min_age != -1 && (commit->date > revs->min_age))
+               switch (simplify_commit(revs, commit)) {
+               case commit_ignore:
                        continue;
-               if (revs->no_merges &&
-                   commit->parents && commit->parents->next)
-                       continue;
-               if (!commit_match(commit, revs))
-                       continue;
-               if (revs->prune_fn && revs->dense) {
-                       /* Commit without changes? */
-                       if (!(commit->object.flags & TREECHANGE)) {
-                               /* drop merges unless we want parenthood */
-                               if (!revs->parents)
-                                       continue;
-                               /* non-merge - always ignore it */
-                               if (!commit->parents || !commit->parents->next)
-                                       continue;
-                       }
-                       if (revs->parents && rewrite_parents(revs, commit) < 0)
-                               return NULL;
+               case commit_error:
+                       return NULL;
+               default:
+                       return commit;
                }
-               return commit;
        } while (revs->commits);
        return NULL;
 }
index 98a0a8f3fa9db4b2302dd31a4867ae824831b25c..992e1e9dd57eac528c3ecaf09987593d525da611 100644 (file)
@@ -3,19 +3,18 @@
 
 #define SEEN           (1u<<0)
 #define UNINTERESTING   (1u<<1)
-#define TREECHANGE     (1u<<2)
+#define TREESAME       (1u<<2)
 #define SHOWN          (1u<<3)
 #define TMP_MARK       (1u<<4) /* for isolated cases; clean after use */
 #define BOUNDARY       (1u<<5)
 #define CHILD_SHOWN    (1u<<6)
 #define ADDED          (1u<<7) /* Parents already parsed and added? */
 #define SYMMETRIC_LEFT (1u<<8)
+#define TOPOSORT       (1u<<9) /* In the active toposort list.. */
 
 struct rev_info;
 struct log_info;
 
-typedef void (prune_fn_t)(struct rev_info *revs, struct commit *commit);
-
 struct rev_info {
        /* Starting list */
        struct commit_list *commits;
@@ -27,10 +26,11 @@ struct rev_info {
        /* Basic information */
        const char *prefix;
        void *prune_data;
-       prune_fn_t *prune_fn;
+       unsigned int early_output;
 
        /* Traversal flags */
        unsigned int    dense:1,
+                       prune:1,
                        no_merges:1,
                        no_walk:1,
                        remove_empty_trees:1,
@@ -96,9 +96,6 @@ struct rev_info {
        struct diff_options diffopt;
        struct diff_options pruning;
 
-       topo_sort_set_fn_t topo_setter;
-       topo_sort_get_fn_t topo_getter;
-
        struct reflog_walk_info *reflog_info;
 };
 
@@ -107,6 +104,8 @@ struct rev_info {
 #define REV_TREE_DIFFERENT     2
 
 /* revision.c */
+typedef void (*show_early_output_fn_t)(struct rev_info *, struct commit_list *);
+volatile show_early_output_fn_t show_early_output;
 
 extern void init_revisions(struct rev_info *revs, const char *prefix);
 extern int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def);
@@ -131,4 +130,12 @@ extern void add_object(struct object *obj,
 
 extern void add_pending_object(struct rev_info *revs, struct object *obj, const char *name);
 
+enum commit_action {
+       commit_ignore,
+       commit_show,
+       commit_error
+};
+
+extern enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit);
+
 #endif
index d99a6c4ea7c776bec717c9952f77db7fa9a69c21..476d00c2182e3af82a0cfe495c61c9df1eb44d26 100644 (file)
@@ -41,7 +41,7 @@ int start_command(struct child_process *cmd)
                cmd->close_out = 1;
        }
 
-       need_err = cmd->err < 0;
+       need_err = !cmd->no_stderr && cmd->err < 0;
        if (need_err) {
                if (pipe(fderr) < 0) {
                        if (need_in)
@@ -87,7 +87,9 @@ int start_command(struct child_process *cmd)
                        close(cmd->out);
                }
 
-               if (need_err) {
+               if (cmd->no_stderr)
+                       dup_devnull(2);
+               else if (need_err) {
                        dup2(fderr[1], 2);
                        close_pair(fderr);
                }
index 94e1e9d516887d818f99f8f6d6b3ded3f3be6d6f..1fc781d7668468f9e74bd430b7569dc040440ba8 100644 (file)
@@ -23,6 +23,7 @@ struct child_process {
        unsigned close_out:1;
        unsigned no_stdin:1;
        unsigned no_stdout:1;
+       unsigned no_stderr:1;
        unsigned git_cmd:1; /* if this is to be git sub-command */
        unsigned stdout_to_stderr:1;
 };
index ab8a1e990db39155efc624ca99e85c1cf8eaefa9..756bbc28d71448781294151cbacd30f68b2bb97b 100644 (file)
  * stream, aka "verbose").  A message over band #3 is a signal that
  * the remote died unexpectedly.  A flush() concludes the stream.
  */
+
+#define PREFIX "remote:"
+#define SUFFIX "\033[K"  /* change to "        " if ANSI sequences don't work */
+
 int recv_sideband(const char *me, int in_stream, int out, int err)
 {
-       char buf[7 + LARGE_PACKET_MAX + 1];
-       strcpy(buf, "remote:");
+       unsigned pf = strlen(PREFIX);
+       unsigned sf = strlen(SUFFIX);
+       char buf[pf + LARGE_PACKET_MAX + sf + 1];
+       memcpy(buf, PREFIX, pf);
        while (1) {
                int band, len;
-               len = packet_read_line(in_stream, buf+7, LARGE_PACKET_MAX);
+               len = packet_read_line(in_stream, buf + pf, LARGE_PACKET_MAX);
                if (len == 0)
                        break;
                if (len < 1) {
@@ -25,35 +31,52 @@ int recv_sideband(const char *me, int in_stream, int out, int err)
                        safe_write(err, buf, len);
                        return SIDEBAND_PROTOCOL_ERROR;
                }
-               band = buf[7] & 0xff;
+               band = buf[pf] & 0xff;
                len--;
                switch (band) {
                case 3:
-                       buf[7] = ' ';
-                       buf[8+len] = '\n';
-                       safe_write(err, buf, 8+len+1);
+                       buf[pf] = ' ';
+                       buf[pf+1+len] = '\n';
+                       safe_write(err, buf, pf+1+len+1);
                        return SIDEBAND_REMOTE_ERROR;
                case 2:
-                       buf[7] = ' ';
-                       len += 8;
+                       buf[pf] = ' ';
+                       len += pf+1;
                        while (1) {
-                               int brk = 8;
+                               int brk = pf+1;
+
+                               /* Break the buffer into separate lines. */
                                while (brk < len) {
                                        brk++;
                                        if (buf[brk-1] == '\n' ||
                                            buf[brk-1] == '\r')
                                                break;
                                }
-                               safe_write(err, buf, brk);
+
+                               /*
+                                * Let's insert a suffix to clear the end
+                                * of the screen line, but only if current
+                                * line data actually contains something.
+                                */
+                               if (brk > pf+1 + 1) {
+                                       char save[sf];
+                                       memcpy(save, buf + brk, sf);
+                                       buf[brk + sf - 1] = buf[brk - 1];
+                                       memcpy(buf + brk - 1, SUFFIX, sf);
+                                       safe_write(err, buf, brk + sf);
+                                       memcpy(buf + brk, save, sf);
+                               } else
+                                       safe_write(err, buf, brk);
+
                                if (brk < len) {
-                                       memmove(buf + 8, buf + brk, len - brk);
-                                       len = len - brk + 8;
+                                       memmove(buf + pf+1, buf + brk, len - brk);
+                                       len = len - brk + pf+1;
                                } else
                                        break;
                        }
                        continue;
                case 1:
-                       safe_write(out, buf+8, len);
+                       safe_write(out, buf + pf+1, len);
                        continue;
                default:
                        len = sprintf(buf,
index cbada946c4e73a403cb2d237f8aebfcda5c88ac4..b9b194b3200e950cfdb3c696d92ece0657e9d344 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -106,6 +106,13 @@ void strbuf_add(struct strbuf *sb, const void *data, size_t len)
        strbuf_setlen(sb, sb->len + len);
 }
 
+void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
+{
+       strbuf_grow(sb, len);
+       memcpy(sb->buf + sb->len, sb->buf + pos, len);
+       strbuf_setlen(sb, sb->len + len);
+}
+
 void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
 {
        int len;
@@ -130,6 +137,30 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
        strbuf_setlen(sb, sb->len + len);
 }
 
+void strbuf_expand(struct strbuf *sb, const char *format,
+                   const char **placeholders, expand_fn_t fn, void *context)
+{
+       for (;;) {
+               const char *percent, **p;
+
+               percent = strchrnul(format, '%');
+               strbuf_add(sb, format, percent - format);
+               if (!*percent)
+                       break;
+               format = percent + 1;
+
+               for (p = placeholders; *p; p++) {
+                       if (!prefixcmp(format, *p))
+                               break;
+               }
+               if (*p) {
+                       fn(sb, *p, context);
+                       format += strlen(*p);
+               } else
+                       strbuf_addch(sb, '%');
+       }
+}
+
 size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
 {
        size_t res;
index cd7f295b65237aaa1f4e4031482af43cbe9d9115..13919123dc5261e7b8e4a4fdfc696f2355482b6c 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
@@ -101,6 +101,10 @@ static inline void strbuf_addstr(struct strbuf *sb, const char *s) {
 static inline void strbuf_addbuf(struct strbuf *sb, struct strbuf *sb2) {
        strbuf_add(sb, sb2->buf, sb2->len);
 }
+extern void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len);
+
+typedef void (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context);
+extern void strbuf_expand(struct strbuf *sb, const char *format, const char **placeholders, expand_fn_t fn, void *context);
 
 __attribute__((format(printf,2,3)))
 extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
diff --git a/t/t2008-checkout-subdir.sh b/t/t2008-checkout-subdir.sh
new file mode 100755 (executable)
index 0000000..f78945e
--- /dev/null
@@ -0,0 +1,82 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 David Symonds
+
+test_description='git checkout from subdirectories'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+
+       echo "base" > file0 &&
+       git add file0 &&
+       mkdir dir1 &&
+       echo "hello" > dir1/file1 &&
+       git add dir1/file1 &&
+       mkdir dir2 &&
+       echo "bonjour" > dir2/file2 &&
+       git add dir2/file2 &&
+       test_tick &&
+       git commit -m "populate tree"
+
+'
+
+test_expect_success 'remove and restore with relative path' '
+
+       (
+               cd dir1 &&
+               rm ../file0 &&
+               git checkout HEAD -- ../file0 &&
+               test "base" = "$(cat ../file0)" &&
+               rm ../dir2/file2 &&
+               git checkout HEAD -- ../dir2/file2 &&
+               test "bonjour" = "$(cat ../dir2/file2)" &&
+               rm ../file0 ./file1 &&
+               git checkout HEAD -- .. &&
+               test "base" = "$(cat ../file0)" &&
+               test "hello" = "$(cat file1)"
+       )
+
+'
+
+test_expect_success 'checkout with empty prefix' '
+
+       rm file0 &&
+       git checkout HEAD -- file0 &&
+       test "base" = "$(cat file0)"
+
+'
+
+test_expect_success 'checkout with simple prefix' '
+
+       rm dir1/file1 &&
+       git checkout HEAD -- dir1 &&
+       test "hello" = "$(cat dir1/file1)" &&
+       rm dir1/file1 &&
+       git checkout HEAD -- dir1/file1 &&
+       test "hello" = "$(cat dir1/file1)"
+
+'
+
+# This is not expected to work as ls-files was not designed
+# to deal with such.  Enable it when ls-files is updated.
+: test_expect_success 'checkout with complex relative path' '
+
+       rm file1 &&
+       git checkout HEAD -- ../dir1/../dir1/file1 && test -f ./file1
+
+'
+
+test_expect_failure 'relative path outside tree should fail' \
+       'git checkout HEAD -- ../../Makefile'
+
+test_expect_failure 'incorrect relative path to file should fail (1)' \
+       'git checkout HEAD -- ../file0'
+
+test_expect_failure 'incorrect relative path should fail (2)' \
+       '( cd dir1 && git checkout HEAD -- ./file0 )'
+
+test_expect_failure 'incorrect relative path should fail (3)' \
+       '( cd dir1 && git checkout HEAD -- ../../file0 )'
+
+test_done
index eb1ced3c371ecaeab9d0dc14be888bf7df110483..24f892f79386478fd5f1162654cb9b72d940bbe4 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='git add -u with path limiting
+test_description='git add -u
 
 This test creates a working tree state with three files:
 
@@ -9,7 +9,10 @@ This test creates a working tree state with three files:
   dir/other (untracked)
 
 and issues a git add -u with path limiting on "dir" to add
-only the updates to dir/sub.'
+only the updates to dir/sub.
+
+Also tested are "git add -u" without limiting, and "git add -u"
+without contents changes.'
 
 . ./test-lib.sh
 
@@ -85,4 +88,27 @@ test_expect_success 'replace a file with a symlink' '
 
 '
 
+test_expect_success 'add everything changed' '
+
+       git add -u &&
+       test -z "$(git diff-files)"
+
+'
+
+test_expect_success 'touch and then add -u' '
+
+       touch check &&
+       git add -u &&
+       test -z "$(git diff-files)"
+
+'
+
+test_expect_success 'touch and then add explicitly' '
+
+       touch check &&
+       git add check &&
+       test -z "$(git diff-files)"
+
+'
+
 test_done
index 0779aaa9aba16f0f8502505b4df5cc49cfe8af82..7b7d07269ae35f56dd02a223f350ae0da97bae85 100755 (executable)
@@ -48,9 +48,14 @@ test_expect_success 'reference merge' '
        git merge -s recursive "reference merge" HEAD master
 '
 
+PRE_REBASE=$(git rev-parse test-rebase)
 test_expect_success rebase '
        git checkout test-rebase &&
-       git rebase --merge master
+       GIT_TRACE=1 git rebase --merge master
+'
+
+test_expect_success 'test-rebase@{1} is pre rebase' '
+       test $PRE_REBASE = $(git rev-parse test-rebase@{1})
 '
 
 test_expect_success 'merge and rebase should match' '
index eab053c3e0e1cbe82bc7824d43109ba56acdb54d..2ee5a00ea794e31946ee3228bc66ecc8e7d3b38f 100755 (executable)
@@ -39,6 +39,19 @@ test_expect_success 'rebase --skip with am -3' '
        git reset --hard HEAD &&
        git rebase --skip
        '
+
+test_expect_success 'rebase moves back to skip-reference' '
+       test refs/heads/skip-reference = $(git symbolic-ref HEAD) &&
+       git branch post-rebase &&
+       git reset --hard pre-rebase &&
+       ! git rebase master &&
+       echo "hello" > hello &&
+       git add hello &&
+       git rebase --continue &&
+       test refs/heads/skip-reference = $(git symbolic-ref HEAD) &&
+       git reset --hard post-rebase
+'
+
 test_expect_success 'checkout skip-merge' 'git checkout -f skip-merge'
 
 test_expect_failure 'rebase with --merge' 'git rebase --merge master'
@@ -51,6 +64,10 @@ test_expect_success 'rebase --skip with --merge' '
 test_expect_success 'merge and reference trees equal' \
        'test -z "`git diff-tree skip-merge skip-reference`"'
 
+test_expect_success 'moved back to branch correctly' '
+       test refs/heads/skip-merge = $(git symbolic-ref HEAD)
+'
+
 test_debug 'gitk --all & sleep 1'
 
 test_done
index a328bf57eb67fd96a88020f02948d380ec699496..287e058e3766df129dcde82aeddecac59b46e2a6 100755 (executable)
@@ -104,9 +104,33 @@ test_expect_success 'add ignored ones with -f' '
        git ls-files --error-unmatch d.ig/d.if d.ig/d.ig
 '
 
+test_expect_success 'add ignored ones with -f' '
+       rm -f .git/index &&
+       git add -f d.?? &&
+       git ls-files --error-unmatch d.ig/d.if d.ig/d.ig
+'
+
+test_expect_success '.gitignore with subdirectory' '
+
+       rm -f .git/index &&
+       mkdir -p sub/dir &&
+       echo "!dir/a.*" >sub/.gitignore &&
+       >sub/a.ig &&
+       >sub/dir/a.ig &&
+       git add sub/dir &&
+       git ls-files --error-unmatch sub/dir/a.ig &&
+       rm -f .git/index &&
+       (
+               cd sub/dir &&
+               git add .
+       ) &&
+       git ls-files --error-unmatch sub/dir/a.ig
+'
+
 mkdir 1 1/2 1/3
 touch 1/2/a 1/3/b 1/2/c
 test_expect_success 'check correct prefix detection' '
+       rm -f .git/index &&
        git add 1/2/a 1/3/b 1/2/c
 '
 
diff --git a/t/t4021-format-patch-numbered.sh b/t/t4021-format-patch-numbered.sh
new file mode 100755 (executable)
index 0000000..43d64bb
--- /dev/null
@@ -0,0 +1,106 @@
+#!/bin/sh
+#
+# Copyright (c) 2006 Brian C Gernhardt
+#
+
+test_description='Format-patch numbering options'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+
+       echo A > file &&
+       git add file &&
+       git commit -m First &&
+
+       echo B >> file &&
+       git commit -a -m Second &&
+
+       echo C >> file &&
+       git commit -a -m Third
+
+'
+
+# Each of these gets used multiple times.
+
+test_num_no_numbered() {
+       cnt=$(grep "^Subject: \[PATCH\]" $1 | wc -l) &&
+       test $cnt = $2
+}
+
+test_single_no_numbered() {
+       test_num_no_numbered $1 1
+}
+
+test_no_numbered() {
+       test_num_no_numbered $1 2
+}
+
+test_single_numbered() {
+       grep "^Subject: \[PATCH 1/1\]" $1
+}
+
+test_numbered() {
+       grep "^Subject: \[PATCH 1/2\]" $1 &&
+       grep "^Subject: \[PATCH 2/2\]" $1
+}
+
+test_expect_success 'Default: no numbered' '
+
+       git format-patch --stdout HEAD~2 >patch0 &&
+       test_no_numbered patch0
+
+'
+
+test_expect_success 'Use --numbered' '
+
+       git format-patch --numbered --stdout HEAD~2 >patch1 &&
+       test_numbered patch1
+
+'
+
+test_expect_success 'format.numbered = true' '
+
+       git config format.numbered true &&
+       git format-patch --stdout HEAD~2 >patch2 &&
+       test_numbered patch2
+
+'
+
+test_expect_success 'format.numbered && single patch' '
+
+       git format-patch --stdout HEAD^ > patch3 &&
+       test_single_numbered patch3
+
+'
+
+test_expect_success 'format.numbered && --no-numbered' '
+
+       git format-patch --no-numbered --stdout HEAD~2 >patch4 &&
+       test_no_numbered patch4
+
+'
+
+test_expect_success 'format.numbered = auto' '
+
+       git config format.numbered auto
+       git format-patch --stdout HEAD~2 > patch5 &&
+       test_numbered patch5
+
+'
+
+test_expect_success 'format.numbered = auto && single patch' '
+
+       git format-patch --stdout HEAD^ > patch6 &&
+       test_single_no_numbered patch6
+
+'
+
+test_expect_success 'format.numbered = auto && --no-numbered' '
+
+       git format-patch --no-numbered --stdout HEAD~2 > patch7 &&
+       test_no_numbered patch7
+
+'
+
+test_done
index b4760f2dc0bb690429b358cefde911db1fb26e9a..16eadd6b68664884836976aafb6dcbb582603c09 100755 (executable)
@@ -86,4 +86,37 @@ test_expect_success 'quickfetch should not leave a corrupted repository' '
 
 '
 
+test_expect_success 'quickfetch should not copy from alternate' '
+
+       (
+               mkdir quickclone &&
+               cd quickclone &&
+               git init-db &&
+               (cd ../.git/objects && pwd) >.git/objects/info/alternates &&
+               git remote add origin .. &&
+               git fetch -k -k
+       ) &&
+       obj_cnt=$( (
+               cd quickclone &&
+               git count-objects | sed -e "s/ *objects,.*//"
+       ) ) &&
+       pck_cnt=$( (
+               cd quickclone &&
+               git count-objects -v | sed -n -e "/packs:/{
+                               s/packs://
+                               p
+                               q
+                       }"
+       ) ) &&
+       origin_master=$( (
+               cd quickclone &&
+               git rev-parse origin/master
+       ) ) &&
+       echo "loose objects: $obj_cnt, packfiles: $pck_cnt" &&
+       test $obj_cnt -eq 0 &&
+       test $pck_cnt -eq 0 &&
+       test z$origin_master = z$(git rev-parse master)
+
+'
+
 test_done
index 0d07bc39c745ade65370dde35f43f16a37231179..5f7e388d7add06b8392997037a86c4d0f8524ceb 100755 (executable)
@@ -1004,4 +1004,30 @@ test_expect_failure \
        'verify signed tag fails when public key is not present' \
        'git-tag -v signed-tag'
 
+test_expect_failure \
+       'git-tag -a fails if tag annotation is empty' '
+       GIT_EDITOR=cat git tag -a initial-comment
+'
+
+test_expect_success \
+       'message in editor has initial comment' '
+       GIT_EDITOR=cat git tag -a initial-comment > actual
+       # check the first line --- should be empty
+       first=$(sed -e 1q <actual) &&
+       test -z "$first" &&
+       # remove commented lines from the remainder -- should be empty
+       rest=$(sed -e 1d -e '/^#/d' <actual) &&
+       test -z "$rest"
+'
+
+get_tag_header reuse $commit commit $time >expect
+echo "An annotation to be reused" >> expect
+test_expect_success \
+       'overwriting an annoted tag should use its previous body' '
+       git tag -a -m "An annotation to be reused" reuse &&
+       GIT_EDITOR=true git tag -f -a reuse &&
+       get_tag_msg reuse >actual &&
+       git diff expect actual
+'
+
 test_done
index 01cc0c02b1c20afef664110389b88af702c52ef7..44228b5ac12f5df9d6def93dc74e3687ba2d8e73 100755 (executable)
@@ -15,7 +15,6 @@ do
 done
 unset vi
 mv e-vi.sh vi
-PATH=".:$PATH"
 unset EDITOR VISUAL GIT_EDITOR
 
 test_expect_success setup '
@@ -61,7 +60,7 @@ do
                ;;
        esac
        test_expect_success "Using $i" '
-               git commit --amend &&
+               git --exec-path=. commit --amend &&
                git show -s --pretty=oneline |
                sed -e "s/^[0-9a-f]* //" >actual &&
                diff actual expect
@@ -83,7 +82,7 @@ do
                ;;
        esac
        test_expect_success "Using $i (override)" '
-               git commit --amend &&
+               git --exec-path=. commit --amend &&
                git show -s --pretty=oneline |
                sed -e "s/^[0-9a-f]* //" >actual &&
                diff actual expect
index abbf54ba63693bbb3e839786bf97284c22912333..cf389b81da041e6bcbc7d20cd367b4274001353f 100755 (executable)
@@ -93,4 +93,36 @@ test_expect_success 'commit message from file should override template' '
        commit_msg_is "standard input msg"
 '
 
+test_expect_success 'using alternate GIT_INDEX_FILE (1)' '
+
+       cp .git/index saved-index &&
+       (
+               echo some new content >file &&
+               GIT_INDEX_FILE=.git/another_index &&
+               export GIT_INDEX_FILE &&
+               git add file &&
+               git commit -m "commit using another index" &&
+               git diff-index --exit-code HEAD &&
+               git diff-files --exit-code
+       ) &&
+       cmp .git/index saved-index >/dev/null
+
+'
+
+test_expect_success 'using alternate GIT_INDEX_FILE (2)' '
+
+       cp .git/index saved-index &&
+       (
+               rm -f .git/no-such-index &&
+               GIT_INDEX_FILE=.git/no-such-index &&
+               export GIT_INDEX_FILE &&
+               git commit -m "commit using nonexistent index" &&
+               test -z "$(git ls-files)" &&
+               test -z "$(git ls-tree HEAD)"
+
+       ) &&
+       cmp .git/index saved-index >/dev/null
+
+'
+
 test_done
index 4dc35bdf558750ef41f229fbbb5dbef0a05401c5..9dba104b1f8bf9125f1a947a2fd115b684a94095 100644 (file)
@@ -33,6 +33,16 @@ test_expect_failure \
        "invalid options 2" \
        "git-commit -C HEAD -m illegal"
 
+test_expect_failure \
+       "using paths with -a" \
+       "echo King of the bongo >file &&
+       git-commit -m foo -a file"
+
+test_expect_failure \
+       "using paths with --interactive" \
+       "echo bong-o-bong >file &&
+       echo 7 | git-commit -m foo --interactive file"
+
 test_expect_failure \
        "using invalid commit with -C" \
        "git-commit -C bogus"
index 3c83127a0e862dd89837755103a97ed967c80e0b..d7a704754ea13f17c098e56a7b068cb4f44c1fd0 100755 (executable)
@@ -48,7 +48,7 @@ EOF
        printf "\r\n" > empty_crlf
        a_empty_crlf=`git-hash-object -w empty_crlf`
 
-       svn import -m 'import for git-svn' . "$svnrepo" >/dev/null
+       svn import --no-auto-props -m 'import for git-svn' . "$svnrepo" >/dev/null
 cd ..
 
 rm -rf import
index 0d4e6b3f040a2cbbcfa16209c3e486427af75f55..902ed4145de5f41f3b0522fac464594e9f6e792b 100755 (executable)
@@ -30,6 +30,12 @@ test_expect_success 'setup repository and import' "
        git reset --hard trunk &&
        echo aye >> README &&
        git commit -a -m aye &&
+       git svn dcommit &&
+       git reset --hard b &&
+       echo spy >> README &&
+       git commit -a -m spy &&
+       echo try >> README &&
+       git commit -a -m try &&
        git svn dcommit
        "
 
@@ -45,4 +51,78 @@ test_expect_success 'run log against a from trunk' "
        git svn log -r3 a | grep ^r3
        "
 
+printf 'r1 \nr2 \nr4 \n' > expected-range-r1-r2-r4
+
+test_expect_success 'test ascending revision range' "
+       git reset --hard trunk &&
+       git svn log -r 1:4 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r1-r2-r4 -
+       "
+
+printf 'r4 \nr2 \nr1 \n' > expected-range-r4-r2-r1
+
+test_expect_success 'test descending revision range' "
+       git reset --hard trunk &&
+       git svn log -r 4:1 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r4-r2-r1 -
+       "
+
+printf 'r1 \nr2 \n' > expected-range-r1-r2
+
+test_expect_success 'test ascending revision range with unreachable revision' "
+       git reset --hard trunk &&
+       git svn log -r 1:3 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r1-r2 -
+       "
+
+printf 'r2 \nr1 \n' > expected-range-r2-r1
+
+test_expect_success 'test descending revision range with unreachable revision' "
+       git reset --hard trunk &&
+       git svn log -r 3:1 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r2-r1 -
+       "
+
+printf 'r2 \n' > expected-range-r2
+
+test_expect_success 'test ascending revision range with unreachable upper boundary revision and 1 commit' "
+       git reset --hard trunk &&
+       git svn log -r 2:3 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r2 -
+       "
+
+test_expect_success 'test descending revision range with unreachable upper boundary revision and 1 commit' "
+       git reset --hard trunk &&
+       git svn log -r 3:2 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r2 -
+       "
+
+printf 'r4 \n' > expected-range-r4
+
+test_expect_success 'test ascending revision range with unreachable lower boundary revision and 1 commit' "
+       git reset --hard trunk &&
+       git svn log -r 3:4 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r4 -
+       "
+
+test_expect_success 'test descending revision range with unreachable lower boundary revision and 1 commit' "
+       git reset --hard trunk &&
+       git svn log -r 4:3 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r4 -
+       "
+
+printf -- '------------------------------------------------------------------------\n' > expected-separator
+
+test_expect_success 'test ascending revision range with unreachable boundary revisions and no commits' "
+       git reset --hard trunk &&
+       git svn log -r 5:6 | diff -u expected-separator -
+       "
+
+test_expect_success 'test descending revision range with unreachable boundary revisions and no commits' "
+       git reset --hard trunk &&
+       git svn log -r 6:5 | diff -u expected-separator -
+       "
+
+test_expect_success 'test ascending revision range with unreachable boundary revisions and 1 commit' "
+       git reset --hard trunk &&
+       git svn log -r 3:5 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r4 -
+       "
+
+test_expect_success 'test descending revision range with unreachable boundary revisions and 1 commit' "
+       git reset --hard trunk &&
+       git svn log -r 5:3 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r4 -
+       "
+
 test_done
diff --git a/t/t9117-git-svn-init-clone.sh b/t/t9117-git-svn-init-clone.sh
new file mode 100755 (executable)
index 0000000..d482b40
--- /dev/null
@@ -0,0 +1,55 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Eric Wong
+#
+
+test_description='git-svn init/clone tests'
+
+. ./lib-git-svn.sh
+
+# setup, run inside tmp so we don't have any conflicts with $svnrepo
+set -e
+rm -r .git
+mkdir tmp
+cd tmp
+
+test_expect_success 'setup svnrepo' "
+       mkdir project project/trunk project/branches project/tags &&
+       echo foo > project/trunk/foo &&
+       svn import -m '$test_description' project $svnrepo/project &&
+       rm -rf project
+       "
+
+test_expect_success 'basic clone' "
+       test ! -d trunk &&
+       git svn clone $svnrepo/project/trunk &&
+       test -d trunk/.git/svn &&
+       test -e trunk/foo &&
+       rm -rf trunk
+       "
+
+test_expect_success 'clone to target directory' "
+       test ! -d target &&
+       git svn clone $svnrepo/project/trunk target &&
+       test -d target/.git/svn &&
+       test -e target/foo &&
+       rm -rf target
+       "
+
+test_expect_success 'clone with --stdlayout' "
+       test ! -d project &&
+       git svn clone -s $svnrepo/project &&
+       test -d project/.git/svn &&
+       test -e project/foo &&
+       rm -rf project
+       "
+
+test_expect_success 'clone to target directory with --stdlayout' "
+       test ! -d target &&
+       git svn clone -s $svnrepo/project target &&
+       test -d target/.git/svn &&
+       test -e target/foo &&
+       rm -rf target
+       "
+
+test_done
index 7c261fd7c3b38d2c2dbd722617c628d98848cbc1..aa0a100295c5c48483c6bfbbfc0105b70680becc 100644 (file)
@@ -39,7 +39,7 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const
                show_entry(opt, "+", t2, base, baselen);
                return 1;
        }
-       if (!opt->find_copies_harder && !hashcmp(sha1, sha2) && mode1 == mode2)
+       if (!DIFF_OPT_TST(opt, FIND_COPIES_HARDER) && !hashcmp(sha1, sha2) && mode1 == mode2)
                return 0;
 
        /*
@@ -52,10 +52,10 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const
                return 0;
        }
 
-       if (opt->recursive && S_ISDIR(mode1)) {
+       if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode1)) {
                int retval;
                char *newbase = malloc_base(base, baselen, path1, pathlen1);
-               if (opt->tree_in_recursive)
+               if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE))
                        opt->change(opt, mode1, mode2,
                                    sha1, sha2, base, path1);
                retval = diff_tree_sha1(sha1, sha2, newbase, opt);
@@ -206,7 +206,7 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree
        const char *path;
        const unsigned char *sha1 = tree_entry_extract(desc, &path, &mode);
 
-       if (opt->recursive && S_ISDIR(mode)) {
+       if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode)) {
                enum object_type type;
                int pathlen = tree_entry_len(path, sha1);
                char *newbase = malloc_base(base, baselen, path, pathlen);
@@ -257,7 +257,7 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru
        int baselen = strlen(base);
 
        for (;;) {
-               if (opt->quiet && opt->has_changes)
+               if (DIFF_OPT_TST(opt, QUIET) && DIFF_OPT_TST(opt, HAS_CHANGES))
                        break;
                if (opt->nr_paths) {
                        skip_uninteresting(t1, base, baselen, opt);
@@ -315,7 +315,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
        q->nr = 0;
 
        diff_setup(&diff_opts);
-       diff_opts.recursive = 1;
+       DIFF_OPT_SET(&diff_opts, RECURSIVE);
        diff_opts.detect_rename = DIFF_DETECT_RENAME;
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
        diff_opts.single_follow = opt->paths[0];
@@ -380,7 +380,7 @@ int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const cha
        init_tree_desc(&t1, tree1, size1);
        init_tree_desc(&t2, tree2, size2);
        retval = diff_tree(&t1, &t2, base, opt);
-       if (opt->follow_renames && diff_might_be_rename()) {
+       if (DIFF_OPT_TST(opt, FOLLOW_RENAMES) && diff_might_be_rename()) {
                init_tree_desc(&t1, tree1, size1);
                init_tree_desc(&t2, tree2, size2);
                try_to_follow_renames(&t1, &t2, base, opt);
index c527d7d049155d1808e0bf69aba42d49cea7b68f..aea16adde846b404900555f5f0dd6d87daea8bbf 100644 (file)
@@ -404,7 +404,7 @@ static void verify_uptodate(struct cache_entry *ce,
                return;
 
        if (!lstat(ce->name, &st)) {
-               unsigned changed = ce_match_stat(ce, &st, 1);
+               unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID);
                if (!changed)
                        return;
                /*
@@ -925,7 +925,7 @@ int oneway_merge(struct cache_entry **src,
                if (o->reset) {
                        struct stat st;
                        if (lstat(old->name, &st) ||
-                           ce_match_stat(old, &st, 1))
+                           ce_match_stat(old, &st, CE_MATCH_IGNORE_VALID))
                                old->ce_flags |= htons(CE_UPDATE);
                }
                return keep_entry(old, o);
diff --git a/utf8.c b/utf8.c
index 8095a71d390e59e1ede1d3ed06921b2fcd50e753..9efcdb9c09970127ebe37923879274b95efd526c 100644 (file)
--- a/utf8.c
+++ b/utf8.c
@@ -284,7 +284,6 @@ int print_wrapped_text(const char *text, int indent, int indent2, int width)
                        text++;
                }
        }
-       return w;
 }
 
 int is_encoding_utf8(const char *name)
index 03b5ec4488cb25bca2f9d96493e874d7c12d3636..9a6ef4a89ae659855ae0d2fa3006daf080190ed4 100644 (file)
@@ -22,7 +22,6 @@ static const char use_add_rm_msg[] =
 "use \"git add/rm <file>...\" to update what will be committed";
 static const char use_add_to_include_msg[] =
 "use \"git add <file>...\" to include in what will be committed";
-static const char *excludes_file;
 
 static int parse_status_slot(const char *var, int offset)
 {
@@ -251,22 +250,16 @@ static void wt_status_print_changed(struct wt_status *s)
 static void wt_status_print_untracked(struct wt_status *s)
 {
        struct dir_struct dir;
-       const char *x;
        int i;
        int shown_header = 0;
 
        memset(&dir, 0, sizeof(dir));
 
-       dir.exclude_per_dir = ".gitignore";
        if (!s->untracked) {
                dir.show_other_directories = 1;
                dir.hide_empty_directories = 1;
        }
-       x = git_path("info/exclude");
-       if (file_exists(x))
-               add_excludes_from_file(&dir, x);
-       if (excludes_file && file_exists(excludes_file))
-               add_excludes_from_file(&dir, excludes_file);
+       setup_standard_excludes(&dir);
 
        read_directory(&dir, ".", "", 0, NULL);
        for(i = 0; i < dir.nr; i++) {
@@ -364,11 +357,5 @@ int git_status_config(const char *k, const char *v)
                int slot = parse_status_slot(k, 13);
                color_parse(v, k, wt_status_colors[slot]);
        }
-       if (!strcmp(k, "core.excludesfile")) {
-               if (!v)
-                       die("core.excludesfile without value");
-               excludes_file = xstrdup(v);
-               return 0;
-       }
        return git_default_config(k, v);
 }
index 5cb7171a8f528881c6171defa5b102e87d7aa522..1bad8462fb32cffdc9ff20a278d513e7a444b257 100644 (file)
@@ -257,8 +257,6 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1,
                        return ec;
                }
        }
-
-       return -1;
 }
 
 
index 2ade97b2574a9f77e7ae4002a4e07a6a38e46d07..d7974d1a3e612a235b0c8adfde08ba802e782b5a 100644 (file)
@@ -232,8 +232,6 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
                return i1 >= s1 && i2 >= s2;
        } else
                return s1 == s2 && !memcmp(l1, l2, s1);
-
-       return 0;
 }
 
 static unsigned long xdl_hash_record_with_whitespace(char const **data,