Merge branch 'js/diff-ni' (early part)
authorJunio C Hamano <junkio@cox.net>
Sun, 4 Mar 2007 06:51:46 +0000 (22:51 -0800)
committerJunio C Hamano <junkio@cox.net>
Sun, 4 Mar 2007 06:51:46 +0000 (22:51 -0800)
* 'js/diff-ni' (early part):
diff: make more cases implicit --no-index

27 files changed:
Documentation/RelNotes-1.5.1.txt
Documentation/build-docdep.perl
Documentation/config.txt
Documentation/git-add.txt
Documentation/git-branch.txt
Documentation/git-bundle.txt
Documentation/git-quiltimport.txt
Documentation/git-send-email.txt
Documentation/git-svn.txt
Documentation/pretty-formats.txt
Makefile
builtin-archive.c
builtin-branch.c
cache.h
commit.c
commit.h
date.c
git-compat-util.h
git-gc.sh
git-merge.sh
git.c
http-push.c
log-tree.c
refs.c
templates/hooks--update
utf8.c
utf8.h
index 5ce385b442e86b618fe3cb20251a6ccae3a82a12..aa371be1daeb75b0a9ce59fa6434ccfdb3f547bc 100644 (file)
@@ -50,7 +50,7 @@ Updates since v1.5.0
     LF at the end of lines.  Currently, which paths to consider
     'text' (i.e. be subjected to the autocrlf mechanism) is
     decided purely based on the contents, but the plan is to
-    allow users to explicitly override this heuristics based on
+    allow users to explicitly override this heuristic based on
     paths.
 
   - The behaviour of 'git-apply', when run in a subdirectory,
index 489389c32af57d39bb843e2b0621144b38006fa3..ba4205e0302a267a5da6bef504f3e69eb0c4aa6d 100755 (executable)
 while (my ($text, $included) = each %include) {
     if (! exists $included{$text} &&
        (my $base = $text) =~ s/\.txt$//) {
-       my ($suffix) = '1';
-       if ($base eq 'git') {
-           $suffix = '7'; # yuck...
-       }
-       print "$base.html $base.$suffix : ", join(" ", keys %$included), "\n";
+       print "$base.html $base.xml : ", join(" ", keys %$included), "\n";
     }
 }
index d2b4a05ca5849c59514c6f0e67c8b31ad444be9e..d20902bc33226fbb7395fe4d003e9c8408eefdb2 100644 (file)
@@ -341,6 +341,11 @@ format.headers::
        Additional email headers to include in a patch to be submitted
        by mail.  See gitlink:git-format-patch[1].
 
+format.suffix::
+       The default for format-patch is to output files with the suffix
+       `.patch`. Use this variable to change that suffix (make sure to
+       include the dot if you want it).
+
 gc.packrefs::
        `git gc` does not run `git pack-refs` in a bare repository by
        default so that older dumb-transport clients can still fetch
index b73a99d61f57c7d532bbf8dc94bf2cb167d78058..755d7186f5f4a74dc84cc98c67eec0b9c86b6289 100644 (file)
@@ -52,7 +52,7 @@ OPTIONS
 -f::
        Allow adding otherwise ignored files.
 
-\i, \--interactive::
+-i, \--interactive::
        Add modified contents in the working tree interactively to
        the index.
 
index aa1fdd402aa1771ab77af5e274a7e0452bbe8aa5..3ea3b8063520fe2a6f97b767d5f2e2ac05d147d9 100644 (file)
@@ -8,7 +8,8 @@ git-branch - List, create, or delete branches
 SYNOPSIS
 --------
 [verse]
-'git-branch' [--color | --no-color] [-r | -a] [-v [--abbrev=<length>]]
+'git-branch' [--color | --no-color] [-r | -a]
+          [-v [--abbrev=<length> | --no-abbrev]]
 'git-branch' [-l] [-f] <branchname> [<start-point>]
 'git-branch' (-m | -M) [<oldbranch>] <newbranch>
 'git-branch' (-d | -D) [-r] <branchname>...
@@ -80,6 +81,9 @@ OPTIONS
        Alter minimum display length for sha1 in output listing,
        default value is 7.
 
+--no-abbrev::
+       Display the full sha1s in output listing rather than abbreviating them.
+
 <branchname>::
        The name of the branch to create or delete.
        The new branch name must pass all checks defined by
index 4ea9e85d5e7c9b9082c4892548ab798d23f30e6d..92e7a687229761b46f57fb4197a725a075f0a0f2 100644 (file)
@@ -19,7 +19,7 @@ DESCRIPTION
 Some workflows require that one or more branches of development on one
 machine be replicated on another machine, but the two machines cannot
 be directly connected so the interactive git protocols (git, ssh,
-rsync, http) cannot be used.  This command provides suport for
+rsync, http) cannot be used.  This command provides support for
 git-fetch and git-pull to operate by packaging objects and references
 in an archive at the originating machine, then importing those into
 another repository using gitlink:git-fetch[1] and gitlink:git-pull[1]
@@ -58,7 +58,7 @@ unbundle <file>::
        gitlink:git-fetch[1].
 
 [git-rev-list-args...]::
