Merge branch 'cc/help'
authorJunio C Hamano <gitster@pobox.com>
Thu, 13 Dec 2007 01:46:16 +0000 (17:46 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 13 Dec 2007 01:46:16 +0000 (17:46 -0800)
* cc/help:
RPM spec: Adjust htmldir
git-help -w: do not require to be in git repository
git.spec.in: remove python_path
Documentation: rename git.texi to user-manual.texi
Add git-browse-help to .gitignore
git-help -i: show info documentation from matching version of git
git-help -i: invoke info with document and node name
Documentation: add gitman.info target
Documentation: describe -w/--web option to "git-help".
Use {web,instaweb,help}.browser config options.
git-help: add -w|--web option to display html man page in a browser.
Documentation: describe -i/--info option to "git-help"
git-help: add -i|--info option to display info page.

41 files changed:
Documentation/diff-format.txt
Documentation/diff-options.txt
Documentation/git-add.txt
Documentation/git-apply.txt
Documentation/git-shortlog.txt
Documentation/glossary.txt
Makefile
builtin-blame.c
builtin-commit.c
builtin-diff.c
builtin-fast-export.c
builtin-log.c
builtin-pack-objects.c
builtin-reset.c
builtin-shortlog.c
builtin-tag.c
cache.h
color.c
config.mak.in
configure.ac
contrib/emacs/git.el
diff.c
environment.c
git-checkout.sh
git-clone.sh
git-merge-one-file.sh
git-send-email.perl
git-svn.perl
http-push.c
merge-recursive.c
pager.c
perl/Makefile.PL
revision.c
revision.h
t/lib-git-svn.sh
t/t4015-diff-whitespace.sh
t/t7004-tag.sh
t/t7201-co.sh
t/t9107-git-svn-migrate.sh
t/t9119-git-svn-info.sh
tree-diff.c
index 2c3a4c433b2a6d2b0846243a4f1dbebeed45236e..400cbb3b1c120b93278472678ee7bdb87a74f95b 100644 (file)
@@ -84,3 +84,64 @@ all parents.
 
 
 include::diff-generate-patch.txt[]
+
+
+other diff formats
+------------------
+
+The `--summary` option describes newly added, deleted, renamed and
+copied files.  The `--stat` option adds diffstat(1) graph to the
+output.  These options can be combined with other options, such as
+`-p`, and are meant for human consumption.
+
+When showing a change that involves a rename or a copy, `--stat` output
+formats the pathnames compactly by combining common prefix and suffix of
+the pathnames.  For example, a change that moves `arch/i386/Makefile` to
+`arch/x86/Makefile` while modifying 4 lines will be shown like this:
+
+------------------------------------
+arch/{i386 => x86}/Makefile    |   4 +--
+------------------------------------
+
+The `--numstat` option gives the diffstat(1) information but is designed
+for easier machine consumption.  An entry in `--numstat` output looks
+like this:
+
+----------------------------------------
+1      2       README
+3      1       arch/{i386 => x86}/Makefile
+----------------------------------------
+
+That is, from left to right:
+
+. the number of added lines;
+. a tab;
+. the number of deleted lines;
+. a tab;
+. pathname (possibly with rename/copy information);
+. a newline.
+
+When `-z` output option is in effect, the output is formatted this way:
+
+----------------------------------------
+1      2       README NUL
+3      1       NUL arch/i386/Makefile NUL arch/x86/Makefile NUL
+----------------------------------------
+
+That is:
+
+. the number of added lines;
+. a tab;
+. the number of deleted lines;
+. a tab;
+. a NUL (only exists if renamed/copied);
+. pathname in preimage;
+. a NUL (only exists if renamed/copied);
+. pathname in postimage (only exists if renamed/copied);
+. a NUL.
+
+The extra `NUL` before the preimage path in renamed case is to allow
+scripts that read the output to tell if the current record being read is
+a single-path record or a rename/copy record without reading ahead.
+After reading added and deleted lines, reading up to `NUL` would yield
+the pathname, but if that is `NUL`, the record will show two paths.
index d0154bbc0a2f868b3f5f1c63dcffd1fc9355ebc3..5d22b7b58c5950fe70d09e0bb7384179ae30220f 100644 (file)
@@ -175,19 +175,19 @@ endif::git-format-patch[]
        Shorthand for "--text".
 
 --ignore-space-at-eol::
-       Ignore changes in white spaces at EOL.
+       Ignore changes in whitespace at EOL.
 
 --ignore-space-change::
-       Ignore changes in amount of white space.  This ignores white
-       space at line end, and consider all other sequences of one or
-       more white space characters to be equivalent.
+       Ignore changes in amount of whitespace.  This ignores whitespace
+       at line end, and considers all other sequences of one or
+       more whitespace characters to be equivalent.
 
 -b::
        Shorthand for "--ignore-space-change".
 
 --ignore-all-space::
-       Ignore white space when comparing lines.  This ignores
-       difference even if one line has white space where the other
+       Ignore whitespace when comparing lines.  This ignores
+       differences even if one line has whitespace where the other
        line has none.
 
 -w::
index bf94cd43bdd8a9e113af37bec5acd568dd1b3930..721ca998c1988de3cb29c43286a2ffe2e516be4c 100644 (file)
@@ -65,7 +65,7 @@ OPTIONS
        operation to a subset of the working tree. See ``Interactive
        mode'' for details.
 
--p, \--patch:
+-p, \--patch::
        Similar to Interactive mode but the initial command loop is
        bypassed and the 'patch' subcommand is invoked using each of
        the specified filepatterns before exiting.
index bae3e7b909736b0827b9fda783d068ade997c466..9ec38f92ba2f9ac51b5cd6ade69758ded31194d6 100644 (file)
@@ -119,7 +119,7 @@ discouraged.
 
 --no-add::
        When applying a patch, ignore additions made by the
-       patch.  This can be used to extract common part between
+       patch.  This can be used to extract the common part between
        two files by first running `diff` on them and applying
        the result with this option, which would apply the
        deletion part but not addition part.
index 2220ef6ea8d3bfa58f3c1279dfcf4f735c2dae0a..e14720b73ff6b44d0300e9a8ad0fbd781738440d 100644 (file)
@@ -8,8 +8,8 @@ git-shortlog - Summarize 'git log' output
 SYNOPSIS
 --------
 [verse]
-git-log --pretty=short | 'git-shortlog' [-h] [-n] [-s]
-git-shortlog [-n|--numbered] [-s|--summary] [<committish>...]
+git-log --pretty=short | 'git-shortlog' [-h] [-n] [-s] [-e]
+git-shortlog [-n|--numbered] [-s|--summary] [-e|--email] [<committish>...]
 
 DESCRIPTION
 -----------
@@ -32,6 +32,9 @@ OPTIONS
 -s, \--summary::
        Suppress commit description and provide a commit count summary only.
 
+-e, \--email::
+       Show the email address of each author.
+
 FILES
 -----
 
index fc1874424e26a2f95574d72bf3fc1c71a3b1a1b6..65f55e4ced20b7a957b83be3d47764dcfe3238c5 100644 (file)
@@ -244,8 +244,7 @@ This commit is referred to as a "merge commit", or sometimes just a
        The unique identifier of an <<def_object,object>>. The <<def_hash,hash>>
        of the object's contents using the Secure Hash Algorithm
        1 and usually represented by the 40 character hexadecimal encoding of
-       the <<def_hash,hash>> of the object (possibly followed by
-       a white space).
+       the <<def_hash,hash>> of the object.
 
 [[def_object_type]]object type::
        One of the identifiers
index f20b8c0092282778ecc2d68d2df49d3f006dce91..16de2f3e252ad2b3324c0c439ad6e771e4ca358c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1033,7 +1033,7 @@ install: all
        $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
        $(INSTALL) git$X '$(DESTDIR_SQ)$(bindir_SQ)'
        $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
-       $(MAKE) -C perl prefix='$(prefix_SQ)' install
+       $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install
 ifndef NO_TCLTK
        $(MAKE) -C gitk-git install
        $(MAKE) -C git-gui install
index c158d319dce78c6b1f0cfeffd91ee565a2d14eff..5466d01f9a5917dbba4108669ee4513b581ff2c9 100644 (file)
@@ -130,6 +130,14 @@ static void origin_decref(struct origin *o)
        }
 }
 