-       A list of arguments, accepatble to git-rev-parse and
+       A list of arguments, acceptable to git-rev-parse and
        git-rev-list, that specify the specific objects and references
        to transport.  For example, "master~10..master" causes the
        current master reference to be packaged along with all objects
@@ -70,7 +70,7 @@ unbundle <file>::
 [refname...]::
        A list of references used to limit the references reported as
        available. This is principally of use to git-fetch, which
-       expects to recieve only those references asked for and not
+       expects to receive only those references asked for and not
        necessarily everything in the pack (in this case, git-bundle is
        acting like gitlink:git-fetch-pack[1]).
 
@@ -87,7 +87,7 @@ specified explicitly (e.g., ^master~10), or implicitly (e.g.,
 master~10..master, master --since=10.days.ago).
 
 It is very important that the basis used be held by the destination.
-It is ok to err on the side of conservatism, causing the bundle file
+It is okay to err on the side of conservatism, causing the bundle file
 to contain objects already in the destination as these are ignored
 when unpacking at the destination.
 
index 6e9a8c369a38e85c003c451b414fd58c24445aba..296937a4167dc2e4c93cfcafca9fea14090cb108 100644 (file)
@@ -42,10 +42,10 @@ OPTIONS
 --patches <dir>::
        The directory to find the quilt patches and the
        quilt series file.
-
-        The default for the patch directory is patches
-       or the value of the $QUILT_PATCHES environment
-       variable.
++
+The default for the patch directory is patches
+or the value of the $QUILT_PATCHES environment
+variable.
 
 Author
 ------
index 4c8d907bd595a4f31b3f53cfff25b84cea059ff7..35b0104e4acbe614fb274c1ee36d6a4ab2ea5849 100644 (file)
@@ -26,13 +26,13 @@ The options available are:
 
 --bcc::
        Specify a "Bcc:" value for each email.
-
-       The --bcc option must be repeated for each user you want on the bcc list.
++
+The --bcc option must be repeated for each user you want on the bcc list.
 
 --cc::
        Specify a starting "Cc:" value for each email.
-
-       The --cc option must be repeated for each user you want on the cc list.
++
+The --cc option must be repeated for each user you want on the cc list.
 
 --chain-reply-to, --no-chain-reply-to::
        If this is set, each email will be sent as a reply to the previous
@@ -87,8 +87,8 @@ The options available are:
        Specify the primary recipient of the emails generated.
        Generally, this will be the upstream maintainer of the
        project involved.
-
-       The --to option must be repeated for each user you want on the to list.
++
+The --to option must be repeated for each user you want on the to list.
 
 
 Author
index cf094ca357758d147c9ab7684ef5abc7d15a50ef..9b5a3d61966eaa8d24b5ee507f2e1be770a1c367 100644 (file)
@@ -63,7 +63,7 @@ COMMANDS
        transports (eg svn+ssh://), you must include the username in
        the URL, eg svn+ssh://foo@svn.bar.com/project
 
---prefix=<prefix>
+--prefix=<prefix>::
        This allows one to specify a prefix which is prepended
        to the names of remotes if trunk/branches/tags are
        specified.  The prefix does not automatically include a
@@ -94,16 +94,16 @@ COMMANDS
        This fetches revisions from the SVN parent of the current HEAD
        and rebases the current (uncommitted to SVN) work against it.
 
-       This works similarly to 'svn update' or 'git-pull' except that
-       it preserves linear history with 'git-rebase' instead of
-       'git-merge' for ease of dcommit-ing with git-svn.
+This works similarly to 'svn update' or 'git-pull' except that
+it preserves linear history with 'git-rebase' instead of
+'git-merge' for ease of dcommit-ing with git-svn.
 
-       This accepts all options that 'git-svn fetch' and 'git-rebase'
-       accepts.  However '--fetch-all' only fetches from the current
-       [svn-remote], and not all [svn-remote] definitions.
+This accepts all options that 'git-svn fetch' and 'git-rebase'
+accepts.  However '--fetch-all' only fetches from the current
+[svn-remote], and not all [svn-remote] definitions.
 
-       Like 'git-rebase'; this requires that the working tree be clean
-       and have no uncommitted changes.
+Like 'git-rebase'; this requires that the working tree be clean
+and have no uncommitted changes.
 
 'dcommit'::
        Commit each diff from a specified head directly to the SVN
@@ -117,29 +117,40 @@ COMMANDS
        alternative to HEAD.
        This is advantageous over 'set-tree' (below) because it produces
        cleaner, more linear history.
+--
 
 'log'::
        This should make it easy to look up svn log messages when svn
        users refer to -r/--revision numbers.
++
+The following features from `svn log' are supported:
++
+--
+--revision=<n>[:<n>];;
+       is supported, non-numeric args are not:
+       HEAD, NEXT, BASE, PREV, etc ...
+-v/--verbose;;
+       it's not completely compatible with the --verbose
+       output in svn log, but reasonably close.
+--limit=<n>;;
+       is NOT the same as --max-count, doesn't count
+       merged/excluded commits
+--incremental;;
+       supported
+--
++
+New features:
++
+--
+--show-commit;;
+       shows the git commit sha1, as well
+--oneline;;
+       our version of --pretty=oneline
+--
++
+Any other arguments are passed directly to `git log'
 
-       The following features from `svn log' are supported:
-
-       --revision=<n>[:<n>] - is supported, non-numeric args are not:
-                              HEAD, NEXT, BASE, PREV, etc ...
-       -v/--verbose         - it's not completely compatible with
-                              the --verbose output in svn log, but
-                              reasonably close.
-       --limit=<n>          - is NOT the same as --max-count,
-                              doesn't count merged/excluded commits
-       --incremental        - supported
-
-       New features:
-
-       --show-commit        - shows the git commit sha1, as well
-       --oneline            - our version of --pretty=oneline
-
-       Any other arguments are passed directly to `git log'
-
+--
 'set-tree'::
        You should consider using 'dcommit' instead of this command.
        Commit specified commit or tree objects to SVN.  This relies on
@@ -256,16 +267,18 @@ config key: svn.authorsfile
        Make git-svn less verbose.
 
 --repack[=<n>]::
---repack-flags=<flags>
-       These should help keep disk usage sane for large fetches
-       with many revisions.
+--repack-flags=<flags>::
+
+These should help keep disk usage sane for large fetches
+with many revisions.
 
-       --repack takes an optional argument for the number of revisions
-       to fetch before repacking.  This defaults to repacking every
-       1000 commits fetched if no argument is specified.
+--repack takes an optional argument for the number of revisions
+to fetch before repacking.  This defaults to repacking every
+1000 commits fetched if no argument is specified.
 
-       --repack-flags are passed directly to gitlink:git-repack[1].
+--repack-flags are passed directly to gitlink:git-repack[1].
 
+[verse]
 config key: svn.repack
 config key: svn.repackflags
 
@@ -323,28 +336,30 @@ CONFIG FILE-ONLY OPTIONS
 
 svn.noMetadata::
 svn-remote.<name>.noMetadata::
-       This gets rid of the git-svn-id: lines at the end of every commit.
 
-       If you lose your .git/svn/git-svn/.rev_db file, git-svn will not
-       be able to rebuild it and you won't be able to fetch again,
-       either.  This is fine for one-shot imports.
+This gets rid of the git-svn-id: lines at the end of every commit.
+
+If you lose your .git/svn/git-svn/.rev_db file, git-svn will not
+be able to rebuild it and you won't be able to fetch again,
+either.  This is fine for one-shot imports.
 
-       The 'git-svn log' command will not work on repositories using
-       this, either.  Using this conflicts with the 'useSvmProps'
-       option for (hopefully) obvious reasons.
+The 'git-svn log' command will not work on repositories using
+this, either.  Using this conflicts with the 'useSvmProps'
+option for (hopefully) obvious reasons.
 
 svn.useSvmProps::
 svn-remote.<name>.useSvmProps::
-       This allows git-svn to re-map repository URLs and UUIDs from
-       mirrors created using SVN::Mirror (or svk) for metadata.
 
-       If an SVN revision has a property, "svm:headrev", it is likely
-       that the revision was created by SVN::Mirror (also used by SVK).
-       The property contains a repository UUID and a revision.  We want
-       to make it look like we are mirroring the original URL, so
-       introduce a helper function that returns the original identity
-       URL and UUID, and use it when generating metadata in commit
-       messages.
+This allows git-svn to re-map repository URLs and UUIDs from
+mirrors created using SVN::Mirror (or svk) for metadata.
+
+If an SVN revision has a property, "svm:headrev", it is likely
+that the revision was created by SVN::Mirror (also used by SVK).
+The property contains a repository UUID and a revision.  We want
+to make it look like we are mirroring the original URL, so
+introduce a helper function that returns the original identity
+URL and UUID, and use it when generating metadata in commit
+messages.
 
 svn.useSvnsyncProps::
 svn-remote.<name>.useSvnsyncprops::
@@ -369,8 +384,8 @@ section because they affect the 'git-svn-id:' metadata line.
 
 --
 
-Basic Examples
-~~~~~~~~~~~~~~
+BASIC EXAMPLES
+--------------
 
 Tracking and contributing to a the trunk of a Subversion-managed project:
 
@@ -405,7 +420,7 @@ Tracking and contributing to an entire Subversion-managed project
 # with the appropriate name):
        git reset --hard remotes/trunk
 # You may only dcommit to one branch/tag/trunk at a time.  The usage
-# of dcommit/rebase/show-ignore should be teh same as above.
+# of dcommit/rebase/show-ignore should be the same as above.
 ------------------------------------------------------------------------
 
 REBASE VS. PULL/MERGE
index fb0b0b95829e0fc1aa98019554ce12e9b45d1f63..2fe6c319675926afe1609ad7c221dceb42c82310 100644 (file)
@@ -77,9 +77,53 @@ displayed in full, regardless of whether --abbrev or
 true parent commits, without taking grafts nor history
 simplification into account.
 
+       * 'format:'
++
+The 'format:' format allows you to specify which information
+you want to show. It works a little bit like printf format,
+with the notable exception that you get a newline with '%n'
+instead of '\n'.
+
+E.g, 'format:"The author of %h was %an, %ar%nThe title was >>%s<<"'
+would show something like this:
+
+The author of fe6e0ee was Junio C Hamano, 23 hours ago
+The title was >>t4119: test autocomputing -p<n> for traditional diff input.<<
+
+The placeholders are:
+
+- '%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
+- '%cn': committer name
+- '%ce': committer email
+- '%cd': committer date
+- '%cD': committer date, RFC2822 style
+- '%cr': committer date, relative
+- '%ct': committer date, UNIX timestamp
+- '%e': encoding
+- '%s': subject
+- '%b': body
+- '%Cred': switch color to red
+- '%Cgreen': switch color to green
+- '%Cblue': switch color to blue
+- '%Creset': reset color
+- '%n': newline
+
+
 --encoding[=<encoding>]::
        The commit objects record the encoding used for the log message
        in their encoding header; this option can be used to tell the
        command to re-code the commit log message in the encoding
        preferred by the user.  For non plumbing commands this
        defaults to UTF-8.
+
index 23ab7d6f9f6554169de554b53042bc2d99bf4fed..a221bdc027851270b9920373a3d9cb8d0fbac2e2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -89,6 +89,9 @@ all::
 #
 # Define NO_ICONV if your libc does not properly support iconv.
 #
+# Define OLD_ICONV if your library has an old iconv(), where the second
+# (input buffer pointer) parameter is declared with type (const char **).
+#
 # Define NO_R_TO_GCC if your gcc does not like "-R/path/lib" that
 # tells runtime paths to dynamic libraries; "-Wl,-rpath=/path/lib"
 # is used instead.
@@ -378,7 +381,6 @@ ifeq ($(uname_O),Cygwin)
        NO_STRCASESTR = YesPlease
        NO_SYMLINK_HEAD = YesPlease
        NEEDS_LIBICONV = YesPlease
-       NO_C99_FORMAT = YesPlease
        NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes
        NO_TRUSTABLE_FILEMODE = UnfortunatelyYes
        # There are conflicting reports about this.
@@ -576,6 +578,10 @@ ifdef NO_ICONV
        BASIC_CFLAGS += -DNO_ICONV
 endif
 
+ifdef OLD_ICONV
+       BASIC_CFLAGS += -DOLD_ICONV
+endif
+
 ifdef PPC_SHA1
        SHA1_HEADER = "ppc/sha1.h"
        LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o
@@ -780,7 +786,7 @@ git-http-push$X: revision.o http.o http-push.o $(GITLIBS)
        $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
 
-$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
+$(LIB_OBJS) $(BUILTIN_OBJS) fetch.o: $(LIB_H)
 $(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
 $(DIFF_OBJS): diffcore.h
 
index 8ea6cb1efc4f988fb09051852f9e51fc88b5efd7..2fae885f5c27f73820824b612d41fd37ab91239d 100644 (file)
@@ -252,8 +252,6 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
 
        memset(&ar, 0, sizeof(ar));
        tree_idx = parse_archive_args(argc, argv, &ar);
-       if (prefix == NULL)
-               prefix = setup_git_directory();
 
        argv += tree_idx;
        parse_treeish_arg(argv, &ar.args, prefix);
index d0179b00a2f78ddf875cf7ea98e712b152664e94..d3718496553078dfb4ceac2413c758457e102592 100644 (file)
@@ -12,7 +12,7 @@
 #include "builtin.h"
 
 static const char builtin_branch_usage[] =
-  "git-branch [-r] (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [--color | --no-color] [-r | -a] [-v [--abbrev=<length>]]";
+  "git-branch [-r] (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [--color | --no-color] [-r | -a] [-v [--abbrev=<length> | --no-abbrev]]";
 
 #define REF_UNKNOWN_TYPE    0x00
 #define REF_LOCAL_BRANCH    0x01
@@ -446,8 +446,16 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                        reflog = 1;
                        continue;
                }
+               if (!prefixcmp(arg, "--no-abbrev")) {
+                       abbrev = 0;
+                       continue;
+               }
                if (!prefixcmp(arg, "--abbrev=")) {
-                       abbrev = atoi(arg+9);
+                       abbrev = strtoul(arg + 9, NULL, 10);
+                       if (abbrev < MINIMUM_ABBREV)
+                               abbrev = MINIMUM_ABBREV;
+                       else if (abbrev > 40)
+                               abbrev = 40;
                        continue;
                }
                if (!strcmp(arg, "-v")) {
diff --git a/cache.h b/cache.h
index b84e3decfcd38a349243dc8e3a88e1b5151ced6c..8018b2cd3b20533ea03ce503bc88b8bd0155432e 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -327,7 +327,8 @@ extern void *read_object_with_reference(const unsigned char *sha1,
                                        unsigned long *size,
                                        unsigned char *sha1_ret);
 
-const char *show_date(unsigned long time, int timezone, int relative);
+enum date_mode { DATE_NORMAL = 0, DATE_RELATIVE, DATE_SHORT };
+const char *show_date(unsigned long time, int timezone, enum date_mode mode);
 const char *show_rfc2822_date(unsigned long time, int timezone);
 int parse_date(const char *date, char *buf, int bufsize);
 void datestamp(char *buf, int bufsize);
index da515a49738c3c8e3065da08e468a93bf976f1e4..555252734298540ffc5678ac5d80888fd23dd4e5 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -3,6 +3,7 @@
 #include "commit.h"
 #include "pkt-line.h"
 #include "utf8.h"
+#include "interpolate.h"
 
 int save_commit_buffer = 1;
 
@@ -36,8 +37,11 @@ struct cmt_fmt_map {
        { "full",       5,      CMIT_FMT_FULL },
        { "fuller",     5,      CMIT_FMT_FULLER },
        { "oneline",    1,      CMIT_FMT_ONELINE },
+       { "format:",    7,      CMIT_FMT_USERFORMAT},
 };
 
+static char *user_format;
+
 enum cmit_fmt get_commit_format(const char *arg)
 {
        int i;
@@ -46,6 +50,12 @@ enum cmit_fmt get_commit_format(const char *arg)
                return CMIT_FMT_DEFAULT;
        if (*arg == '=')
                arg++;
+       if (!prefixcmp(arg, "format:")) {
+               if (user_format)
+                       free(user_format);
+               user_format = xstrdup(arg + 7);
+               return CMIT_FMT_USERFORMAT;
+       }
        for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) {
                if (!strncmp(arg, cmt_fmts[i].n, cmt_fmts[i].cmp_len) &&
                    !strncmp(arg, cmt_fmts[i].n, strlen(arg)))
@@ -710,6 +720,188 @@ static char *logmsg_reencode(const struct commit *commit,
        return out;
 }
 
+static char *xstrndup(const char *text, int len)
+{
+       char *result = xmalloc(len + 1);
+       memcpy(result, text, len);
+       result[len] = '\0';
+       return result;
+}
+
+static void fill_person(struct interp *table, const char *msg, int len)
+{
+       int start, end, tz = 0;
+       unsigned long date;
+       char *ep;
+
+       /* parse name */
+       for (end = 0; end < len && msg[end] != '<'; end++)
+               ; /* do nothing */
+       start = end + 1;
+       while (end > 0 && isspace(msg[end - 1]))
+               end--;
+       table[0].value = xstrndup(msg, end);
+
+       if (start >= len)
+               return;
+
+       /* parse email */
+       for (end = start + 1; end < len && msg[end] != '>'; end++)
+               ; /* do nothing */
+
+       if (end >= len)
+               return;
+
+       table[1].value = xstrndup(msg + start, end - start);
+
+       /* parse date */
+       for (start = end + 1; start < len && isspace(msg[start]); start++)
+               ; /* do nothing */
+       if (start >= len)
+               return;
+       date = strtoul(msg + start, &ep, 10);
+       if (msg + start == ep)
+               return;
+
+       table[5].value = xstrndup(msg + start, ep - msg + start);
+
+       /* parse tz */
+       for (start = ep - msg + 1; start < len && isspace(msg[start]); start++)
+               ; /* do nothing */
+       if (start + 1 < len) {
+               tz = strtoul(msg + start + 1, NULL, 10);
+               if (msg[start] == '-')
+                       tz = -tz;
+       }
+
+       interp_set_entry(table, 2, show_date(date, tz, 0));
+       interp_set_entry(table, 3, show_rfc2822_date(date, tz));
+       interp_set_entry(table, 4, show_date(date, tz, 1));
+}
+
+static long format_commit_message(const struct commit *commit,
+               const char *msg, char *buf, unsigned long space)
+{
+       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 */
+               { "%cn" },      /* committer name */
+               { "%ce" },      /* committer email */
+               { "%cd" },      /* committer date */
+               { "%cD" },      /* committer date, RFC2822 style */
+               { "%cr" },      /* committer date, relative */
+               { "%ct" },      /* committer date, UNIX timestamp */
+               { "%e" },       /* encoding */
+               { "%s" },       /* subject */
+               { "%b" },       /* body */
+               { "%Cred" },    /* red */
+               { "%Cgreen" },  /* green */
+               { "%Cblue" },   /* blue */
+               { "%Creset" },  /* reset color */
+               { "%n" }        /* newline */
+       };
+       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,
+               ICOMMITTER_NAME, ICOMMITTER_EMAIL,
+               ICOMMITTER_DATE, ICOMMITTER_DATE_RFC2822,
+               ICOMMITTER_DATE_RELATIVE, ICOMMITTER_TIMESTAMP,
+               IENCODING,
+               ISUBJECT,
+               IBODY,
+               IRED, IGREEN, IBLUE, IRESET_COLOR,
+               INEWLINE
+       };
+       struct commit_list *p;
+       char parents[1024];
+       int i;
+       enum { HEADER, SUBJECT, BODY } state;
+
+       if (INEWLINE + 1 != ARRAY_SIZE(table))
+               die("invalid interp table!");
+
+       /* 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");
+
+       /* 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));
+       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);
+       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);
+
+       for (i = 0, state = HEADER; msg[i] && state < BODY; i++) {
+               int eol;
+               for (eol = i; msg[eol] && msg[eol] != '\n'; eol++)
+                       ; /* do nothing */
+
+               if (state == SUBJECT) {
+                       table[ISUBJECT].value = xstrndup(msg + i, eol - i);
+                       i = eol;
+               }
+               if (i == eol) {
+                       state++;
+                       /* 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 = xstrndup(msg + i, eol - i);
+               i = eol;
+       }
+       if (msg[i])
+               table[IBODY].value = xstrdup(msg + i);
+       for (i = 0; i < ARRAY_SIZE(table); i++)
+               if (!table[i].value)
+                       interp_set_entry(table, i, "<unknown>");
+
+       interpolate(buf, space, user_format, table, ARRAY_SIZE(table));
+       interp_clear_table(table, ARRAY_SIZE(table));
+
+       return strlen(buf);
+}
+
 unsigned long pretty_print_commit(enum cmit_fmt fmt,
                                  const struct commit *commit,
                                  unsigned long len,
@@ -727,6 +919,9 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
        char *reencoded;
        char *encoding;
 
+       if (fmt == CMIT_FMT_USERFORMAT)
+               return format_commit_message(commit, msg, buf, space);
+
        encoding = (git_log_output_encoding
                    ? git_log_output_encoding
                    : git_commit_encoding);
index c73744463ca55ce0df3623dffbb994bd4a86d76e..83507a07e4cbaab81f130891a64b78539d1beede 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -47,6 +47,7 @@ enum cmit_fmt {
        CMIT_FMT_FULLER,
        CMIT_FMT_ONELINE,
        CMIT_FMT_EMAIL,
+       CMIT_FMT_USERFORMAT,
 
        CMIT_FMT_UNSPECIFIED,
 };
diff --git a/date.c b/date.c
index 542c004c2e8d2a9f731a1f303cc3393d88f5a6e8..0ceccbe03401faa67836577b9bdbe139fe025dd5 100644 (file)
--- a/date.c
+++ b/date.c
@@ -55,12 +55,12 @@ static struct tm *time_to_tm(unsigned long time, int tz)
        return gmtime(&t);
 }
 
-const char *show_date(unsigned long time, int tz, int relative)
+const char *show_date(unsigned long time, int tz, enum date_mode mode)
 {
        struct tm *tm;
        static char timebuf[200];
 
-       if (relative) {
+       if (mode == DATE_RELATIVE) {
                unsigned long diff;
                struct timeval now;
                gettimeofday(&now, NULL);
@@ -105,12 +105,16 @@ const char *show_date(unsigned long time, int tz, int relative)
        tm = time_to_tm(time, tz);
        if (!tm)
                return NULL;
-       sprintf(timebuf, "%.3s %.3s %d %02d:%02d:%02d %d %+05d",
-               weekday_names[tm->tm_wday],
-               month_names[tm->tm_mon],
-               tm->tm_mday,
-               tm->tm_hour, tm->tm_min, tm->tm_sec,
-               tm->tm_year + 1900, tz);
+       if (mode == DATE_SHORT)
+               sprintf(timebuf, "%04d-%02d-%02d", tm->tm_year + 1900,
+                               tm->tm_mon + 1, tm->tm_mday);
+       else
+               sprintf(timebuf, "%.3s %.3s %d %02d:%02d:%02d %d %+05d",
+                               weekday_names[tm->tm_wday],
+                               month_names[tm->tm_mon],
+                               tm->tm_mday,
+                               tm->tm_hour, tm->tm_min, tm->tm_sec,
+                               tm->tm_year + 1900, tz);
        return timebuf;
 }
 
index 5d154faef6bcdbef7ae8ad91b92b08be326af1e1..56212b2f115d0ef738c5835c42d7bf241db4576a 100644 (file)
 #include <netdb.h>
 #include <pwd.h>
 #include <inttypes.h>
+#if defined(__CYGWIN__)
+#undef _XOPEN_SOURCE
+#include <grp.h>
+#define _XOPEN_SOURCE 600
+#else
 #undef _ALL_SOURCE /* AIX 5.3L defines a struct list with _ALL_SOURCE. */
 #include <grp.h>
 #define _ALL_SOURCE 1
+#endif
 
 #ifndef NO_ICONV
 #include <iconv.h>
index 1a45de5dff7763fbca2a9076a4d3bdb0ed903439..436d7caff5c26f7c0ff8c0a410bdabccdec0a900 100755 (executable)
--- a/git-gc.sh
+++ b/git-gc.sh
@@ -4,7 +4,7 @@
 #
 # Cleanup unreachable files and optimize the repository.
 
-USAGE='git-gc [--prune]'
+USAGE='[--prune]'
 SUBDIRECTORY_OK=Yes
 . git-sh-setup
 
index 498c938c4507ccdc27f5a9e30e85f013a067c876..4afcd95316c01e5d1811184c615c4da574ab0717 100755 (executable)
@@ -294,7 +294,7 @@ f,*)
        git-update-index --refresh 2>/dev/null
        new_head=$(git-rev-parse --verify "$1^0") &&
        git-read-tree -v -m -u --exclude-per-directory=.gitignore $head "$new_head" &&
-       finish "$new_head" "Fast forward"
+       finish "$new_head" "Fast forward" || exit
        dropsave
        exit 0
        ;;
diff --git a/git.c b/git.c
index 9b37f423216a6e8a86646ba15af642b9f7cc10e6..04fc99a3dd9666bb4c22c99754334aeecc08bab5 100644 (file)
--- a/git.c
+++ b/git.c
@@ -226,7 +226,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
                { "add", cmd_add, RUN_SETUP | NOT_BARE },
                { "annotate", cmd_annotate, USE_PAGER },
                { "apply", cmd_apply },
-               { "archive", cmd_archive },
+               { "archive", cmd_archive, RUN_SETUP },
                { "blame", cmd_blame, RUN_SETUP },
                { "branch", cmd_branch, RUN_SETUP },
                { "bundle", cmd_bundle },
index 68b78b538ad42bce99dce690bc40ea85c1ed2377..cbb02d3bc1eef3d5a088be320a3a8bcb87a4a685 100644 (file)
@@ -1271,7 +1271,9 @@ xml_cdata(void *userData, const XML_Char *s, int len)
        struct xml_ctx *ctx = (struct xml_ctx *)userData;
        free(ctx->cdata);
        ctx->cdata = xmalloc(len + 1);
-       strlcpy(ctx->cdata, s, len + 1);
+       /* NB: 's' is not null-terminated, can not use strlcpy here */
+       memcpy(ctx->cdata, s, len);
+       ctx->cdata[len] = '\0';
 }
 
 static struct remote_lock *lock_remote(const char *path, long timeout)
@@ -1473,7 +1475,8 @@ static void process_ls_object(struct remote_ls_ctx *ls)
                return;
        path += 8;
        obj_hex = xmalloc(strlen(path));
-       strlcpy(obj_hex, path, 3);
+       /* NB: path is not null-terminated, can not use strlcpy here */
+       memcpy(obj_hex, path, 2);
        strcpy(obj_hex + 2, path + 3);
        one_remote_object(obj_hex);
        free(obj_hex);
@@ -2170,7 +2173,8 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
        /* If it's a symref, set the refname; otherwise try for a sha1 */
        if (!prefixcmp((char *)buffer.buffer, "ref: ")) {
                *symref = xmalloc(buffer.posn - 5);
-               strlcpy(*symref, (char *)buffer.buffer + 5, buffer.posn - 5);
+               memcpy(*symref, (char *)buffer.buffer + 5, buffer.posn - 6);
+               (*symref)[buffer.posn - 6] = '\0';
        } else {
                get_sha1_hex(buffer.buffer, sha1);
        }
index ac8619404797633436258dbf9d76f9f4aa323395..6ce239d8f92837ccce7326dab1951f74360eef88 100644 (file)
@@ -211,7 +211,7 @@ void show_log(struct rev_info *opt, const char *sep)
                                 sha1, sha1);
                        opt->diffopt.stat_sep = buffer;
                }