+static void drop_origin_blob(struct origin *o)
+{
+       if (o->file.ptr) {
+               free(o->file.ptr);
+               o->file.ptr = NULL;
+       }
+}
+
 /*
  * Each group of lines is described by a blame_entry; it can be split
  * as we pass blame to the parents.  They form a linked list in the
@@ -380,6 +388,7 @@ static struct origin *find_origin(struct scoreboard *sb,
                }
        }
        diff_flush(&diff_opts);
+       diff_tree_release_paths(&diff_opts);
        if (porigin) {
                /*
                 * Create a freestanding copy that is not part of
@@ -436,6 +445,7 @@ static struct origin *find_rename(struct scoreboard *sb,
                }
        }
        diff_flush(&diff_opts);
+       diff_tree_release_paths(&diff_opts);
        return porigin;
 }
 
@@ -1157,7 +1167,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
                }
        }
        diff_flush(&diff_opts);
-
+       diff_tree_release_paths(&diff_opts);
        return retval;
 }
 
@@ -1274,8 +1284,13 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
                }
 
  finish:
-       for (i = 0; i < MAXPARENT; i++)
-               origin_decref(parent_origin[i]);
+       for (i = 0; i < MAXPARENT; i++) {
+               if (parent_origin[i]) {
+                       drop_origin_blob(parent_origin[i]);
+                       origin_decref(parent_origin[i]);
+               }
+       }
+       drop_origin_blob(origin);
 }
 
 /*
index b6b81d531d8b560315298353e5b0ae377581c566..9cb7589ac68172591ae458a20031e7dedd65adee 100644 (file)
@@ -660,12 +660,16 @@ static void print_summary(const char *prefix, const unsigned char *sha1)
        rev.verbose_header = 1;
        rev.show_root_diff = 1;
        rev.commit_format = get_commit_format("format:%h: %s");
-       rev.always_show_header = 1;
+       rev.always_show_header = 0;
 
        printf("Created %scommit ", initial_commit ? "initial " : "");
 
-       log_tree_commit(&rev, commit);
-       printf("\n");
+       if (!log_tree_commit(&rev, commit)) {
+               struct strbuf buf = STRBUF_INIT;
+               format_commit_message(commit, "%h: %s", &buf);
+               printf("%s\n", buf.buf);
+               strbuf_release(&buf);
+       }
 }
 
 int git_commit_config(const char *k, const char *v)
index 1b615991e1fc6aaa329811cc9f7b615e20b00917..55fb84c730e4141bdb53fec6602a2bdafc99f8fd 100644 (file)
@@ -176,18 +176,6 @@ static int builtin_diff_combined(struct rev_info *revs,
        return 0;
 }
 
-void add_head(struct rev_info *revs)
-{
-       unsigned char sha1[20];
-       struct object *obj;
-       if (get_sha1("HEAD", sha1))
-               return;
-       obj = parse_object(sha1);
-       if (!obj)
-               return;
-       add_pending_object(revs, obj, "HEAD");
-}
-
 static void refresh_index_quietly(void)
 {
        struct lock_file *lock_file;
@@ -272,7 +260,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
                        if (!strcmp(arg, "--"))
                                break;
                        else if (!strcmp(arg, "--cached")) {
-                               add_head(&rev);
+                               add_head_to_pending(&rev);
                                if (!rev.pending.nr)
                                        die("No HEAD commit to compare with (yet)");
                                break;
index 2136aadfd7831828ee29fbfa9ae7974c65271dee..ef27eee71bdef2cac6f751e07b1da71588989b03 100755 (executable)
@@ -103,7 +103,7 @@ static void handle_object(const unsigned char *sha1)
        mark_object(object);
 
        printf("blob\nmark :%d\ndata %lu\n", last_idnum, size);
-       if (fwrite(buf, size, 1, stdout) != 1)
+       if (size && fwrite(buf, size, 1, stdout) != 1)
                die ("Could not write blob %s", sha1_to_hex(sha1));
        printf("\n");
 
index b6a11220e258468bddd92181bf18ce55343abf2e..cc3cc9069a824740d2d5cceba95597e036f67120 100644 (file)
@@ -18,9 +18,6 @@
 static int default_show_root = 1;
 static const char *fmt_patch_subject_prefix = "PATCH";
 
-/* this is in builtin-diff.c */
-void add_head(struct rev_info *revs);
-
 static void add_name_decoration(const char *prefix, const char *name, struct object *obj)
 {
        int plen = strlen(prefix);
@@ -746,7 +743,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                         * does not have.
                         */
                        rev.pending.objects[0].item->flags |= UNINTERESTING;
-                       add_head(&rev);
+                       add_head_to_pending(&rev);
                }
                /*
                 * Otherwise, it is "format-patch -22 HEAD", and/or
index 250dc56ab5121d3ffda916228ed3dbf71d0def88..7dd0d7f82605798a81e731c8e0db1b5c009e1e08 100644 (file)
@@ -1709,6 +1709,16 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
                                list++;
                                sub_size--;
                        }
+                       if (!sub_size) {
+                               /*
+                                * It is possible for some "paths" to have
+                                * so many objects that no hash boundary
+                                * might be found.  Let's just steal the
+                                * exact half in that case.
+                                */
+                               sub_size = victim->remaining / 2;
+                               list -= sub_size;
+                       }
                        target->list = list;
                        victim->list_size -= sub_size;
                        victim->remaining -= sub_size;
index 4c61025aaef96ae9f8bcabe3fd4ad6c0fc2beba3..713c2d5346e8dc7e502beffc256bfdcad9da6ad5 100644 (file)
@@ -158,6 +158,7 @@ static int read_from_tree(const char *prefix, const char **argv,
                return 1;
        diffcore_std(&opt);
        diff_flush(&opt);
+       diff_tree_release_paths(&opt);
 
        if (!index_was_discarded)
                /* The index is still clobbered from do_diff_cache() */
index b9cc134443feb4f9573166faf0745074384e0c21..3d8d7094ab8f85f557cf3bd58e408c8ab4272f08 100644 (file)
@@ -11,6 +11,7 @@ static const char shortlog_usage[] =
 "git-shortlog [-n] [-s] [<commit-id>... ]";
 
 static char *common_repo_prefix;
+static int email;
 
 static int compare_by_number(const void *a1, const void *a2)
 {
@@ -57,6 +58,14 @@ static void insert_one_record(struct path_list *list,
                        len--;
                namebuf[len] = '\0';
        }
+       else
+               len = strlen(namebuf);
+
+       if (email) {
+               size_t room = sizeof(namebuf) - len - 1;
+               int maillen = eoemail - boemail + 1;
+               snprintf(namebuf + len, room, " %.*s", maillen, boemail);
+       }
 
        buffer = xstrdup(namebuf);
        item = path_list_insert(buffer, list);
@@ -219,6 +228,9 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
                else if (!strcmp(argv[1], "-s") ||
                                !strcmp(argv[1], "--summary"))
                        summary = 1;
+               else if (!strcmp(argv[1], "-e") ||
+                        !strcmp(argv[1], "--email"))
+                       email = 1;
                else if (!prefixcmp(argv[1], "-w")) {
                        wrap_lines = 1;
                        parse_wrap_args(argv[1], &in1, &in2, &wrap);
@@ -237,9 +249,10 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
 
        read_mailmap(&mailmap, ".mailmap", &common_repo_prefix);
 
+       /* assume HEAD if from a tty */
+       if (!rev.pending.nr && isatty(0))
+               add_head_to_pending(&rev);
        if (rev.pending.nr == 0) {
-               if (isatty(0))
-                       fprintf(stderr, "(reading log to summarize from standard input)\n");
                read_from_stdin(&list);
        }
        else
@@ -253,7 +266,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
                struct path_list *onelines = list.items[i].util;
 
                if (summary) {
-                       printf("%s: %d\n", list.items[i].path, onelines->nr);
+                       printf("%6d\t%s\n", onelines->nr, list.items[i].path);
                } else {
                        printf("%s (%d):\n", list.items[i].path, onelines->nr);
                        for (j = onelines->nr - 1; j >= 0; j--) {
index 517419fd3d885d677e8c2eeb533fc14f3df501f5..274901a408fa0d1d988da35d637ead7ca565552e 100644 (file)
@@ -236,14 +236,18 @@ static const char tag_template[] =
        "# Write a tag message\n"
        "#\n";
 
+static void set_signingkey(const char *value)
+{
+       if (strlcpy(signingkey, value, sizeof(signingkey)) >= sizeof(signingkey))
+               die("signing key value too long (%.10s...)", value);
+}
+
 static int git_tag_config(const char *var, const char *value)
 {
        if (!strcmp(var, "user.signingkey")) {
                if (!value)
                        die("user.signingkey without value");
-               if (strlcpy(signingkey, value, sizeof(signingkey))
-                                               >= sizeof(signingkey))
-                       die("user.signingkey value too long");
+               set_signingkey(value);
                return 0;
        }
 
@@ -396,6 +400,10 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 
        argc = parse_options(argc, argv, options, git_tag_usage, 0);
 
+       if (keyid) {
+               sign = 1;
+               set_signingkey(keyid);
+       }
        if (sign)
                annotate = 1;
 
diff --git a/cache.h b/cache.h
index 1bcb3df7a20b7eb90c15807b92ae0e016266d5fd..27d90fe543b97eac91f61bf96f170c32d735e44d 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -608,7 +608,7 @@ extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char
 /* pager.c */
 extern void setup_pager(void);
 extern char *pager_program;
-extern int pager_in_use;
+extern int pager_in_use(void);
 extern int pager_use_color;
 
 extern char *editor_program;
diff --git a/color.c b/color.c
index 7bd424a8f6012859f40f2aa6210e7d4ce7686dc0..7f66c29fae57abceda30b1257c2a66626f3be0b2 100644 (file)
--- a/color.c
+++ b/color.c
@@ -135,7 +135,7 @@ int git_config_colorbool(const char *var, const char *value, int stdout_is_tty)
  auto_color:
        if (stdout_is_tty < 0)
                stdout_is_tty = isatty(1);
-       if (stdout_is_tty || (pager_in_use && pager_use_color)) {
+       if (stdout_is_tty || (pager_in_use() && pager_use_color)) {
                char *term = getenv("TERM");
                if (term && strcmp(term, "dumb"))
                        return 1;
index 7d5df9bf3c5dc898a68b538bae55f3d44dbc01ff..15fb26cb9226bd8c65cb6869ef38fe0af0b1260c 100644 (file)
@@ -23,6 +23,7 @@ VPATH = @srcdir@
 export exec_prefix mandir
 export srcdir VPATH
 
+ASCIIDOC8=@ASCIIDOC8@
 NEEDS_SSL_WITH_CRYPTO=@NEEDS_SSL_WITH_CRYPTO@
 NO_OPENSSL=@NO_OPENSSL@
 NO_CURL=@NO_CURL@
index dd4b4eb9822f131f0efc746013a803c4adba02d2..6f641e32f0d9e802f6fff72cde7388b7a3521769 100644 (file)
@@ -122,6 +122,27 @@ if test -z "$NO_TCLTK"; then
     AC_SUBST(TCLTK_PATH)
   fi
 fi
+AC_CHECK_PROGS(ASCIIDOC, [asciidoc])
+if test -n "$ASCIIDOC"; then
+       AC_MSG_CHECKING([for asciidoc version])
+       asciidoc_version=`$ASCIIDOC --version 2>&1`
+       case "${asciidoc_version}" in
+       asciidoc' '8*)
+               ASCIIDOC8=YesPlease
+               AC_MSG_RESULT([${asciidoc_version} > 7])
+               ;;
+       asciidoc' '7*)
+               ASCIIDOC8=
+               AC_MSG_RESULT([${asciidoc_version}])
+               ;;
+       *)
+               ASCIIDOC8=
+               AC_MSG_RESULT([${asciidoc_version} (unknown)])
+               ;;
+       esac
+fi
+AC_SUBST(ASCIIDOC8)
+
 
 ## Checks for libraries.
 AC_MSG_NOTICE([CHECKS for libraries])
index e147da0596a880e864fb707192b5bc856cb3daba..28a4899a0a46d67978280a1d0657f4b2b98be1d7 100644 (file)
@@ -49,6 +49,7 @@
 (eval-when-compile (require 'cl))
 (require 'ewoc)
 (require 'log-edit)
+(require 'easymenu)
 
 
 ;;;; Customizations
@@ -1297,7 +1298,47 @@ Return the list of files that haven't been handled."
     (define-key toggle-map "i" 'git-toggle-show-ignored)
     (define-key toggle-map "k" 'git-toggle-show-unknown)
     (define-key toggle-map "m" 'git-toggle-all-marks)
-    (setq git-status-mode-map map)))
+    (setq git-status-mode-map map))
+  (easy-menu-define git-menu git-status-mode-map
+    "Git Menu"
+    `("Git"
+      ["Refresh" git-refresh-status t]
+      ["Commit" git-commit-file t]
+      ("Merge"
+       ["Next Unmerged File" git-next-unmerged-file t]
+       ["Prev Unmerged File" git-prev-unmerged-file t]
+       ["Mark as Resolved" git-resolve-file t]
+       ["Interactive Merge File" git-find-file-imerge t]
+       ["Diff Against Common Base File" git-diff-file-base t]
+       ["Diff Combined" git-diff-file-combined t]
+       ["Diff Against Merge Head" git-diff-file-merge-head t]
+       ["Diff Against Mine" git-diff-file-mine t]
+       ["Diff Against Other" git-diff-file-other t])
+      "--------"
+      ["Add File" git-add-file t]
+      ["Revert File" git-revert-file t]
+      ["Ignore File" git-ignore-file t]
+      ["Remove File" git-remove-file t]
+      "--------"
+      ["Find File" git-find-file t]
+      ["View File" git-view-file t]
+      ["Diff File" git-diff-file t]
+      ["Interactive Diff File" git-diff-file-idiff t]
+      ["Log" git-log-file t]
+      "--------"
+      ["Mark" git-mark-file t]
+      ["Mark All" git-mark-all t]
+      ["Unmark" git-unmark-file t]
+      ["Unmark All" git-unmark-all t]
+      ["Toggle All Marks" git-toggle-all-marks t]
+      ["Hide Handled Files" git-remove-handled t]
+      "--------"
+      ["Show Uptodate Files" git-toggle-show-uptodate :style toggle :selected git-show-uptodate]
+      ["Show Ignored Files" git-toggle-show-ignored :style toggle :selected git-show-ignored]
+      ["Show Unknown Files" git-toggle-show-unknown :style toggle :selected git-show-unknown]
+      "--------"
+      ["Quit" git-status-quit t])))
+
 
 ;; git mode should only run in the *git status* buffer
 (put 'git-status-mode 'mode-class 'special)
diff --git a/diff.c b/diff.c
index f780e3e8e67f4b1e07ef1d70ab3b9f101ff6b868..9c79ee289151e9fc3eb1aaad91dd979bfee63102 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -734,7 +734,9 @@ struct diffstat_t {
        int nr;
        int alloc;
        struct diffstat_file {
+               char *from_name;
                char *name;
+               char *print_name;
                unsigned is_unmerged:1;
                unsigned is_binary:1;
                unsigned is_renamed:1;
@@ -755,11 +757,14 @@ static struct diffstat_file *diffstat_add(struct diffstat_t *diffstat,
        }
        diffstat->files[diffstat->nr++] = x;
        if (name_b) {
-               x->name = pprint_rename(name_a, name_b);
+               x->from_name = xstrdup(name_a);
+               x->name = xstrdup(name_b);
                x->is_renamed = 1;
        }
-       else
+       else {
+               x->from_name = NULL;
                x->name = xstrdup(name_a);
+       }
        return x;
 }
 
@@ -803,6 +808,28 @@ static void show_graph(char ch, int cnt, const char *set, const char *reset)
        printf("%s", reset);
 }
 
+static void fill_print_name(struct diffstat_file *file)
+{
+       char *pname;
+
+       if (file->print_name)
+               return;
+
+       if (!file->is_renamed) {
+               struct strbuf buf;
+               strbuf_init(&buf, 0);
+               if (quote_c_style(file->name, &buf, NULL, 0)) {
+                       pname = strbuf_detach(&buf, NULL);
+               } else {
+                       pname = file->name;
+                       strbuf_release(&buf);
+               }
+       } else {
+               pname = pprint_rename(file->from_name, file->name);
+       }
+       file->print_name = pname;
+}
+
 static void show_stats(struct diffstat_t* data, struct diff_options *options)
 {
        int i, len, add, del, total, adds = 0, dels = 0;
@@ -836,19 +863,8 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
        for (i = 0; i < data->nr; i++) {
                struct diffstat_file *file = data->files[i];
                int change = file->added + file->deleted;
-
-               if (!file->is_renamed) {  /* renames are already quoted by pprint_rename */
-                       struct strbuf buf;
-                       strbuf_init(&buf, 0);
-                       if (quote_c_style(file->name, &buf, NULL, 0)) {
-                               free(file->name);
-                               file->name = strbuf_detach(&buf, NULL);
-                       } else {
-                               strbuf_release(&buf);
-                       }
-               }
-
-               len = strlen(file->name);
+               fill_print_name(file);
+               len = strlen(file->print_name);
                if (max_len < len)
                        max_len = len;
 
@@ -873,7 +889,7 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
 
        for (i = 0; i < data->nr; i++) {
                const char *prefix = "";
-               char *name = data->files[i]->name;
+               char *name = data->files[i]->print_name;
                int added = data->files[i]->added;
                int deleted = data->files[i]->deleted;
                int name_len;
@@ -901,17 +917,17 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
                        printf("%s%d%s", add_c, added, reset);
                        printf(" bytes");
                        printf("\n");
-                       goto free_diffstat_file;
+                       continue;
                }
                else if (data->files[i]->is_unmerged) {
                        show_name(prefix, name, len, reset, set);
                        printf("  Unmerged\n");
-                       goto free_diffstat_file;
+                       continue;
                }
                else if (!data->files[i]->is_renamed &&
                         (added + deleted == 0)) {
                        total_files--;
-                       goto free_diffstat_file;
+                       continue;
                }
 
                /*
@@ -933,11 +949,7 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
                show_graph('+', add, add_c, reset);
                show_graph('-', del, del_c, reset);
                putchar('\n');
-       free_diffstat_file:
-               free(data->files[i]->name);
-               free(data->files[i]);
        }
-       free(data->files);
        printf("%s %d files changed, %d insertions(+), %d deletions(-)%s\n",
               set, total_files, adds, dels, reset);
 }
@@ -962,11 +974,7 @@ static void show_shortstats(struct diffstat_t* data)
                                dels += deleted;
                        }
                }
-               free(data->files[i]->name);
-               free(data->files[i]);
        }
-       free(data->files);
-
        printf(" %d files changed, %d insertions(+), %d deletions(-)\n",
               total_files, adds, dels);
 }
@@ -975,6 +983,9 @@ static void show_numstat(struct diffstat_t* data, struct diff_options *options)
 {
        int i;
 
+       if (data->nr == 0)
+               return;
+
        for (i = 0; i < data->nr; i++) {
                struct diffstat_file *file = data->files[i];
 
@@ -982,15 +993,39 @@ static void show_numstat(struct diffstat_t* data, struct diff_options *options)
                        printf("-\t-\t");
                else
                        printf("%d\t%d\t", file->added, file->deleted);
-               if (!file->is_renamed) {
-                       write_name_quoted(file->name, stdout, options->line_termination);
+               if (options->line_termination) {
+                       fill_print_name(file);
+                       if (!file->is_renamed)
+                               write_name_quoted(file->name, stdout,
+                                                 options->line_termination);
+                       else {
+                               fputs(file->print_name, stdout);
+                               putchar(options->line_termination);
+                       }
                } else {
-                       fputs(file->name, stdout);
-                       putchar(options->line_termination);
+                       if (file->is_renamed) {
+                               putchar('\0');
+                               write_name_quoted(file->from_name, stdout, '\0');
+                       }
+                       write_name_quoted(file->name, stdout, '\0');
                }
        }
 }
 
+static void free_diffstat_info(struct diffstat_t *diffstat)
+{
+       int i;
+       for (i = 0; i < diffstat->nr; i++) {
+               struct diffstat_file *f = diffstat->files[i];
+               if (f->name != f->print_name)
+                       free(f->print_name);
+               free(f->name);
+               free(f->from_name);
+               free(f);
+       }
+       free(diffstat->files);
+}
+
 struct checkdiff_t {
        struct xdiff_emit_state xm;
        const char *filename;
@@ -1009,13 +1044,20 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
                int i, spaces = 0, space_before_tab = 0, white_space_at_end = 0;
 
                /* check space before tab */
-               for (i = 1; i < len && (line[i] == ' ' || line[i] == '\t'); i++)
+               for (i = 1; i < len; i++) {
                        if (line[i] == ' ')
                                spaces++;
-               if (line[i - 1] == '\t' && spaces)
-                       space_before_tab = 1;
+                       else if (line[i] == '\t') {
+                               if (spaces) {
+                                       space_before_tab = 1;
+                                       break;
+                               }
+                       }
+                       else
+                               break;
+               }
 
-               /* check white space at line end */
+               /* check whitespace at line end */
                if (line[len - 1] == '\n')
                        len--;
                if (isspace(line[len - 1]))
@@ -1029,7 +1071,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
                                        putchar(',');
                        }
                        if (white_space_at_end)
-                               printf("white space at end");
+                               printf("whitespace at end");
                        printf(":%s ", reset);
                        emit_line_with_ws(1, set, reset, ws, line, len,
                                          data->ws_rule);
@@ -2943,8 +2985,9 @@ void diff_flush(struct diff_options *options)
                        show_numstat(&diffstat, options);
                if (output_format & DIFF_FORMAT_DIFFSTAT)
                        show_stats(&diffstat, options);
-               else if (output_format & DIFF_FORMAT_SHORTSTAT)
+               if (output_format & DIFF_FORMAT_SHORTSTAT)
                        show_shortstats(&diffstat);
+               free_diffstat_info(&diffstat);
                separator++;
        }
 
index f3e3d4138d463520dbe6d709dfbe0803b619456d..18a1c4eec49bfddcb81d6669c83f8f97a218d7bf 100644 (file)
@@ -31,7 +31,6 @@ size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
 size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
 size_t delta_base_cache_limit = 16 * 1024 * 1024;
 char *pager_program;
-int pager_in_use;
 int pager_use_color = 1;
 char *editor_program;
 char *excludes_file;
index f6d58ac044e5afb09855d687d3c1bcc8e2273be3..5621c69d86062c7c75c0b8c2749d34efc78cafb4 100755 (executable)
@@ -2,13 +2,13 @@
 
 OPTIONS_KEEPDASHDASH=t
 OPTIONS_SPEC="\
-git-branch [options] [<branch>] [<paths>...]
+git-checkout [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
+l           create the new branch's reflog
+track       arrange that the new branch tracks 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
+m           merge local modifications into the new branch
 q,quiet     be quiet
 "
 SUBDIRECTORY_OK=Sometimes
index ecf9d89a108484af3f73817e60c523f1dca8fff0..68085a3225cb0047ab3c5764472d3d024e467160 100755 (executable)
@@ -205,7 +205,10 @@ fi
 # it is local
 if base=$(get_repo_base "$repo"); then
        repo="$base"
-       local=yes
+       if test -z "$depth"
+       then
+               local=yes
+       fi
 fi
 
 dir="$2"
@@ -297,7 +300,8 @@ yes)
                                      find objects -type f -print | sed -e 1q)
                        # objects directory should not be empty because
                        # we are cloning!
-                       test -f "$repo/$sample_file" || exit
+                       test -f "$repo/$sample_file" ||
+                               die "fatal: cannot clone empty repository"
                        if ln "$repo/$sample_file" "$GIT_DIR/objects/sample" 2>/dev/null
                        then
                                rm -f "$GIT_DIR/objects/sample"
index 1e7727d2763e744b94f55c2056eccaab12367c9e..9ee3f804520eadb322de3d0ea70a2bf9f092b089 100755 (executable)
@@ -80,6 +80,10 @@ case "${1:-.}${2:-.}${3:-.}" in
                echo "ERROR: $4: Not merging symbolic link changes."
                exit 1
                ;;
+       *,160000,*)
+               echo "ERROR: $4: Not merging conflicting submodule changes."
+               exit 1
+               ;;
        esac
 
        src2=`git-unpack-file $3`
index c0e1dd348c1f62029bb99b16cae290d2e4a77217..1d6f46645328dc2520226aba532c4acb86f5ec32 100755 (executable)
@@ -368,9 +368,10 @@ sub expand_aliases {
 
        $initial_reply_to = $_;
 }
-
-$initial_reply_to =~ s/^\s*<?/</;
-$initial_reply_to =~ s/>?\s*$/>/;
+if (defined $initial_reply_to && $_ ne "") {
+       $initial_reply_to =~ s/^\s*<?/</;
+       $initial_reply_to =~ s/>?\s*$/>/;
+}
 
 if (!defined $smtp_server) {
        foreach (qw( /usr/sbin/sendmail /usr/lib/sendmail )) {
index 9f884eb2132c76b86475b97256e0ed565f84bb2e..54d784469af7b787190e80d277abf2a4782c7d3f 100755 (executable)
@@ -529,7 +529,7 @@ sub cmd_find_rev {
                            "$head history\n";
                }
                my $desired_revision = substr($revision_or_hash, 1);
-               $result = $gs->rev_db_get($desired_revision);
+               $result = $gs->rev_map_get($desired_revision);
        } else {
                my (undef, $rev, undef) = cmt_metadata($revision_or_hash);
                $result = $rev;
@@ -1128,12 +1128,12 @@ sub working_head_info {
                if (defined $url && defined $rev) {
                        next if $max{$url} and $max{$url} < $rev;
                        if (my $gs = Git::SVN->find_by_url($url)) {
-                               my $c = $gs->rev_db_get($rev);
+                               my $c = $gs->rev_map_get($rev);
                                if ($c && $c eq $hash) {
                                        close $fh; # break the pipe
                                        return ($url, $rev, $uuid, $gs);
                                } else {
-                                       $max{$url} ||= $gs->rev_db_max;
+                                       $max{$url} ||= $gs->rev_map_max;
                                }
                        }
                }
@@ -1234,6 +1234,8 @@ sub md5sum {
 package Git::SVN;
 use strict;
 use warnings;
+use Fcntl qw/:DEFAULT :seek/;
+use constant rev_map_fmt => 'NH40';
 use vars qw/$default_repo_id $default_ref_id $_no_metadata $_follow_parent
             $_repack $_repack_flags $_use_svm_props $_head
             $_use_svnsync_props $no_reuse_existing $_minimize_url
@@ -1362,7 +1364,7 @@ sub fetch_all {
        if ($fetch) {
                foreach my $p (sort keys %$fetch) {
                        my $gs = Git::SVN->new($fetch->{$p}, $repo_id, $p);
-                       my $lr = $gs->rev_db_max;
+                       my $lr = $gs->rev_map_max;
                        if (defined $lr) {
                                $base = $lr if ($lr < $base);
                        }
@@ -1897,38 +1899,20 @@ sub last_rev_commit {
                        return ($rev, $c);
                }
        }
-       my $db_path = $self->db_path;
-       unless (-e $db_path) {
+       my $map_path = $self->map_path;
+       unless (-e $map_path) {
                ($self->{last_rev}, $self->{last_commit}) = (undef, undef);
                return (undef, undef);
        }
-       my $offset = -41; # from tail
-       my $rl;
-       open my $fh, '<', $db_path or croak "$db_path not readable: $!\n";
-       sysseek($fh, $offset, 2); # don't care for errors
-       sysread($fh, $rl, 41) == 41 or return (undef, undef);
-       chomp $rl;
-       while (('0' x40) eq $rl && sysseek($fh, 0, 1) != 0) {
-               $offset -= 41;
-               sysseek($fh, $offset, 2); # don't care for errors
-               sysread($fh, $rl, 41) == 41 or return (undef, undef);
-               chomp $rl;
-       }
-       if ($c && $c ne $rl) {
-               die "$db_path and ", $self->refname,
-                   " inconsistent!:\n$c != $rl\n";
-       }
-       my $rev = sysseek($fh, 0, 1) or croak $!;
-       $rev =  ($rev - 41) / 41;
-       close $fh or croak $!;
-       ($self->{last_rev}, $self->{last_commit}) = ($rev, $c);
-       return ($rev, $c);
+       my ($rev, $commit) = $self->rev_map_max(1);
+       ($self->{last_rev}, $self->{last_commit}) = ($rev, $commit);
+       return ($rev, $commit);
 }
 
 sub get_fetch_range {
        my ($self, $min, $max) = @_;
        $max ||= $self->ra->get_latest_revnum;
-       $min ||= $self->rev_db_max;
+       $min ||= $self->rev_map_max;
        (++$min, $max);
 }
 
@@ -2073,7 +2057,7 @@ sub do_git_commit {
                    " was r$lr, but we are about to fetch: ",
                    "r$log_entry->{revision}!\n";
        }
-       if (my $c = $self->rev_db_get($log_entry->{revision})) {
+       if (my $c = $self->rev_map_get($log_entry->{revision})) {
                croak "$log_entry->{revision} = $c already exists! ",
                      "Why are we refetching it?\n";
        }
@@ -2116,14 +2100,14 @@ sub do_git_commit {
                die "Failed to commit, invalid sha1: $commit\n";
        }
 
-       $self->rev_db_set($log_entry->{revision}, $commit, 1);
+       $self->rev_map_set($log_entry->{revision}, $commit, 1);
 
        $self->{last_rev} = $log_entry->{revision};
        $self->{last_commit} = $commit;
        print "r$log_entry->{revision}";
        if (defined $log_entry->{svm_revision}) {
                 print " (\@$log_entry->{svm_revision})";
-                $self->rev_db_set($log_entry->{svm_revision}, $commit,
+                $self->rev_map_set($log_entry->{svm_revision}, $commit,
                                   0, $self->svm_uuid);
        }
        print " = $commit ($self->{ref_id})\n";
@@ -2465,25 +2449,44 @@ sub set_tree {
        }
 }
 
+sub rebuild_from_rev_db {
+       my ($self, $path) = @_;
+       my $r = -1;
+       open my $fh, '<', $path or croak "open: $!";
+       while (<$fh>) {
+               length($_) == 41 or croak "inconsistent size in ($_) != 41";
+               chomp($_);
+               ++$r;
+               next if $_ eq ('0' x 40);
+               $self->rev_map_set($r, $_);
+               print "r$r = $_\n";
+       }
+       close $fh or croak "close: $!";
+       unlink $path or croak "unlink: $!";
+}
+
 sub rebuild {
        my ($self) = @_;
-       my $db_path = $self->db_path;
-       return if (-e $db_path && ! -z $db_path);
+       my $map_path = $self->map_path;
+       return if (-e $map_path && ! -z $map_path);
        return unless ::verify_ref($self->refname.'^0');
-       if (-f $self->{db_root}) {
-               rename $self->{db_root}, $db_path or die
-                    "rename $self->{db_root} => $db_path failed: $!\n";
-               my ($dir, $base) = ($db_path =~ m#^(.*?)/?([^/]+)$#);
-               symlink $base, $self->{db_root} or die
-                    "symlink $base => $self->{db_root} failed: $!\n";
+       if ($self->use_svm_props || $self->no_metadata) {
+               my $rev_db = $self->rev_db_path;
+               $self->rebuild_from_rev_db($rev_db);
+               if ($self->use_svm_props) {
+                       my $svm_rev_db = $self->rev_db_path($self->svm_uuid);
+                       $self->rebuild_from_rev_db($svm_rev_db);
+               }
+               $self->unlink_rev_db_symlink;
                return;
        }
-       print "Rebuilding $db_path ...\n";
-       my ($log, $ctx) = command_output_pipe("log", '--no-color', $self->refname);
-       my $latest;
+       print "Rebuilding $map_path ...\n";
+       my ($log, $ctx) =
+           command_output_pipe(qw/rev-list --pretty=raw --no-color --reverse/,
+                               $self->refname, '--');
        my $full_url = $self->full_url;
        remove_username($full_url);
-       my $svn_uuid;
+       my $svn_uuid = $self->ra_uuid;
        my $c;
        while (<$log>) {
                if ( m{^commit ($::sha1)$} ) {
@@ -2499,46 +2502,85 @@ sub rebuild {
 
                # if we merged or otherwise started elsewhere, this is
                # how we break out of it
-               if ((defined $svn_uuid && ($uuid ne $svn_uuid)) ||
+               if (($uuid ne $svn_uuid) ||
                    ($full_url && $url && ($url ne $full_url))) {
                        next;
                }
-               $latest ||= $rev;
-               $svn_uuid ||= $uuid;
 
-               $self->rev_db_set($rev, $c);
+               $self->rev_map_set($rev, $c);
                print "r$rev = $c\n";
        }
        command_close_pipe($log, $ctx);
-       print "Done rebuilding $db_path\n";
+       print "Done rebuilding $map_path\n";
+       my $rev_db_path = $self->rev_db_path;
+       if (-f $self->rev_db_path) {
+               unlink $self->rev_db_path or croak "unlink: $!";
+       }
+       $self->unlink_rev_db_symlink;
 }
 
-# rev_db:
+# rev_map:
 # Tie::File seems to be prone to offset errors if revisions get sparse,
 # it's not that fast, either.  Tie::File is also not in Perl 5.6.  So
 # one of my favorite modules is out :<  Next up would be one of the DBM
-# modules, but I'm not sure which is most portable...  So I'll just
-# go with something that's plain-text, but still capable of
-# being randomly accessed.  So here's my ultra-simple fixed-width
-# database.  All records are 40 characters + "\n", so it's easy to seek
-# to a revision: (41 * rev) is the byte offset.
-# A record of 40 0s denotes an empty revision.
-# And yes, it's still pretty fast (faster than Tie::File).
+# modules, but I'm not sure which is most portable...
+#
+# This is the replacement for the rev_db format, which was too big
+# and inefficient for large repositories with a lot of sparse history
+# (mainly tags)
+#
+# The format is this:
+#   - 24 bytes for every record,
+#     * 4 bytes for the integer representing an SVN revision number
+#     * 20 bytes representing the sha1 of a git commit
+#   - No empty padding records like the old format
+#     (except the last record, which can be overwritten)
+#   - new records are written append-only since SVN revision numbers
+#     increase monotonically
+#   - lookups on SVN revision number are done via a binary search
+#   - Piping the file to xxd -c24 is a good way of dumping it for
+#     viewing or editing (piped back through xxd -r), should the need
+#     ever arise.
+#   - The last record can be padding revision with an all-zero sha1
+#     This is used to optimize fetch performance when using multiple
+#     "fetch" directives in .git/config
+#
 # These files are disposable unless noMetadata or useSvmProps is set
 
-sub _rev_db_set {
+sub _rev_map_set {
        my ($fh, $rev, $commit) = @_;
-       my $offset = $rev * 41;
-       # assume that append is the common case:
-       seek $fh, 0, 2 or croak $!;
-       my $pos = tell $fh;
-       if ($pos < $offset) {
-               for (1 .. (($offset - $pos) / 41)) {
-                       print $fh (('0' x 40),"\n") or croak $!;
+
+       my $size = (stat($fh))[7];
+       ($size % 24) == 0 or croak "inconsistent size: $size";
+
+       my $wr_offset = 0;
+       if ($size > 0) {
+               sysseek($fh, -24, SEEK_END) or croak "seek: $!";
+               my $read = sysread($fh, my $buf, 24) or croak "read: $!";
+               $read == 24 or croak "read only $read bytes (!= 24)";
+               my ($last_rev, $last_commit) = unpack(rev_map_fmt, $buf);
+               if ($last_commit eq ('0' x40)) {
+                       if ($size >= 48) {
+                               sysseek($fh, -48, SEEK_END) or croak "seek: $!";
+                               $read = sysread($fh, $buf, 24) or
+                                   croak "read: $!";
+                               $read == 24 or
+                                   croak "read only $read bytes (!= 24)";
+                               ($last_rev, $last_commit) =
+                                   unpack(rev_map_fmt, $buf);
+                               if ($last_commit eq ('0' x40)) {
+                                       croak "inconsistent .rev_map\n";
+                               }
+                       }
+                       if ($last_rev >= $rev) {
+                               croak "last_rev is higher!: $last_rev >= $rev";
+                       }
+                       $wr_offset = -24;
                }
        }
-       seek $fh, $offset, 0 or croak $!;
-       print $fh $commit,"\n" or croak $!;
+       sysseek($fh, $wr_offset, SEEK_END) or croak "seek: $!";
+       syswrite($fh, pack(rev_map_fmt, $rev, $commit), 24) == 24 or
+         croak "write: $!";
 }
 
 sub mkfile {
@@ -2551,10 +2593,10 @@ sub mkfile {
        }
 }
 
-sub rev_db_set {
+sub rev_map_set {
        my ($self, $rev, $commit, $update_ref, $uuid) = @_;
        length $commit == 40 or die "arg3 must be a full SHA1 hexsum\n";
-       my $db = $self->db_path($uuid);
+       my $db = $self->map_path($uuid);
        my $db_lock = "$db.lock";
        my $sig;
        if ($update_ref) {
@@ -2569,16 +2611,18 @@ sub rev_db_set {
        # and we can't afford to lose it because rebuild() won't work
        if ($self->use_svm_props || $self->no_metadata) {
                $sync = 1;
-               copy($db, $db_lock) or die "rev_db_set(@_): ",
+               copy($db, $db_lock) or die "rev_map_set(@_): ",
                                           "Failed to copy: ",
                                           "$db => $db_lock ($!)\n";
        } else {
-               rename $db, $db_lock or die "rev_db_set(@_): ",
+               rename $db, $db_lock or die "rev_map_set(@_): ",
                                            "Failed to rename: ",
                                            "$db => $db_lock ($!)\n";
        }
-       open my $fh, '+<', $db_lock or die "Couldn't open $db_lock: $!\n";
-       _rev_db_set($fh, $rev, $commit);
+
+       sysopen(my $fh, $db_lock, O_RDWR | O_CREAT)
+            or croak "Couldn't open $db_lock: $!\n";
+       _rev_map_set($fh, $rev, $commit);
        if ($sync) {
                $fh->flush or die "Couldn't flush $db_lock: $!\n";
                $fh->sync or die "Couldn't sync $db_lock: $!\n";
@@ -2589,7 +2633,7 @@ sub rev_db_set {
                command_noisy('update-ref', '-m', "r$rev",
                              $self->refname, $commit);
        }
-       rename $db_lock, $db or die "rev_db_set(@_): ", "Failed to rename: ",
+       rename $db_lock, $db or die "rev_map_set(@_): ", "Failed to rename: ",
                                    "$db_lock => $db ($!)\n";
        delete $LOCKFILES{$db_lock};
        if ($update_ref) {
@@ -2599,29 +2643,76 @@ sub rev_db_set {
        }
 }
 
-sub rev_db_max {
-       my ($self) = @_;
+# If want_commit, this will return an array of (rev, commit) where
+# commit _must_ be a valid commit in the archive.
+# Otherwise, it'll return the max revision (whether or not the
+# commit is valid or just a 0x40 placeholder).
+sub rev_map_max {
+       my ($self, $want_commit) = @_;
        $self->rebuild;
-       my $db_path = $self->db_path;
-       my @stat = stat $db_path or return 0;
-       ($stat[7] % 41) == 0 or die "$db_path inconsistent size: $stat[7]\n";
-       my $max = $stat[7] / 41;
-       (($max > 0) ? $max - 1 : 0);
+       my $map_path = $self->map_path;
+       stat $map_path or return $want_commit ? (0, undef) : 0;
+       sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";
+       my $size = (stat($fh))[7];
+       ($size % 24) == 0 or croak "inconsistent size: $size";
+
+       if ($size == 0) {
+               close $fh or croak "close: $!";
+               return $want_commit ? (0, undef) : 0;
+       }
+
+       sysseek($fh, -24, SEEK_END) or croak "seek: $!";
+       sysread($fh, my $buf, 24) == 24 or croak "read: $!";
+       my ($r, $c) = unpack(rev_map_fmt, $buf);
+       if ($want_commit && $c eq ('0' x40)) {
+               if ($size < 48) {
+                       return $want_commit ? (0, undef) : 0;
+               }
+               sysseek($fh, -48, SEEK_END) or croak "seek: $!";
+               sysread($fh, $buf, 24) == 24 or croak "read: $!";
+               ($r, $c) = unpack(rev_map_fmt, $buf);
+               if ($c eq ('0'x40)) {
+                       croak "Penultimate record is all-zeroes in $map_path";
+               }
+       }
+       close $fh or croak "close: $!";
+       $want_commit ? ($r, $c) : $r;
 }
 
-sub rev_db_get {
+sub rev_map_get {
        my ($self, $rev, $uuid) = @_;
-       my $ret;
-       my $offset = $rev * 41;
-       my $db_path = $self->db_path($uuid);
-       return undef unless -e $db_path;
-       open my $fh, '<', $db_path or croak $!;
-       if (sysseek($fh, $offset, 0) == $offset) {
-               my $read = sysread($fh, $ret, 40);
-               $ret = undef if ($read != 40 || $ret eq ('0'x40));
+       my $map_path = $self->map_path($uuid);
+       return undef unless -e $map_path;
+
+       sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";
+       my $size = (stat($fh))[7];
+       ($size % 24) == 0 or croak "inconsistent size: $size";
+
+       if ($size == 0) {
+               close $fh or croak "close: $fh";
+               return undef;
        }
-       close $fh or croak $!;
-       $ret;
+
+       my ($l, $u) = (0, $size - 24);
+       my ($r, $c, $buf);
+
+       while ($l <= $u) {
+               my $i = int(($l/24 + $u/24) / 2) * 24;
+               sysseek($fh, $i, SEEK_SET) or croak "seek: $!";
+               sysread($fh, my $buf, 24) == 24 or croak "read: $!";
+               my ($r, $c) = unpack('NH40', $buf);
+
+               if ($r < $rev) {
+                       $l = $i + 24;
+               } elsif ($r > $rev) {
+                       $u = $i - 24;
+               } else { # $r == $rev
+                       close($fh) or croak "close: $!";
+                       return $c eq ('0' x 40) ? undef : $c;
+               }
+       }
+       close($fh) or croak "close: $!";
+       undef;
 }
 
 # Finds the first svn revision that exists on (if $eq_ok is true) or
@@ -2633,7 +2724,7 @@ sub find_rev_before {
        --$rev unless $eq_ok;
        $min_rev ||= 1;
        while ($rev >= $min_rev) {
-               if (my $c = $self->rev_db_get($rev)) {
+               if (my $c = $self->rev_map_get($rev)) {
                        return ($rev, $c);
                }
                --$rev;
@@ -2648,9 +2739,9 @@ sub find_rev_before {
 sub find_rev_after {
        my ($self, $rev, $eq_ok, $max_rev) = @_;
        ++$rev unless $eq_ok;
-       $max_rev ||= $self->rev_db_max();
+       $max_rev ||= $self->rev_map_max;
        while ($rev <= $max_rev) {
-               if (my $c = $self->rev_db_get($rev)) {
+               if (my $c = $self->rev_map_get($rev)) {
                        return ($rev, $c);
                }
                ++$rev;
@@ -2673,13 +2764,32 @@ sub _new {
        bless {
                ref_id => $ref_id, dir => $dir, index => "$dir/index",
                path => $path, config => "$ENV{GIT_DIR}/svn/config",
-               db_root => "$dir/.rev_db", repo_id => $repo_id }, $class;
+               map_root => "$dir/.rev_map", repo_id => $repo_id }, $class;
 }
 
-sub db_path {
+# for read-only access of old .rev_db formats
+sub unlink_rev_db_symlink {
+       my ($self) = @_;
+       my $link = $self->rev_db_path;
+       $link =~ s/\.[\w-]+$// or croak "missing UUID at the end of $link";
+       if (-l $link) {
+               unlink $link or croak "unlink: $link failed!";
+       }
+}
+
+sub rev_db_path {
+       my ($self, $uuid) = @_;
+       my $db_path = $self->map_path($uuid);
+       $db_path =~ s{/\.rev_map\.}{/\.rev_db\.}
+           or croak "map_path: $db_path does not contain '/.rev_map.' !";
+       $db_path;
+}
+
+# the new replacement for .rev_db
+sub map_path {
        my ($self, $uuid) = @_;
        $uuid ||= $self->ra_uuid;
-       "$self->{db_root}.$uuid";
+       "$self->{map_root}.$uuid";
 }
 
 sub uri_encode {
@@ -3763,7 +3873,7 @@ sub gs_fetch_loop_common {
 
                        foreach my $gs ($self->match_globs(\%exists, $paths,
                                                           $globs, $r)) {
-                               if ($gs->rev_db_max >= $r) {
+                               if ($gs->rev_map_max >= $r) {
                                        next;
                                }
                                next unless $gs->match_paths($paths, $r);
@@ -3792,8 +3902,9 @@ sub gs_fetch_loop_common {
                # pre-fill the .rev_db since it'll eventually get filled in
                # with '0' x40 if something new gets committed
                foreach my $gs (@$gsv) {
-                       next if defined $gs->rev_db_get($max);
-                       $gs->rev_db_set($max, 0 x40);
+                       next if $gs->rev_map_max >= $max;
+                       next if defined $gs->rev_map_get($max);
+                       $gs->rev_map_set($max, 0 x40);
                }
                foreach my $g (@$globs) {
                        my $k = "svn-remote.$g->{remote}.$g->{t}-maxRev";
@@ -3969,39 +4080,7 @@ sub cmt_showable {
 }
 
 sub log_use_color {
-       return 1 if $color;
-       my ($dc, $dcvar);
-       $dcvar = 'color.diff';
-       $dc = `git-config --get $dcvar`;
-       if ($dc eq '') {
-               # nothing at all; fallback to "diff.color"
-               $dcvar = 'diff.color';
-               $dc = `git-config --get $dcvar`;
-       }
-       chomp($dc);
-       if ($dc eq 'auto') {
-               my $pc;
-               $pc = `git-config --get color.pager`;
-               if ($pc eq '') {
-                       # does not have it -- fallback to pager.color
-                       $pc = `git-config --bool --get pager.color`;
-               }
-               else {
-                       $pc = `git-config --bool --get color.pager`;
-                       if ($?) {
-                               $pc = 'false';
-                       }
-               }
-               chomp($pc);
-               if (-t *STDOUT || (defined $pager && $pc eq 'true')) {
-                       return ($ENV{TERM} && $ENV{TERM} ne 'dumb');
-               }
-               return 0;
-       }
-       return 0 if $dc eq 'never';
-       return 1 if $dc eq 'always';
-       chomp($dc = `git-config --bool --get $dcvar`);
-       return ($dc eq 'true');
+       return $color || Git->repository->get_colorbool('color.diff');
 }
 
 sub git_svn_log_cmd {
@@ -4030,7 +4109,7 @@ sub git_svn_log_cmd {
        push @cmd, @log_opts;
        if (defined $r_max && $r_max == $r_min) {
                push @cmd, '--max-count=1';
-               if (my $c = $gs->rev_db_get($r_max)) {
+               if (my $c = $gs->rev_map_get($r_max)) {
                        push @cmd, $c;
                }
        } elsif (defined $r_max) {
@@ -4060,6 +4139,7 @@ sub config_pager {
        } elsif (length $pager == 0 || $pager eq 'cat') {
                $pager = undef;
        }
+       $ENV{GIT_PAGER_IN_USE} = defined($pager);
 }
 
 sub run_pager {
@@ -4311,6 +4391,16 @@ package Git::SVN::Migration;
 #              --use-separate-remotes option in git-clone (now default)
 #            - we do not automatically migrate to this (following
 #              the example set by core git)
+#
+# v5 layout: .rev_db.$UUID => .rev_map.$UUID
+#            - newer, more-efficient format that uses 24-bytes per record
+#              with no filler space.
+#            - use xxd -c24 < .rev_map.$UUID to view and debug
+#            - This is a one-way migration, repositories updated to the
+#              new format will not be able to use old git-svn without
+#              rebuilding the .rev_db.  Rebuilding the rev_db is not
+#              possible if noMetadata or useSvmProps are set; but should
+#              be no problem for users that use the (sensible) defaults.
 use strict;
 use warnings;
 use Carp qw/croak/;
index 78283b4de3b9111d87368df747daa96b5f6c09c3..fffbe9ccb42e305d898a25a126918db0883b11cb 100644 (file)
@@ -1275,8 +1275,6 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
        char *ep;
        char timeout_header[25];
        struct remote_lock *lock = NULL;
-       XML_Parser parser = XML_ParserCreate(NULL);
-       enum XML_Status result;
        struct curl_slist *dav_headers = NULL;
        struct xml_ctx ctx;
 
@@ -1345,6 +1343,8 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
        if (start_active_slot(slot)) {
                run_active_slot(slot);
                if (results.curl_result == CURLE_OK) {
+                       XML_Parser parser = XML_ParserCreate(NULL);
+                       enum XML_Status result;
                        ctx.name = xcalloc(10, 1);
                        ctx.len = 0;
                        ctx.cdata = NULL;
@@ -1363,6 +1363,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
                                                XML_GetErrorCode(parser)));
                                lock->timeout = -1;
                        }
+                       XML_ParserFree(parser);
                }
        } else {
                fprintf(stderr, "Unable to start LOCK request\n");
@@ -1525,8 +1526,6 @@ static void remote_ls(const char *path, int flags,
        struct buffer out_buffer;
        char *in_data;
        char *out_data;
-       XML_Parser parser = XML_ParserCreate(NULL);
-       enum XML_Status result;
        struct curl_slist *dav_headers = NULL;
        struct xml_ctx ctx;
        struct remote_ls_ctx ls;
@@ -1569,6 +1568,8 @@ static void remote_ls(const char *path, int flags,
        if (start_active_slot(slot)) {
                run_active_slot(slot);
                if (results.curl_result == CURLE_OK) {
+                       XML_Parser parser = XML_ParserCreate(NULL);
+                       enum XML_Status result;
                        ctx.name = xcalloc(10, 1);
                        ctx.len = 0;
                        ctx.cdata = NULL;
@@ -1587,6 +1588,7 @@ static void remote_ls(const char *path, int flags,
                                        XML_ErrorString(
                                                XML_GetErrorCode(parser)));
                        }
+                       XML_ParserFree(parser);
                }
        } else {
                fprintf(stderr, "Unable to start PROPFIND request\n");
@@ -1620,8 +1622,6 @@ static int locking_available(void)
        struct buffer out_buffer;
        char *in_data;
        char *out_data;
-       XML_Parser parser = XML_ParserCreate(NULL);
-       enum XML_Status result;
        struct curl_slist *dav_headers = NULL;
        struct xml_ctx ctx;
        int lock_flags = 0;
@@ -1658,6 +1658,8 @@ static int locking_available(void)
        if (start_active_slot(slot)) {
                run_active_slot(slot);
                if (results.curl_result == CURLE_OK) {
+                       XML_Parser parser = XML_ParserCreate(NULL);
+                       enum XML_Status result;
                        ctx.name = xcalloc(10, 1);
                        ctx.len = 0;
                        ctx.cdata = NULL;
@@ -1676,6 +1678,7 @@ static int locking_available(void)
                                                XML_GetErrorCode(parser)));
                                lock_flags = 0;
                        }
+                       XML_ParserFree(parser);
                }
        } else {
                fprintf(stderr, "Unable to start PROPFIND request\n");
index 9a1e2f269dc5eff3b7544507a1e483948cc1254d..2a58dad3f43590008045282614fb0f174f3733e5 100644 (file)
@@ -1046,14 +1046,16 @@ static struct merge_file_info merge_file(struct diff_filespec *o,
 
                        free(result_buf.ptr);
                        result.clean = (merge_status == 0);
-               } else {
-                       if (!(S_ISLNK(a->mode) || S_ISLNK(b->mode)))
-                               die("cannot merge modes?");
-
+               } else if (S_ISGITLINK(a->mode)) {
+                       result.clean = 0;
+                       hashcpy(result.sha, a->sha1);
+               } else if (S_ISLNK(a->mode)) {
                        hashcpy(result.sha, a->sha1);
 
                        if (!sha_eq(a->sha1, b->sha1))
                                result.clean = 0;
+               } else {
+                       die("unsupported object type in the tree");
                }
        }
 
diff --git a/pager.c b/pager.c
index fb7a1a625abf07b0d896a270286ee422a700c14c..0376953cb1b8a4095346e0d12ecef6e7db9c48c9 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -5,6 +5,8 @@
  * something different on Windows, for example.
  */
 
+static int spawned_pager;
+
 static void run_pager(const char *pager)
 {
        /*
@@ -41,7 +43,7 @@ void setup_pager(void)
        else if (!*pager || !strcmp(pager, "cat"))
                return;
 
-       pager_in_use = 1; /* means we are emitting to terminal */
+       spawned_pager = 1; /* means we are emitting to terminal */
 
        if (pipe(fd) < 0)
                return;
@@ -70,3 +72,14 @@ void setup_pager(void)
        die("unable to execute pager '%s'", pager);
        exit(255);
 }
+
+int pager_in_use(void)
+{
+       const char *env;
+
+       if (spawned_pager)
+               return 1;
+
+       env = getenv("GIT_PAGER_IN_USE");
+       return env ? git_config_bool("GIT_PAGER_IN_USE", env) : 0;
+}
index 6aecd897f8fe5b69b1805e94a20c578c10246a4d..320253eb8e91eb1d914aa4e34f7d3af4649b9b39 100644 (file)
@@ -17,9 +17,6 @@ if ($@ || $Error::VERSION < 0.15009) {
        $pm{'private-Error.pm'} = '$(INST_LIBDIR)/Error.pm';
 }
 
-my %extra;
-$extra{DESTDIR} = $ENV{DESTDIR} if $ENV{DESTDIR};
-
 # redirect stdout, otherwise the message "Writing perl.mak for Git"
 # disrupts the output for the target 'instlibdir'
 open STDOUT, ">&STDERR";
@@ -29,6 +26,5 @@ WriteMakefile(
        VERSION_FROM    => 'Git.pm',
        PM              => \%pm,
        MAKEFILE        => 'perl.mak',
-       INSTALLSITEMAN3DIR => '$(SITEPREFIX)/share/man/man3',
-       %extra
+       INSTALLSITEMAN3DIR => '$(SITEPREFIX)/share/man/man3'
 );
index 2a59035192baec8265acccf8b5d00aa7b2db4dd7..7e2f4f1eb5090588fc6515b78d39b7c7a4eda00d 100644 (file)
@@ -139,6 +139,18 @@ void add_pending_object(struct rev_info *revs, struct object *obj, const char *n
        add_pending_object_with_mode(revs, obj, name, S_IFINVALID);
 }
 
+void add_head_to_pending(struct rev_info *revs)
+{
+       unsigned char sha1[20];
+       struct object *obj;
+       if (get_sha1("HEAD", sha1))
+               return;
+       obj = parse_object(sha1);
+       if (!obj)
+               return;
+       add_pending_object(revs, obj, "HEAD");
+}
+
 static struct object *get_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags)
 {
        struct object *object;
index 992e1e9dd57eac528c3ecaf09987593d525da611..8572315954d1fde8c36c426d66c665534c22d1f2 100644 (file)
@@ -130,6 +130,8 @@ extern void add_object(struct object *obj,
 
 extern void add_pending_object(struct rev_info *revs, struct object *obj, const char *name);
 
+extern void add_head_to_pending(struct rev_info *);
+
 enum commit_action {
        commit_ignore,
        commit_show,
index 8d4a44721380213369668ea74dc4dbe3cf360485..9ee35e79013f9b1f6ef3df6c9102368fa347c089 100644 (file)
@@ -82,3 +82,29 @@ stop_httpd () {
        test -z "$SVN_HTTPD_PORT" && return
        "$SVN_HTTPD_PATH" -f "$GIT_DIR"/httpd.conf -k stop
 }
+
+convert_to_rev_db () {
+       perl -w -- - "$@" <<\EOF
+use strict;
+@ARGV == 2 or die "Usage: convert_to_rev_db <input> <output>";
+open my $wr, '+>', $ARGV[1] or die "$!: couldn't open: $ARGV[1]";
+open my $rd, '<', $ARGV[0] or die "$!: couldn't open: $ARGV[0]";
+my $size = (stat($rd))[7];
+($size % 24) == 0 or die "Inconsistent size: $size";
+while (sysread($rd, my $buf, 24) == 24) {
+       my ($r, $c) = unpack('NH40', $buf);
+       my $offset = $r * 41;
+       seek $wr, 0, 2 or die $!;
+       my $pos = tell $wr;
+       if ($pos < $offset) {
+               for (1 .. (($offset - $pos) / 41)) {
+                       print $wr (('0' x 40),"\n") or die $!;
+               }
+       }
+       seek $wr, $offset, 0 or die $!;
+       print $wr $c,"\n" or die $!;
+}
+close $wr or die $!;
+close $rd or die $!;
+EOF
+}
index 79fdff3f3a87cfe45b7fefa96e350675bd4e048c..6adf9d11d03c3e9b1b7ee1ee46364f0e3a755016 100755 (executable)
@@ -117,4 +117,13 @@ EOF
 git diff -b > out
 test_expect_success 'another test, with -b' 'git diff expect out'
 
+
+test_expect_success 'check mixed spaces and tabs in indent' '
+
+       # This is indented with SP HT SP.
+       echo "   foo();" > x &&
+       git diff --check | grep "space before tab"
+
+'
+
 test_done
index c7130c4dcc31dda1f70160c81804096676943af4..09d56e0839f042a74bee5c13ab251f19fcc2c76e 100755 (executable)
@@ -640,6 +640,46 @@ test_expect_success 'creating a signed tag with -m message should succeed' '
        git diff expect actual
 '
 
+get_tag_header u-signed-tag $commit commit $time >expect
+echo 'Another message' >>expect
+echo '-----BEGIN PGP SIGNATURE-----' >>expect
+test_expect_success 'sign with a given key id' '
+
+       git tag -u committer@example.com -m "Another message" u-signed-tag &&
+       get_tag_msg u-signed-tag >actual &&
+       git diff expect actual
+
+'
+
+test_expect_success 'sign with an unknown id (1)' '
+
+       ! git tag -u author@example.com -m "Another message" o-signed-tag
+
+'
+
+test_expect_success 'sign with an unknown id (2)' '
+
+       ! git tag -u DEADBEEF -m "Another message" o-signed-tag
+
+'
+
+cat >fakeeditor <<'EOF'
+#!/bin/sh
+test -n "$1" && exec >"$1"
+echo A signed tag message
+echo from a fake editor.
+EOF
+chmod +x fakeeditor
+
+get_tag_header implied-sign $commit commit $time >expect
+./fakeeditor >>expect
+echo '-----BEGIN PGP SIGNATURE-----' >>expect
+test_expect_success '-u implies signed tag' '
+       GIT_EDITOR=./fakeeditor git-tag -u CDDE430D implied-sign &&
+       get_tag_msg implied-sign >actual &&
+       git diff expect actual
+'
+
 cat >sigmsgfile <<EOF
 Another signed tag
 message in a file.
@@ -667,13 +707,6 @@ test_expect_success 'creating a signed tag with -F - should succeed' '
        git diff expect actual
 '
 
-cat >fakeeditor <<'EOF'
-#!/bin/sh
-test -n "$1" && exec >"$1"
-echo A signed tag message
-echo from a fake editor.
-EOF
-chmod +x fakeeditor
 get_tag_header implied-annotate $commit commit $time >expect
 ./fakeeditor >>expect
 echo '-----BEGIN PGP SIGNATURE-----' >>expect
index 55558aba8b862b93cb8ad97a681a4749bae3b3e1..73d8a00e2cca907e562c50c70a10c02e3c0e02ca 100755 (executable)
@@ -20,6 +20,8 @@ Test switching across them.
 
 . ./test-lib.sh
 
+test_tick
+
 fill () {
        for i
        do
@@ -30,9 +32,10 @@ fill () {
 
 test_expect_success setup '
 
+       fill x y z > same &&
        fill 1 2 3 4 5 6 7 8 >one &&
        fill a b c d e >two &&
-       git add one two &&
+       git add same one two &&
        git commit -m "Initial A one, A two" &&
 
        git checkout -b renamer &&
@@ -74,16 +77,44 @@ test_expect_success "checkout with dirty tree without -m" '
 
 '
 
+test_expect_success "checkout with unrelated dirty tree without -m" '
+
+       git checkout -f master &&
+       fill 0 1 2 3 4 5 6 7 8 >same &&
+       cp same kept
+       git checkout side >messages &&
+       git diff same kept
+       (cat > messages.expect <<EOF
+M      same
+EOF
+) &&
+       touch messages.expect &&
+       git diff messages.expect messages
+'
+
 test_expect_success "checkout -m with dirty tree" '
 
        git checkout -f master &&
        git clean -f &&
 
        fill 0 1 2 3 4 5 6 7 8 >one &&
-       git checkout -m side &&
+       git checkout -m side > messages &&
 
        test "$(git symbolic-ref HEAD)" = "refs/heads/side" &&
 
+       (cat >expect.messages <<EOF
+Merging side with local
+Merging:
+ab76817 Side M one, D two, A three
+virtual local
+found 1 common ancestor(s):
+7329388 Initial A one, A two
+Auto-merged one
+M      one
+EOF
+) &&
+       git diff expect.messages messages &&
+
        fill "M one" "A three" "D       two" >expect.master &&
        git diff --name-status master >current.master &&
        diff expect.master current.master &&
@@ -145,7 +176,16 @@ test_expect_success 'checkout -m with merge conflict' '
 test_expect_success 'checkout to detach HEAD' '
 
        git checkout -f renamer && git clean -f &&
-       git checkout renamer^ &&
+       git checkout renamer^ 2>messages &&
+       (cat >messages.expect <<EOF
+Note: moving to "renamer^" which isn'"'"'t a local branch
+If you want to create a new branch from this checkout, you may do so
+(now or later) by using -b with the checkout command again. Example:
+  git checkout -b <new_branch_name>
+HEAD is now at 7329388... Initial A one, A two
+EOF
+) &&
+       git diff messages.expect messages &&
        H=$(git rev-parse --verify HEAD) &&
        M=$(git show-ref -s --verify refs/heads/master) &&
        test "z$H" = "z$M" &&
index 67fdf7023f3aed9273eeaf5664cbd62950e32616..0a41d52c7a734c530cd93e8f536aa9a0a8b5a3f6 100755 (executable)
@@ -97,15 +97,19 @@ test_expect_success 'migrate --minimize on old inited layout' "
        grep '^:refs/remotes/git-svn' fetch.out
        "
 
-test_expect_success  ".rev_db auto-converted to .rev_db.UUID" "
+test_expect_success  ".rev_db auto-converted to .rev_map.UUID" "
        git-svn fetch -i trunk &&
-       expect=$GIT_DIR/svn/trunk/.rev_db.* &&
+       test -z \"\$(ls $GIT_DIR/svn/trunk/.rev_db.* 2>/dev/null)\" &&
+       expect=\"\$(ls $GIT_DIR/svn/trunk/.rev_map.*)\" &&
        test -n \"\$expect\" &&
-       mv \$expect $GIT_DIR/svn/trunk/.rev_db &&
+       rev_db=\$(echo \$expect | sed -e 's,_map,_db,') &&
+       convert_to_rev_db \$expect \$rev_db &&
+       rm -f \$expect &&
+       test -f \$rev_db &&
        git-svn fetch -i trunk &&
-       test -L $GIT_DIR/svn/trunk/.rev_db &&
-       test -f \$expect &&
-       cmp \$expect $GIT_DIR/svn/trunk/.rev_db
+       test -z \"\$(ls $GIT_DIR/svn/trunk/.rev_db.* 2>/dev/null)\" &&
+       test ! -e $GIT_DIR/svn/trunk/.rev_db &&
+       test -f \$expect
        "
 
 test_done
index 439bd93c886091f820a7de48a0fe92966e31fe1c..cc619115931cb74a85a171ade915ca2c47639c9b 100755 (executable)
@@ -5,6 +5,8 @@
 test_description='git-svn info'
 
 . ./lib-git-svn.sh
+say 'skipping svn-info test (has a race undiagnosed yet)'
+test_done
 
 ptouch() {
        perl -w -e '
index aa0a100295c5c48483c6bfbbfc0105b70680becc..e1e2e6c6ce3c4effffb26e9aed7c6bdd2b00a5ae 100644 (file)
@@ -326,6 +326,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
                die("unable to set up diff options to follow renames");
        diff_tree(t1, t2, base, &diff_opts);
        diffcore_std(&diff_opts);
+       diff_tree_release_paths(&diff_opts);
 
        /* Go through the new set of filepairing, and see if we find a more interesting one */
        for (i = 0; i < q->nr; i++) {
@@ -342,6 +343,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
                        choice = p;
 
                        /* Update the path we use from now on.. */
+                       diff_tree_release_paths(opt);
                        opt->paths[0] = xstrdup(p->one->path);
                        diff_tree_setup_paths(opt->paths, opt);
                        break;