-       } else {
+       } else if (opt->commit_format != CMIT_FMT_USERFORMAT) {
                fputs(diff_get_color(opt->diffopt.color_diff, DIFF_COMMIT),
                      stdout);
                if (opt->commit_format != CMIT_FMT_ONELINE)
diff --git a/refs.c b/refs.c
index d347876c876cfe210896a1f31d2b073849271f28..7a1f89caad17cfb090e683c9888537666e8398b9 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1042,7 +1042,9 @@ int create_symref(const char *ref_target, const char *refs_heads_master,
                return -1;
        }
 
+#ifndef NO_SYMLINK_HEAD
        done:
+#endif
        if (logmsg && !read_ref(refs_heads_master, new_sha1))
                log_ref_write(ref_target, old_sha1, new_sha1, logmsg);
 
index fd1f73d6aa48b104cc74d08dcb6a29bd3f8f08d9..5b82b68e93980924befa9ecc99e099e77da27b5f 100644 (file)
@@ -64,7 +64,7 @@ case "$refname","$newrev_type" in
                # un-annotated tag
                refname_type="tag"
                short_refname=${refname##refs/tags/}
-               if [ $allowunannotated != "true" ]; then
+               if [ "$allowunannotated" != "true" ]; then
                        echo "*** The un-annotated tag, $short_refname is not allowed in this repository" >&2
                        echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
                        exit 1
@@ -148,7 +148,7 @@ case "$refname_type" in
                        # This shows all log entries that are not already covered by
                        # another ref - i.e. commits that are now accessible from this
                        # ref that were previously not accessible
-                       git-rev-parse --not --all | git-rev-list --stdin --pretty $newref
+                       git log $newrev --not --all
                        echo $LOGEND
                else
                        # oldrev is valid
@@ -165,7 +165,7 @@ case "$refname_type" in
                        baserev=$(git-merge-base $oldrev $newrev)
 
                        # Commit with a parent
-                       for rev in $(git-rev-parse --not --all | git-rev-list --stdin $newrev ^$baserev)
+                       for rev in $(git-rev-list $newrev --not $baserev --all)
                        do
                                revtype=$(git-cat-file -t "$rev")
                                echo "       via  $rev ($revtype)"
@@ -190,12 +190,11 @@ case "$refname_type" in
                        fi
                        echo ""
                        echo $LOGBEGIN
-                       git-rev-parse --not --all |
-                       git-rev-list --stdin --pretty $newrev ^$baserev
+                       git log $newrev --not $baserev --all
                        echo $LOGEND
                        echo ""
                        echo "Diffstat:"
-                       git-diff-tree --no-color --stat -M -C --find-copies-harder $newrev ^$baserev
+                       git-diff-tree --no-color --stat -M -C --find-copies-harder $baserev..$newrev
                fi
                ;;
        "annotated tag")
diff --git a/utf8.c b/utf8.c
index 7c80eeccb4537ab6d4387941c6262c89cab30d33..a2965c9c1106b7e772d9b53c8885d86320d18f07 100644 (file)
--- a/utf8.c
+++ b/utf8.c
@@ -3,13 +3,15 @@
 
 /* This code is originally from http://www.cl.cam.ac.uk/~mgk25/ucs/ */
 
+typedef unsigned int ucs_char_t;  /* assuming 32bit int */
+
 struct interval {
   int first;
   int last;
 };
 
 /* auxiliary function for binary search in interval table */
-static int bisearch(wchar_t ucs, const struct interval *table, int max) {
+static int bisearch(ucs_char_t ucs, const struct interval *table, int max) {
        int min = 0;
        int mid;
 
@@ -56,11 +58,11 @@ static int bisearch(wchar_t ucs, const struct interval *table, int max) {
  *      ISO 8859-1 and WGL4 characters, Unicode control characters,
  *      etc.) have a column width of 1.
  *
- * This implementation assumes that wchar_t characters are encoded
+ * This implementation assumes that ucs_char_t characters are encoded
  * in ISO 10646.
  */
 
-static int wcwidth(wchar_t ch)
+static int wcwidth(ucs_char_t ch)
 {
        /*
         * Sorted list of non-overlapping intervals of non-spacing characters,
@@ -157,7 +159,7 @@ static int wcwidth(wchar_t ch)
 int utf8_width(const char **start)
 {
        unsigned char *s = (unsigned char *)*start;
-       wchar_t ch;
+       ucs_char_t ch;
 
        if (*s < 0x80) {
                /* 0xxxxxxx */
@@ -235,12 +237,19 @@ static void print_spaces(int count)
 /*
  * Wrap the text, if necessary. The variable indent is the indent for the
  * first line, indent2 is the indent for all other lines.
+ * If indent is negative, assume that already -indent columns have been
+ * consumed (and no extra indent is necessary for the first line).
  */
-void print_wrapped_text(const char *text, int indent, int indent2, int width)
+int print_wrapped_text(const char *text, int indent, int indent2, int width)
 {
        int w = indent, assume_utf8 = is_utf8(text);
        const char *bol = text, *space = NULL;
 
+       if (indent < 0) {
+               w = -indent;
+               space = text;
+       }
+
        for (;;) {
                char c = *text;
                if (!c || isspace(c)) {
@@ -251,10 +260,9 @@ void print_wrapped_text(const char *text, int indent, int indent2, int width)
                                else
                                        print_spaces(indent);
                                fwrite(start, text - start, 1, stdout);
-                               if (!c) {
-                                       putchar('\n');
-                                       return;
-                               } else if (c == '\t')
+                               if (!c)
+                                       return w;
+                               else if (c == '\t')
                                        w |= 0x07;
                                space = text;
                                w++;
@@ -262,7 +270,7 @@ void print_wrapped_text(const char *text, int indent, int indent2, int width)
                        }
                        else {
                                putchar('\n');
-                               text = bol = space + 1;
+                               text = bol = space + isspace(*space);
                                space = NULL;
                                w = indent = indent2;
                        }
@@ -275,6 +283,7 @@ void print_wrapped_text(const char *text, int indent, int indent2, int width)
                        text++;
                }
        }
+       return w;
 }
 
 int is_encoding_utf8(const char *name)
@@ -291,11 +300,17 @@ int is_encoding_utf8(const char *name)
  * with iconv.  If the conversion fails, returns NULL.
  */
 #ifndef NO_ICONV
+#ifdef OLD_ICONV
+       typedef const char * iconv_ibp;
+#else
+       typedef char * iconv_ibp;
+#endif
 char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding)
 {
        iconv_t conv;
        size_t insz, outsz, outalloc;
-       char *out, *outpos, *cp;
+       char *out, *outpos;
+       iconv_ibp cp;
 
        if (!in_encoding)
                return NULL;
@@ -307,7 +322,7 @@ char *reencode_string(const char *in, const char *out_encoding, const char *in_e
        outalloc = outsz + 1; /* for terminating NUL */
        out = xmalloc(outalloc);
        outpos = out;
-       cp = (char *)in;
+       cp = (iconv_ibp)in;
 
        while (1) {
                size_t cnt = iconv(conv, &cp, &insz, &outpos, &outsz);
diff --git a/utf8.h b/utf8.h
index a07c5a88af63d41ae963f230510a33d78b68a525..15db6f1f27ef7a1f056d5b6adca901f092036f82 100644 (file)
--- a/utf8.h
+++ b/utf8.h
@@ -5,7 +5,7 @@ int utf8_width(const char **start);
 int is_utf8(const char *text);
 int is_encoding_utf8(const char *name);
 
-void print_wrapped_text(const char *text, int indent, int indent2, int len);
+int print_wrapped_text(const char *text, int indent, int indent2, int len);
 
 #ifndef NO_ICONV
 char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding);