Merge branch 'jk/add-i-mode'
authorJunio C Hamano <gitster@pobox.com>
Wed, 9 Apr 2008 07:29:24 +0000 (00:29 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 9 Apr 2008 07:29:24 +0000 (00:29 -0700)
* jk/add-i-mode:
add--interactive: allow user to choose mode update
add--interactive: ignore mode change in 'p'atch command

43 files changed:
Documentation/RelNotes-1.5.4.5.txt
Documentation/RelNotes-1.5.5.txt
Documentation/config.txt
Documentation/git-add.txt
Documentation/git-cvsserver.txt
Documentation/git-pack-objects.txt
Documentation/git.txt
Documentation/pretty-formats.txt
Documentation/technical/pack-format.txt
GIT-VERSION-GEN
builtin-apply.c
builtin-fetch.c
builtin-prune.c
builtin-verify-tag.c
contrib/completion/git-completion.bash
contrib/fast-import/git-p4
diff-lib.c
git-clone.sh
git-cvsserver.perl
git-filter-branch.sh
git-gui/GIT-VERSION-GEN
git-gui/git-gui.sh
git-gui/po/fr.po
git-svn.perl
git.c
gitk-git/gitk
gitweb/gitweb.perl
help.c
log-tree.c
mktag.c
parse-options.c
parse-options.h
pretty.c
t/t2201-add-update-typechange.sh [new file with mode: 0755]
t/t3800-mktag.sh
t/t4104-apply-boundary.sh
t/t5304-prune.sh
t/t7003-filter-branch.sh
t/t7004-tag.sh
t/t7005-editor.sh
t/t9121-git-svn-fetch-renamed-dir.sh [new file with mode: 0755]
t/t9121/renamed-dir.dump [new file with mode: 0644]
t/t9400-git-cvsserver-server.sh
index 56fcd27b5cf76517683775e11b0c7b9f07a18bae..02823413987d5a10364d936327e3a1cfb38cbac2 100644 (file)
@@ -54,9 +54,3 @@ Fixes since v1.5.4.4
    "rebase --continue" impossible.
 
 As usual, it also comes with many documentation fixes and clarifications.
-
---
-exec >/var/tmp/1
-echo O=$(git describe maint)
-O=v1.5.4.4-32-gb88605f
-git shortlog --no-merges $O..maint
index b299e8792c3fb4ad875ad243ea98198383b3c6d1..29322124881bf65c3ee6f5d613251b09f4a98d9a 100644 (file)
@@ -6,7 +6,7 @@ Updates since v1.5.4
 
 (subsystems)
 
- * Comes with git-gui 0.9.3.
+ * Comes with git-gui 0.10.1
 
 (portability)
 
@@ -166,8 +166,8 @@ Updates since v1.5.4
    symmetric difference between the HEAD version and the work tree version
    of the submodule commits.
 
- * Various "git cvsimport", "git cvsexportcommit", "git svn" and
-   "git p4" improvements.
+ * Various "git cvsimport", "git cvsexportcommit", "git cvsserver",
+   "git svn" and "git p4" improvements.
 
 (internal)
 
@@ -205,9 +205,3 @@ this release, unless otherwise noted.
 
  * "git imap-send" without setting imap.host did not error out but
    segfaulted.
-
----
-exec >/var/tmp/1
-O=v1.5.5-rc1-21-g319a36a
-echo O=`git describe refs/heads/master`
-git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
index 3017d640cff918e33544272cb2b9f7b9cfd5db4c..04c01c5fdca566b1760e8eed02687607017e89aa 100644 (file)
@@ -661,6 +661,13 @@ gitcvs.dbuser, gitcvs.dbpass::
        'gitcvs.dbuser' supports variable substitution (see
        linkgit:git-cvsserver[1] for details).
 
+gitcvs.dbTableNamePrefix::
+       Database table name prefix.  Prepended to the names of any
+       database tables used, allowing a single database to be used
+       for several repositories.  Supports variable substitution (see
+       linkgit:git-cvsserver[1] for details).  Any non-alphabetic
+       characters will be replaced with underscores.
+
 All gitcvs variables except for 'gitcvs.allbinary' can also be
 specified as 'gitcvs.<access_method>.<varname>' (where 'access_method'
 is one of "ext" and "pserver") to make them apply only for the given
index c751a17d079dc2a6c5d3160573a42a7b6be3d5e2..35e67a06e4248182c05c98b4b9b421bb3e02940a 100644 (file)
@@ -226,6 +226,12 @@ diff::
   This lets you review what will be committed (i.e. between
   HEAD and index).
 
+Bugs
+----
+The interactive mode does not work with files whose names contain
+characters that need C-quoting.  `core.quotepath` configuration can be
+used to work this limitation around to some degree, but backslash,
+double-quote and control characters will still have problems.
 
 See Also
 --------
index d3e99931d7d344cdfb04b90133dd926a2aac1c9b..9cec8021b8c66b6bac692e2a9f14204503f7f18a 100644 (file)
@@ -227,6 +227,11 @@ gitcvs.dbpass::
        Database password.  Only useful if setting `dbdriver`, since
        SQLite has no concept of database passwords.
 
+gitcvs.dbTableNamePrefix::
+       Database table name prefix.  Supports variable substitution
+       (see below).  Any non-alphabetic characters will be replaced
+       with underscores.
+
 All variables can also be set per access method, see <<configaccessmethod,above>>.
 
 Variable substitution
index eed0a94c6e4d6f520923a2ee86f1fcfbee228185..3a1be08186e9c87e5e3db5922a31b3f3f5aafdd7 100644 (file)
@@ -22,8 +22,9 @@ archive with specified base-name, or to the standard output.
 A packed archive is an efficient way to transfer set of objects
 between two repositories, and also is an archival format which
 is efficient to access.  The packed archive format (.pack) is
-designed to be unpackable without having anything else, but for
-random access, accompanied with the pack index file (.idx).
+designed to be self contained so that it can be unpacked without
+any further information, but for fast, random access to the objects
+in the pack, a pack index file (.idx) will be generated.
 
 Placing both in the pack/ subdirectory of $GIT_OBJECT_DIRECTORY (or
 any of the directories on $GIT_ALTERNATE_OBJECT_DIRECTORIES)
index 3ed24d449a1f277c40dbb49654a196e38d1fa3e4..336fe99cc78d932f216cc7b04ac3a36685f9f96e 100644 (file)
@@ -43,9 +43,15 @@ unreleased) version of git, that is available from 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v1.5.4.4/git.html[documentation for release 1.5.4.4]
+* link:v1.5.5/git.html[documentation for release 1.5.5]
 
 * release notes for
+  link:RelNotes-1.5.5.txt[1.5.5].
+
+* link:v1.5.4.5/git.html[documentation for release 1.5.4.5]
+
+* release notes for
+  link:RelNotes-1.5.4.5.txt[1.5.4.5],
   link:RelNotes-1.5.4.4.txt[1.5.4.4],
   link:RelNotes-1.5.4.3.txt[1.5.4.3],
   link:RelNotes-1.5.4.2.txt[1.5.4.2],
index 0193c3ce58de4f51a164d43e68023fdf5639a920..e8bea3e18e569e702233d0bb986fc7e52266d445 100644 (file)
@@ -123,3 +123,4 @@ The placeholders are:
 - '%Creset': reset color
 - '%m': left, right or boundary mark
 - '%n': newline
+- '%x00': print a byte from a hex code
index aa87756a55dfe6337f06b8aece0ed88d092036b1..1803e64e465fa4f8f0fe520fc0fd95d0c9def5bd 100644 (file)
@@ -103,10 +103,24 @@ Pack file entry: <+
      packed object data:
         If it is not DELTA, then deflated bytes (the size above
                is the size before compression).
-       If it is DELTA, then
+       If it is REF_DELTA, then
          20-byte base object name SHA1 (the size above is the
                size of the delta data that follows).
           delta data, deflated.
+       If it is OFS_DELTA, then
+         n-byte offset (see below) interpreted as a negative
+               offset from the type-byte of the header of the
+               ofs-delta entry (the size above is the size of
+               the delta data that follows).
+         delta data, deflated.
+
+     offset encoding:
+         n bytes with MSB set in all but the last one.
+         The offset is then the number constructed by
+         concatenating the lower 7 bit of each byte, and
+         for n >= 2 adding 2^7 + 2^14 + ... + 2^(7*(n-1))
+         to the result.
+
 
 
 = Version 2 pack-*.idx files support packs larger than 4 GiB, and
index d0b60f40d80017b4638a403ff4b0ec05550014b2..f60bab896bd9a54714eff3596e38c9ffb9d38ac8 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.5.5-rc1.GIT
+DEF_VER=v1.5.5.GIT
 
 LF='
 '
index b5f78ac3a78679fdb747380305fb6772c39874e0..abe73a0f8194e95c2a10a27c2007560e6d57f3d5 100644 (file)
@@ -1937,21 +1937,24 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
        trailing = frag->trailing;
 
        /*
-        * If we don't have any leading/trailing data in the patch,
-        * we want it to match at the beginning/end of the file.
+        * A hunk to change lines at the beginning would begin with
+        * @@ -1,L +N,M @@
         *
-        * But that would break if the patch is generated with
-        * --unified=0; sane people wouldn't do that to cause us
-        * trouble, but we try to please not so sane ones as well.
+        * And a hunk to add to an empty file would begin with
+        * @@ -0,0 +N,M @@
+        *
+        * In other words, a hunk that is (frag->oldpos <= 1) with or
+        * without leading context must match at the beginning.
         */
-       if (unidiff_zero) {
-               match_beginning = (!leading && !frag->oldpos);
-               match_end = 0;
-       }
-       else {
-               match_beginning = !leading && (frag->oldpos == 1);
-               match_end = !trailing;
-       }
+       match_beginning = frag->oldpos <= 1;
+
+       /*
+        * A hunk without trailing lines must match at the end.
+        * However, we simply cannot tell if a hunk must match end
+        * from the lack of trailing lines if the patch was generated
+        * with unidiff without any context.
+        */
+       match_end = !unidiff_zero && !trailing;
 
        pos = frag->newpos ? (frag->newpos - 1) : 0;
        preimage.buf = oldlines;
index a11548c8943f75b8d3e9ddfa1e6e2e3d13eaa431..5841b3e51a5c908a32761398d6237968ddac4d46 100644 (file)
@@ -637,6 +637,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                        if (!strcmp(argv[i], "tag")) {
                                char *ref;
                                i++;
+                               if (i >= argc)
+                                       die("You need to specify a tag name.");
                                ref = xmalloc(strlen(argv[i]) * 2 + 22);
                                strcpy(ref, "refs/tags/");
                                strcat(ref, argv[i]);
index bb8ead92cf41c3cbdbc421a1490fb40ce19f11c3..25f9304b829c9074e8a034eba5e34c38794058a4 100644 (file)
@@ -4,8 +4,12 @@
 #include "revision.h"
 #include "builtin.h"
 #include "reachable.h"
+#include "parse-options.h"
 
-static const char prune_usage[] = "git-prune [-n]";
+static const char * const prune_usage[] = {
+       "git-prune [-n] [--expire <time>] [--] [<head>...]",
+       NULL
+};
 static int show_only;
 static unsigned long expire;
 
@@ -123,32 +127,33 @@ static void remove_temporary_files(void)
 
 int cmd_prune(int argc, const char **argv, const char *prefix)
 {
-       int i;
        struct rev_info revs;
-
-       for (i = 1; i < argc; i++) {
-               const char *arg = argv[i];
-               if (!strcmp(arg, "-n")) {
-                       show_only = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "--expire")) {
-                       if (++i < argc) {
-                               expire = approxidate(argv[i]);
-                               continue;
-                       }
-               }
-               else if (!prefixcmp(arg, "--expire=")) {
-                       expire = approxidate(arg + 9);
-                       continue;
-               }
-               usage(prune_usage);
-       }
+       const struct option options[] = {
+               OPT_BOOLEAN('n', NULL, &show_only,
+                           "do not remove, show only"),
+               OPT_DATE(0, "expire", &expire,
+                        "expire objects older than <time>"),
+               OPT_END()
+       };
 
        save_commit_buffer = 0;
        init_revisions(&revs, prefix);
-       mark_reachable_objects(&revs, 1);
 
+       argc = parse_options(argc, argv, options, prune_usage, 0);
+       while (argc--) {
+               unsigned char sha1[20];
+               const char *name = *argv++;
+
+               if (!get_sha1(name, sha1)) {
+                       struct object *object = parse_object(sha1);
+                       if (!object)
+                               die("bad object: %s", name);
+                       add_pending_object(&revs, object, "");
+               }
+               else
+                       die("unrecognized argument: %s", name);
+       }
+       mark_reachable_objects(&revs, 1);
        prune_object_dir(get_object_directory());
 
        sync();
index f3ef11fa2d582682b428d6e165da65f05e2d7511..db81496b464e253341a42e01eb72d6845e87199c 100644 (file)
@@ -46,8 +46,10 @@ static int run_gpg_verify(const char *buf, unsigned long size, int verbose)
        gpg.argv = args_gpg;
        gpg.in = -1;
        args_gpg[2] = path;
-       if (start_command(&gpg))
+       if (start_command(&gpg)) {
+               unlink(path);
                return error("could not run gpg.");
+       }
 
        write_in_full(gpg.in, buf, len);
        close(gpg.in);
index 5046f699349aa87bedbc79a997dfcb9ea54e7618..4d81963b1d00b1b4e874330a9e5933111f491def 100755 (executable)
@@ -639,7 +639,9 @@ _git_diff ()
                        --find-copies-harder --pickaxe-all --pickaxe-regex
                        --text --ignore-space-at-eol --ignore-space-change
                        --ignore-all-space --exit-code --quiet --ext-diff
-                       --no-ext-diff"
+                       --no-ext-diff
+                       --no-prefix --src-prefix= --dst-prefix=
+                       "
                return
                ;;
        esac
@@ -696,6 +698,7 @@ _git_format_patch ()
                        --full-index --binary
                        --not --all
                        --cover-letter
+                       --no-prefix --src-prefix= --dst-prefix=
                        "
                return
                ;;
@@ -865,7 +868,7 @@ _git_rebase ()
                return
                ;;
        --*)
-               __gitcomp "--onto --merge --strategy"
+               __gitcomp "--onto --merge --strategy --interactive"
                return
        esac
        __gitcomp "$(__git_refs)"
@@ -999,7 +1002,8 @@ _git_config ()
                gitcvs.enabled
                gitcvs.logfile
                gitcvs.allbinary
-               gitcvs.dbname gitcvs.dbdriver gitcvs.dbuser gitcvs.dvpass
+               gitcvs.dbname gitcvs.dbdriver gitcvs.dbuser gitcvs.dbpass
+               gitcvs.dbtablenameprefix
                gc.packrefs
                gc.reflogexpire
                gc.reflogexpireunreachable
index 3cb0330ec2d89d0637bbbc5a529158f695793638..d8de9f6c255ca7e458eac62e7f14b3d664054587 100755 (executable)
@@ -90,11 +90,11 @@ def getP4OpenedType(file):
     # Returns the perforce file type for the given file.
 
     result = read_pipe("p4 opened %s" % file)
-    match = re.match(".*\((.+)\)$", result)
+    match = re.match(".*\((.+)\)\r?$", result)
     if match:
         return match.group(1)
     else:
-        die("Could not determine file type for %s" % file)
+        die("Could not determine file type for %s (result: '%s')" % (file, result))
 
 def diffTreePattern():
     # This is a simple generator for the diff tree regex pattern. This could be
@@ -513,6 +513,8 @@ class P4Submit(Command):
         template = ""
         inFilesSection = False
         for line in read_pipe_lines("p4 change -o"):
+            if line.endswith("\r\n"):
+                line = line[:-2] + "\n"
             if inFilesSection:
                 if line.startswith("\t"):
                     # path starts and ends with a tab
@@ -619,8 +621,6 @@ class P4Submit(Command):
             setP4ExecBit(f, mode)
 
         logMessage = extractLogMessageFromGitCommit(id)
-        if self.isWindows:
-            logMessage = logMessage.replace("\n", "\r\n")
         logMessage = logMessage.strip()
 
         template = self.prepareSubmitTemplate()
@@ -631,23 +631,25 @@ class P4Submit(Command):
                 del(os.environ["P4DIFF"])
             diff = read_pipe("p4 diff -du ...")
 
+            newdiff = ""
             for newFile in filesToAdd:
-                diff += "==== new file ====\n"
-                diff += "--- /dev/null\n"
-                diff += "+++ %s\n" % newFile
+                newdiff += "==== new file ====\n"
+                newdiff += "--- /dev/null\n"
+                newdiff += "+++ %s\n" % newFile
                 f = open(newFile, "r")
                 for line in f.readlines():
-                    diff += "+" + line
+                    newdiff += "+" + line
                 f.close()
 
-            separatorLine = "######## everything below this line is just the diff #######"
-            if platform.system() == "Windows":
-                separatorLine += "\r"
-            separatorLine += "\n"
+            separatorLine = "######## everything below this line is just the diff #######\n"
 
             [handle, fileName] = tempfile.mkstemp()
             tmpFile = os.fdopen(handle, "w+")
-            tmpFile.write(submitTemplate + separatorLine + diff)
+            if self.isWindows:
+                submitTemplate = submitTemplate.replace("\n", "\r\n")
+                separatorLine = separatorLine.replace("\n", "\r\n")
+                newdiff = newdiff.replace("\n", "\r\n")
+            tmpFile.write(submitTemplate + separatorLine + diff + newdiff)
             tmpFile.close()
             defaultEditor = "vi"
             if platform.system() == "Windows":
index 52dbac34a40b2ca7bcbb7c2343a0487e5cb90ccf..069e4507ae7caa70f79d5369bc61dfefd0f174e2 100644 (file)
@@ -10,6 +10,7 @@
 #include "cache-tree.h"
 #include "path-list.h"
 #include "unpack-trees.h"
+#include "refs.h"
 
 /*
  * diff-files
@@ -333,6 +334,26 @@ int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv)
        }
        return run_diff_files(revs, options);
 }
+/*
+ * See if work tree has an entity that can be staged.  Return 0 if so,
+ * return 1 if not and return -1 if error.
+ */
+static int check_work_tree_entity(const struct cache_entry *ce, struct stat *st, char *symcache)
+{
+       if (lstat(ce->name, st) < 0) {
+               if (errno != ENOENT && errno != ENOTDIR)
+                       return -1;
+               return 1;
+       }
+       if (has_symlink_leading_path(ce->name, symcache))
+               return 1;
+       if (S_ISDIR(st->st_mode)) {
+               unsigned char sub[20];
+               if (resolve_gitlink_ref(ce->name, "HEAD", sub))
+                       return 1;
+       }
+       return 0;
+}
 
 int run_diff_files(struct rev_info *revs, unsigned int option)
 {
@@ -341,10 +362,12 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
        int silent_on_removed = option & DIFF_SILENT_ON_REMOVED;
        unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
                              ? CE_MATCH_RACY_IS_DIRTY : 0);
+       char symcache[PATH_MAX];
 
        if (diff_unmerged_stage < 0)
                diff_unmerged_stage = 2;
        entries = active_nr;
+       symcache[0] = '\0';
        for (i = 0; i < entries; i++) {
                struct stat st;
                unsigned int oldmode, newmode;
@@ -376,16 +399,17 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
                        memset(&(dpath->parent[0]), 0,
                               sizeof(struct combine_diff_parent)*5);
 
-                       if (lstat(ce->name, &st) < 0) {
-                               if (errno != ENOENT && errno != ENOTDIR) {
+                       changed = check_work_tree_entity(ce, &st, symcache);
+                       if (!changed)
+                               dpath->mode = ce_mode_from_stat(ce, st.st_mode);
+                       else {
+                               if (changed < 0) {
                                        perror(ce->name);
                                        continue;
                                }
                                if (silent_on_removed)
                                        continue;
                        }
-                       else
-                               dpath->mode = ce_mode_from_stat(ce, st.st_mode);
 
                        while (i < entries) {
                                struct cache_entry *nce = active_cache[i];
@@ -438,8 +462,10 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
 
                if (ce_uptodate(ce))
                        continue;
-               if (lstat(ce->name, &st) < 0) {
-                       if (errno != ENOENT && errno != ENOTDIR) {
+
+               changed = check_work_tree_entity(ce, &st, symcache);
+               if (changed) {
+                       if (changed < 0) {
                                perror(ce->name);
                                continue;
                        }
@@ -468,6 +494,11 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
  * diff-index
  */
 
+struct oneway_unpack_data {
+       struct rev_info *revs;
+       char symcache[PATH_MAX];
+};
+
 /* A file entry went away or appeared */
 static void diff_index_show_file(struct rev_info *revs,
                                 const char *prefix,
@@ -481,7 +512,8 @@ static void diff_index_show_file(struct rev_info *revs,
 static int get_stat_data(struct cache_entry *ce,
                         const unsigned char **sha1p,
                         unsigned int *modep,
-                        int cached, int match_missing)
+                        int cached, int match_missing,
+                        struct oneway_unpack_data *cbdata)
 {
        const unsigned char *sha1 = ce->sha1;
        unsigned int mode = ce->ce_mode;
@@ -489,8 +521,11 @@ static int get_stat_data(struct cache_entry *ce,
        if (!cached) {
                int changed;
                struct stat st;
-               if (lstat(ce->name, &st) < 0) {
-                       if (errno == ENOENT && match_missing) {
+               changed = check_work_tree_entity(ce, &st, cbdata->symcache);
+               if (changed < 0)
+                       return -1;
+               else if (changed) {
+                       if (match_missing) {
                                *sha1p = sha1;
                                *modep = mode;
                                return 0;
@@ -509,23 +544,25 @@ static int get_stat_data(struct cache_entry *ce,
        return 0;
 }
 
-static void show_new_file(struct rev_info *revs,
+static void show_new_file(struct oneway_unpack_data *cbdata,
                          struct cache_entry *new,
                          int cached, int match_missing)
 {
        const unsigned char *sha1;
        unsigned int mode;
+       struct rev_info *revs = cbdata->revs;
 
-       /* New file in the index: it might actually be different in
+       /*
+        * New file in the index: it might actually be different in
         * the working copy.
         */
-       if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0)
+       if (get_stat_data(new, &sha1, &mode, cached, match_missing, cbdata) < 0)
                return;
 
        diff_index_show_file(revs, "+", new, sha1, mode);
 }
 
-static int show_modified(struct rev_info *revs,
+static int show_modified(struct oneway_unpack_data *cbdata,
                         struct cache_entry *old,
                         struct cache_entry *new,
                         int report_missing,
@@ -533,8 +570,9 @@ static int show_modified(struct rev_info *revs,
 {
        unsigned int mode, oldmode;
        const unsigned char *sha1;
+       struct rev_info *revs = cbdata->revs;
 
-       if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0) {
+       if (get_stat_data(new, &sha1, &mode, cached, match_missing, cbdata) < 0) {
                if (report_missing)
                        diff_index_show_file(revs, "-", old,
                                             old->sha1, old->ce_mode);
@@ -602,7 +640,8 @@ static void do_oneway_diff(struct unpack_trees_options *o,
        struct cache_entry *idx,
        struct cache_entry *tree)
 {
-       struct rev_info *revs = o->unpack_data;
+       struct oneway_unpack_data *cbdata = o->unpack_data;
+       struct rev_info *revs = cbdata->revs;
        int match_missing, cached;
 
        /*
@@ -625,7 +664,7 @@ static void do_oneway_diff(struct unpack_trees_options *o,
         * Something added to the tree?
         */
        if (!tree) {
-               show_new_file(revs, idx, cached, match_missing);
+               show_new_file(cbdata, idx, cached, match_missing);
                return;
        }
 
@@ -638,7 +677,7 @@ static void do_oneway_diff(struct unpack_trees_options *o,
        }
 
        /* Show difference between old and new */
-       show_modified(revs, tree, idx, 1, cached, match_missing);
+       show_modified(cbdata, tree, idx, 1, cached, match_missing);
 }
 
 static inline void skip_same_name(struct cache_entry *ce, struct unpack_trees_options *o)
@@ -675,7 +714,8 @@ static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o)
 {
        struct cache_entry *idx = src[0];
        struct cache_entry *tree = src[1];
-       struct rev_info *revs = o->unpack_data;
+       struct oneway_unpack_data *cbdata = o->unpack_data;
+       struct rev_info *revs = cbdata->revs;
 
        if (idx && ce_stage(idx))
                skip_same_name(idx, o);
@@ -702,6 +742,7 @@ int run_diff_index(struct rev_info *revs, int cached)
        const char *tree_name;
        struct unpack_trees_options opts;
        struct tree_desc t;
+       struct oneway_unpack_data unpack_cb;
 
        mark_merge_entries();
 
@@ -711,12 +752,14 @@ int run_diff_index(struct rev_info *revs, int cached)
        if (!tree)
                return error("bad tree object %s", tree_name);
 
+       unpack_cb.revs = revs;
+       unpack_cb.symcache[0] = '\0';
        memset(&opts, 0, sizeof(opts));
        opts.head_idx = 1;
        opts.index_only = cached;
        opts.merge = 1;
        opts.fn = oneway_diff;
-       opts.unpack_data = revs;
+       opts.unpack_data = &unpack_cb;
        opts.src_index = &the_index;
        opts.dst_index = NULL;
 
@@ -738,6 +781,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
        struct cache_entry *last = NULL;
        struct unpack_trees_options opts;
        struct tree_desc t;
+       struct oneway_unpack_data unpack_cb;
 
        /*
         * This is used by git-blame to run diff-cache internally;
@@ -766,12 +810,14 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
        if (!tree)
                die("bad tree object %s", sha1_to_hex(tree_sha1));
 
+       unpack_cb.revs = &revs;
+       unpack_cb.symcache[0] = '\0';
        memset(&opts, 0, sizeof(opts));
        opts.head_idx = 1;
        opts.index_only = 1;
        opts.merge = 1;
        opts.fn = oneway_diff;
-       opts.unpack_data = &revs;
+       opts.unpack_data = &unpack_cb;
        opts.src_index = &the_index;
        opts.dst_index = &the_index;
 
index e98112277839349a47c26e69ce30982604d12d2c..2636159aaa7a6278d9b8fc64b853b319ac8da123 100755 (executable)
@@ -310,6 +310,9 @@ yes)
                mkdir -p "$GIT_DIR/objects/info"
                echo "$repo/objects" >>"$GIT_DIR/objects/info/alternates"
        else
+               cpio_quiet_flag=""
+               cpio --help 2>&1 | grep -- --quiet >/dev/null && \
+                       cpio_quiet_flag=--quiet
                l= &&
                if test "$use_local_hardlink" = yes
                then
@@ -330,7 +333,8 @@ yes)
                        fi
                fi &&
                cd "$repo" &&
-               find objects -depth -print | cpio -pumd$l "$GIT_DIR/" || exit 1
+               find objects -depth -print | cpio $cpio_quiet_flag -pumd$l "$GIT_DIR/" || \
+                       exit 1
        fi
        git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1
        ;;
index 7f632af20defd7a3cfd92008c51f7e599be13830..29dbfc940b6c8ec10c9e0eb12d08a70581fe870c 100755 (executable)
@@ -73,8 +73,8 @@
     'status'          => \&req_status,
     'admin'           => \&req_CATCHALL,
     'history'         => \&req_CATCHALL,
-    'watchers'        => \&req_CATCHALL,
-    'editors'         => \&req_CATCHALL,
+    'watchers'        => \&req_EMPTY,
+    'editors'         => \&req_EMPTY,
     'annotate'        => \&req_annotate,
     'Global_option'   => \&req_Globaloption,
     #'annotate'        => \&req_CATCHALL,
@@ -199,6 +199,11 @@ sub req_CATCHALL
     $log->warn("Unhandled command : req_$cmd : $data");
 }
 
+# This method invariably succeeds with an empty response.
+sub req_EMPTY
+{
+    print "ok\n";
+}
 
 # Root pathname \n
 #     Response expected: no. Tell the server which CVSROOT to use. Note that
@@ -958,6 +963,17 @@ sub req_update
             $meta = $updater->getmeta($filename);
         }
 
+        # If -p was given, "print" the contents of the requested revision.
+        if ( exists ( $state->{opt}{p} ) ) {
+            if ( defined ( $meta->{revision} ) ) {
+                $log->info("Printing '$filename' revision " . $meta->{revision});
+
+                transmitfile($meta->{filehash}, { print => 1 });
+            }
+
+            next;
+        }
+
        if ( ! defined $meta )
        {
            $meta = {
@@ -1091,9 +1107,9 @@ sub req_update
             my $file_local = $filepart . ".mine";
             system("ln","-s",$state->{entries}{$filename}{modified_filename}, $file_local);
             my $file_old = $filepart . "." . $oldmeta->{revision};
-            transmitfile($oldmeta->{filehash}, $file_old);
+            transmitfile($oldmeta->{filehash}, { targetfile => $file_old });
             my $file_new = $filepart . "." . $meta->{revision};
-            transmitfile($meta->{filehash}, $file_new);
+            transmitfile($meta->{filehash}, { targetfile => $file_new });
 
             # we need to merge with the local changes ( M=successful merge, C=conflict merge )
             $log->info("Merging $file_local, $file_old, $file_new");
@@ -1423,6 +1439,8 @@ sub req_status
     {
         $filename = filecleanup($filename);
 
+        next if exists($state->{opt}{l}) && index($filename, '/', length($state->{prependdir})) >= 0;
+
         my $meta = $updater->getmeta($filename);
         my $oldmeta = $meta;
 
@@ -1466,8 +1484,10 @@ sub req_status
 
         $status ||= "Unknown";
 
+        my ($filepart) = filenamesplit($filename);
+
         print "M ===================================================================\n";
-        print "M File: $filename\tStatus: $status\n";
+        print "M File: $filepart\tStatus: $status\n";
         if ( defined($state->{entries}{$filename}{revision}) )
         {
             print "M Working revision:\t" . $state->{entries}{$filename}{revision} . "\n";
@@ -1541,14 +1561,14 @@ sub req_diff
                 print "E File $filename at revision 1.$revision1 doesn't exist\n";
                 next;
             }
-            transmitfile($meta1->{filehash}, $file1);
+            transmitfile($meta1->{filehash}, { targetfile => $file1 });
         }
         # otherwise we just use the working copy revision
         else
         {
             ( undef, $file1 ) = tempfile( DIR => $TEMP_DIR, OPEN => 0 );
             $meta1 = $updater->getmeta($filename, $wrev);
-            transmitfile($meta1->{filehash}, $file1);
+            transmitfile($meta1->{filehash}, { targetfile => $file1 });
         }
 
         # if we have a second -r switch, use it too
@@ -1563,7 +1583,7 @@ sub req_diff
                 next;
             }
 
-            transmitfile($meta2->{filehash}, $file2);
+            transmitfile($meta2->{filehash}, { targetfile => $file2 });
         }
         # otherwise we just use the working copy
         else
@@ -1576,7 +1596,7 @@ sub req_diff
         {
             ( undef, $file2 ) = tempfile( DIR => $TEMP_DIR, OPEN => 0 );
             $meta2 = $updater->getmeta($filename, $wrev);
-            transmitfile($meta2->{filehash}, $file2);
+            transmitfile($meta2->{filehash}, { targetfile => $file2 });
         }
 
         # We need to have retrieved something useful
@@ -1708,8 +1728,7 @@ sub req_log
             print "M revision 1.$revision->{revision}\n";
             # reformat the date for log output
             $revision->{modified} = sprintf('%04d/%02d/%02d %s', $3, $DATE_LIST->{$2}, $1, $4 ) if ( $revision->{modified} =~ /(\d+)\s+(\w+)\s+(\d+)\s+(\S+)/ and defined($DATE_LIST->{$2}) );
-            $revision->{author} =~ s/\s+.*//;
-            $revision->{author} =~ s/^(.{8}).*/$1/;
+            $revision->{author} = cvs_author($revision->{author});
             print "M date: $revision->{modified};  author: $revision->{author};  state: " . ( $revision->{filehash} eq "deleted" ? "dead" : "Exp" ) . ";  lines: +2 -3\n";
             my $commitmessage = $updater->commitmessage($revision->{commithash});
             $commitmessage =~ s/^/M /mg;
@@ -1824,8 +1843,7 @@ sub req_annotate
                 unless ( defined ( $metadata->{$commithash} ) )
                 {
                     $metadata->{$commithash} = $updater->getmeta($filename, $commithash);
-                    $metadata->{$commithash}{author} =~ s/\s+.*//;
-                    $metadata->{$commithash}{author} =~ s/^(.{8}).*/$1/;
+                    $metadata->{$commithash}{author} = cvs_author($metadata->{$commithash}{author});
                     $metadata->{$commithash}{modified} = sprintf("%02d-%s-%02d", $1, $2, $3) if ( $metadata->{$commithash}{modified} =~ /^(\d+)\s(\w+)\s\d\d(\d\d)/ );
                 }
                 printf("M 1.%-5d      (%-8s %10s): %s\n",
@@ -2005,14 +2023,17 @@ sub revparse
     return undef;
 }
 
-# This method takes a file hash and does a CVS "file transfer" which transmits the
-# size of the file, and then the file contents.
-# If a second argument $targetfile is given, the file is instead written out to
-# a file by the name of $targetfile
+# This method takes a file hash and does a CVS "file transfer".  Its
+# exact behaviour depends on a second, optional hash table argument:
+# - If $options->{targetfile}, dump the contents to that file;
+# - If $options->{print}, use M/MT to transmit the contents one line
+#   at a time;
+# - Otherwise, transmit the size of the file, followed by the file
+#   contents.
 sub transmitfile
 {
     my $filehash = shift;
-    my $targetfile = shift;
+    my $options = shift;
 
     if ( defined ( $filehash ) and $filehash eq "deleted" )
     {
@@ -2034,11 +2055,20 @@ sub transmitfile
 
     if ( open my $fh, '-|', "git-cat-file", "blob", $filehash )
     {
-        if ( defined ( $targetfile ) )
+        if ( defined ( $options->{targetfile} ) )
         {
+            my $targetfile = $options->{targetfile};
             open NEWFILE, ">", $targetfile or die("Couldn't open '$targetfile' for writing : $!");
             print NEWFILE $_ while ( <$fh> );
             close NEWFILE or die("Failed to write '$targetfile': $!");
+        } elsif ( defined ( $options->{print} ) && $options->{print} ) {
+            while ( <$fh> ) {
+                if( /\n\z/ ) {
+                    print 'M ', $_;
+                } else {
+                    print 'MT text ', $_, "\n";
+                }
+            }
         } else {
             print "$size\n";
             print while ( <$fh> );
@@ -2107,6 +2137,16 @@ sub kopts_from_path
     }
 }
 
+# Generate a CVS author name from Git author information, by taking
+# the first eight characters of the user part of the email address.
+sub cvs_author
+{
+    my $author_line = shift;
+    (my $author) = $author_line =~ /<([^>@]{1,8})/;
+
+    $author;
+}
+
 package GITCVS::log;
 
 ####
@@ -2311,6 +2351,14 @@ sub new
 
     bless $self, $class;
 
+    $self->{valid_tables} = {'revision' => 1,
+                             'revision_ix1' => 1,
+                             'revision_ix2' => 1,
+                             'head' => 1,
+                             'head_ix1' => 1,
+                             'properties' => 1,
+                             'commitmsgs' => 1};
+
     $self->{module} = $module;
     $self->{git_path} = $config . "/";
 
@@ -2326,6 +2374,8 @@ sub new
         $cfg->{gitcvs}{dbuser} || "";
     $self->{dbpass} = $cfg->{gitcvs}{$state->{method}}{dbpass} ||
         $cfg->{gitcvs}{dbpass} || "";
+    $self->{dbtablenameprefix} = $cfg->{gitcvs}{$state->{method}}{dbtablenameprefix} ||
+        $cfg->{gitcvs}{dbtablenameprefix} || "";
     my %mapping = ( m => $module,
                     a => $state->{method},
                     u => getlogin || getpwuid($<) || $<,
@@ -2334,6 +2384,8 @@ sub new
                     );
     $self->{dbname} =~ s/%([mauGg])/$mapping{$1}/eg;
     $self->{dbuser} =~ s/%([mauGg])/$mapping{$1}/eg;
+    $self->{dbtablenameprefix} =~ s/%([mauGg])/$mapping{$1}/eg;
+    $self->{dbtablenameprefix} = mangle_tablename($self->{dbtablenameprefix});
 
     die "Invalid char ':' in dbdriver" if $self->{dbdriver} =~ /:/;
     die "Invalid char ';' in dbname" if $self->{dbname} =~ /;/;
@@ -2349,10 +2401,13 @@ sub new
     }
 
     # Construct the revision table if required
-    unless ( $self->{tables}{revision} )
+    unless ( $self->{tables}{$self->tablename("revision")} )
     {
+        my $tablename = $self->tablename("revision");
+        my $ix1name = $self->tablename("revision_ix1");
+        my $ix2name = $self->tablename("revision_ix2");
         $self->{dbh}->do("
-            CREATE TABLE revision (
+            CREATE TABLE $tablename (
                 name       TEXT NOT NULL,
                 revision   INTEGER NOT NULL,
                 filehash   TEXT NOT NULL,
@@ -2363,20 +2418,22 @@ sub new
             )
         ");
         $self->{dbh}->do("
-            CREATE INDEX revision_ix1
-            ON revision (name,revision)
+            CREATE INDEX $ix1name
+            ON $tablename (name,revision)
         ");
         $self->{dbh}->do("
-            CREATE INDEX revision_ix2
-            ON revision (name,commithash)
+            CREATE INDEX $ix2name
+            ON $tablename (name,commithash)
         ");
     }
 
     # Construct the head table if required
-    unless ( $self->{tables}{head} )
+    unless ( $self->{tables}{$self->tablename("head")} )
     {
+        my $tablename = $self->tablename("head");
+        my $ix1name = $self->tablename("head_ix1");
         $self->{dbh}->do("
-            CREATE TABLE head (
+            CREATE TABLE $tablename (
                 name       TEXT NOT NULL,
                 revision   INTEGER NOT NULL,
                 filehash   TEXT NOT NULL,
@@ -2387,16 +2444,17 @@ sub new
             )
         ");
         $self->{dbh}->do("
-            CREATE INDEX head_ix1
-            ON head (name)
+            CREATE INDEX $ix1name
+            ON $tablename (name)
         ");
     }
 
     # Construct the properties table if required
-    unless ( $self->{tables}{properties} )
+    unless ( $self->{tables}{$self->tablename("properties")} )
     {
+        my $tablename = $self->tablename("properties");
         $self->{dbh}->do("
-            CREATE TABLE properties (
+            CREATE TABLE $tablename (
                 key        TEXT NOT NULL PRIMARY KEY,
                 value      TEXT
             )
@@ -2404,10 +2462,11 @@ sub new
     }
 
     # Construct the commitmsgs table if required
-    unless ( $self->{tables}{commitmsgs} )
+    unless ( $self->{tables}{$self->tablename("commitmsgs")} )
     {
+        my $tablename = $self->tablename("commitmsgs");
         $self->{dbh}->do("
-            CREATE TABLE commitmsgs (
+            CREATE TABLE $tablename (
                 key        TEXT NOT NULL PRIMARY KEY,
                 value      TEXT
             )
@@ -2417,6 +2476,21 @@ sub new
     return $self;
 }
 
+=head2 tablename
+
+=cut
+sub tablename
+{
+    my $self = shift;
+    my $name = shift;
+
+    if (exists $self->{valid_tables}{$name}) {
+        return $self->{dbtablenameprefix} . $name;
+    } else {
+        return undef;
+    }
+}
+
 =head2 update
 
 =cut
@@ -2633,7 +2707,7 @@ sub update
                     };
                     $self->insert_rev($name, $head->{$name}{revision}, $hash, $commit->{hash}, $commit->{date}, $commit->{author}, $git_perms);
                 }
-                elsif ( $change eq "M" )
+                elsif ( $change eq "M" || $change eq "T" )
                 {
                     #$log->debug("MODIFIED $name");
                     $head->{$name} = {
@@ -2782,8 +2856,9 @@ sub insert_rev
     my $modified = shift;
     my $author = shift;
     my $mode = shift;
+    my $tablename = $self->tablename("revision");
 
-    my $insert_rev = $self->{dbh}->prepare_cached("INSERT INTO revision (name, revision, filehash, commithash, modified, author, mode) VALUES (?,?,?,?,?,?,?)",{},1);
+    my $insert_rev = $self->{dbh}->prepare_cached("INSERT INTO $tablename (name, revision, filehash, commithash, modified, author, mode) VALUES (?,?,?,?,?,?,?)",{},1);
     $insert_rev->execute($name, $revision, $filehash, $commithash, $modified, $author, $mode);
 }
 
@@ -2792,16 +2867,18 @@ sub insert_mergelog
     my $self = shift;
     my $key = shift;
     my $value = shift;
+    my $tablename = $self->tablename("commitmsgs");
 
-    my $insert_mergelog = $self->{dbh}->prepare_cached("INSERT INTO commitmsgs (key, value) VALUES (?,?)",{},1);
+    my $insert_mergelog = $self->{dbh}->prepare_cached("INSERT INTO $tablename (key, value) VALUES (?,?)",{},1);
     $insert_mergelog->execute($key, $value);
 }
 
 sub delete_head
 {
     my $self = shift;
+    my $tablename = $self->tablename("head");
 
-    my $delete_head = $self->{dbh}->prepare_cached("DELETE FROM head",{},1);
+    my $delete_head = $self->{dbh}->prepare_cached("DELETE FROM $tablename",{},1);
     $delete_head->execute();
 }
 
@@ -2815,8 +2892,9 @@ sub insert_head
     my $modified = shift;
     my $author = shift;
     my $mode = shift;
+    my $tablename = $self->tablename("head");
 
-    my $insert_head = $self->{dbh}->prepare_cached("INSERT INTO head (name, revision, filehash, commithash, modified, author, mode) VALUES (?,?,?,?,?,?,?)",{},1);
+    my $insert_head = $self->{dbh}->prepare_cached("INSERT INTO $tablename (name, revision, filehash, commithash, modified, author, mode) VALUES (?,?,?,?,?,?,?)",{},1);
     $insert_head->execute($name, $revision, $filehash, $commithash, $modified, $author, $mode);
 }
 
@@ -2824,8 +2902,9 @@ sub _headrev
 {
     my $self = shift;
     my $filename = shift;
+    my $tablename = $self->tablename("head");
 
-    my $db_query = $self->{dbh}->prepare_cached("SELECT filehash, revision, mode FROM head WHERE name=?",{},1);
+    my $db_query = $self->{dbh}->prepare_cached("SELECT filehash, revision, mode FROM $tablename WHERE name=?",{},1);
     $db_query->execute($filename);
     my ( $hash, $revision, $mode ) = $db_query->fetchrow_array;
 
@@ -2836,8 +2915,9 @@ sub _get_prop
 {
     my $self = shift;
     my $key = shift;
+    my $tablename = $self->tablename("properties");
 
-    my $db_query = $self->{dbh}->prepare_cached("SELECT value FROM properties WHERE key=?",{},1);
+    my $db_query = $self->{dbh}->prepare_cached("SELECT value FROM $tablename WHERE key=?",{},1);
     $db_query->execute($key);
     my ( $value ) = $db_query->fetchrow_array;
 
@@ -2849,13 +2929,14 @@ sub _set_prop
     my $self = shift;
     my $key = shift;
     my $value = shift;
+    my $tablename = $self->tablename("properties");
 
-    my $db_query = $self->{dbh}->prepare_cached("UPDATE properties SET value=? WHERE key=?",{},1);
+    my $db_query = $self->{dbh}->prepare_cached("UPDATE $tablename SET value=? WHERE key=?",{},1);
     $db_query->execute($value, $key);
 
     unless ( $db_query->rows )
     {
-        $db_query = $self->{dbh}->prepare_cached("INSERT INTO properties (key, value) VALUES (?,?)",{},1);
+        $db_query = $self->{dbh}->prepare_cached("INSERT INTO $tablename (key, value) VALUES (?,?)",{},1);
         $db_query->execute($key, $value);
     }
 
@@ -2869,10 +2950,11 @@ =head2 gethead
 sub gethead
 {
     my $self = shift;
+    my $tablename = $self->tablename("head");
 
     return $self->{gethead_cache} if ( defined ( $self->{gethead_cache} ) );
 
-    my $db_query = $self->{dbh}->prepare_cached("SELECT name, filehash, mode, revision, modified, commithash, author FROM head ORDER BY name ASC",{},1);
+    my $db_query = $self->{dbh}->prepare_cached("SELECT name, filehash, mode, revision, modified, commithash, author FROM $tablename ORDER BY name ASC",{},1);
     $db_query->execute();
 
     my $tree = [];
@@ -2894,8 +2976,9 @@ sub getlog
 {
     my $self = shift;
     my $filename = shift;
+    my $tablename = $self->tablename("revision");
 
-    my $db_query = $self->{dbh}->prepare_cached("SELECT name, filehash, author, mode, revision, modified, commithash FROM revision WHERE name=? ORDER BY revision DESC",{},1);
+    my $db_query = $self->{dbh}->prepare_cached("SELECT name, filehash, author, mode, revision, modified, commithash FROM $tablename WHERE name=? ORDER BY revision DESC",{},1);
     $db_query->execute($filename);
 
     my $tree = [];
@@ -2919,19 +3002,21 @@ sub getmeta
     my $self = shift;
     my $filename = shift;
     my $revision = shift;
+    my $tablename_rev = $self->tablename("revision");
+    my $tablename_head = $self->tablename("head");
 
     my $db_query;
     if ( defined($revision) and $revision =~ /^\d+$/ )
     {
-        $db_query = $self->{dbh}->prepare_cached("SELECT * FROM revision WHERE name=? AND revision=?",{},1);
+        $db_query = $self->{dbh}->prepare_cached("SELECT * FROM $tablename_rev WHERE name=? AND revision=?",{},1);
         $db_query->execute($filename, $revision);
     }
     elsif ( defined($revision) and $revision =~ /^[a-zA-Z0-9]{40}$/ )
     {
-        $db_query = $self->{dbh}->prepare_cached("SELECT * FROM revision WHERE name=? AND commithash=?",{},1);
+        $db_query = $self->{dbh}->prepare_cached("SELECT * FROM $tablename_rev WHERE name=? AND commithash=?",{},1);
         $db_query->execute($filename, $revision);
     } else {
-        $db_query = $self->{dbh}->prepare_cached("SELECT * FROM head WHERE name=?",{},1);
+        $db_query = $self->{dbh}->prepare_cached("SELECT * FROM $tablename_head WHERE name=?",{},1);
         $db_query->execute($filename);
     }
 
@@ -2947,11 +3032,12 @@ sub commitmessage
 {
     my $self = shift;
     my $commithash = shift;
+    my $tablename = $self->tablename("commitmsgs");
 
     die("Need commithash") unless ( defined($commithash) and $commithash =~ /^[a-zA-Z0-9]{40}$/ );
 
     my $db_query;
-    $db_query = $self->{dbh}->prepare_cached("SELECT value FROM commitmsgs WHERE key=?",{},1);
+    $db_query = $self->{dbh}->prepare_cached("SELECT value FROM $tablename WHERE key=?",{},1);
     $db_query->execute($commithash);
 
     my ( $message ) = $db_query->fetchrow_array;
@@ -2979,9 +3065,10 @@ sub gethistory
 {
     my $self = shift;
     my $filename = shift;
+    my $tablename = $self->tablename("revision");
 
     my $db_query;
-    $db_query = $self->{dbh}->prepare_cached("SELECT revision, filehash, commithash FROM revision WHERE name=? ORDER BY revision DESC",{},1);
+    $db_query = $self->{dbh}->prepare_cached("SELECT revision, filehash, commithash FROM $tablename WHERE name=? ORDER BY revision DESC",{},1);
     $db_query->execute($filename);
 
     return $db_query->fetchall_arrayref;
@@ -3001,9 +3088,10 @@ sub gethistorydense
 {
     my $self = shift;
     my $filename = shift;
+    my $tablename = $self->tablename("revision");
 
     my $db_query;
-    $db_query = $self->{dbh}->prepare_cached("SELECT revision, filehash, commithash FROM revision WHERE name=? AND filehash!='deleted' ORDER BY revision DESC",{},1);
+    $db_query = $self->{dbh}->prepare_cached("SELECT revision, filehash, commithash FROM $tablename WHERE name=? AND filehash!='deleted' ORDER BY revision DESC",{},1);
     $db_query->execute($filename);
 
     return $db_query->fetchall_arrayref;
@@ -3061,4 +3149,19 @@ sub mangle_dirname {
     return $dirname;
 }
 
+=head2 mangle_tablename
+
+create a string from a that is suitable to use as part of an SQL table
+name, mainly by converting all chars except \w to _
+
+=cut
+sub mangle_tablename {
+    my $tablename = shift;
+    return unless defined $tablename;
+
+    $tablename =~ s/[^\w_]/_/g;
+
+    return $tablename;
+}
+
 1;
index 22b6ed4a784192bb865dff83731255b1979a1e39..ea59015baa2507fdc8fe77d1c77ebdb2d5db2fa7 100755 (executable)
@@ -281,7 +281,7 @@ while read commit parents; do
                        die "Could not checkout the index"
                # files that $commit removed are now still in the working tree;
                # remove them, else they would be added again
-               git clean -q -f -x
+               git clean -d -q -f -x
                eval "$filter_tree" < /dev/null ||
                        die "tree filter failed: $filter_tree"
 
index cfe46a857e5fd319fa6eb49474ddbb37bd47c537..0ab478ef90aba9048a2de785d538da16e1bae431 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=0.9.GITGUI
+DEF_VER=0.10.GITGUI
 
 LF='
 '
index 5e97fbf03e3f79fd3be52c332e2b13f68673b39e..7c25bb98089ec4c0a57993020a30d2d1afad8dae 100755 (executable)
@@ -1846,6 +1846,22 @@ proc add_range_to_selection {w x y} {
        $w tag add in_sel $begin.0 [expr {$end + 1}].0
 }
 
+proc show_more_context {} {
+       global repo_config
+       if {$repo_config(gui.diffcontext) < 99} {
+               incr repo_config(gui.diffcontext)
+               reshow_diff
+       }
+}
+
+proc show_less_context {} {
+       global repo_config
+       if {$repo_config(gui.diffcontext) >= 1} {
+               incr repo_config(gui.diffcontext) -1
+               reshow_diff
+       }
+}
+
 ######################################################################
 ##
 ## ui construction
@@ -2046,6 +2062,16 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} {
 
        .mbar.commit add separator
 
+       .mbar.commit add command -label [mc "Show Less Context"] \
+               -command show_less_context \
+               -accelerator $M1T-\-
+
+       .mbar.commit add command -label [mc "Show More Context"] \
+               -command show_more_context \
+               -accelerator $M1T-=
+
+       .mbar.commit add separator
+
        .mbar.commit add command -label [mc "Sign Off"] \
                -command do_signoff \
                -accelerator $M1T-S
@@ -2593,17 +2619,11 @@ lappend diff_actions [list $ctxm entryconf $ui_diff_applyhunk -state]
 $ctxm add separator
 $ctxm add command \
        -label [mc "Show Less Context"] \
-       -command {if {$repo_config(gui.diffcontext) >= 1} {
-               incr repo_config(gui.diffcontext) -1
-               reshow_diff
-       }}
+       -command show_less_context
 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
 $ctxm add command \
        -label [mc "Show More Context"] \
-       -command {if {$repo_config(gui.diffcontext) < 99} {
-               incr repo_config(gui.diffcontext)
-               reshow_diff
-       }}
+       -command show_more_context
 lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state]
 $ctxm add separator
 $ctxm add command \
@@ -2695,6 +2715,11 @@ bind $ui_comm <$M1B-Key-v> {tk_textPaste %W; %W see insert; break}
 bind $ui_comm <$M1B-Key-V> {tk_textPaste %W; %W see insert; break}
 bind $ui_comm <$M1B-Key-a> {%W tag add sel 0.0 end;break}
 bind $ui_comm <$M1B-Key-A> {%W tag add sel 0.0 end;break}
+bind $ui_comm <$M1B-Key-minus> {show_less_context;break}
+bind $ui_comm <$M1B-Key-KP_Subtract> {show_less_context;break}
+bind $ui_comm <$M1B-Key-equal> {show_more_context;break}
+bind $ui_comm <$M1B-Key-plus> {show_more_context;break}
+bind $ui_comm <$M1B-Key-KP_Add> {show_more_context;break}
 
 bind $ui_diff <$M1B-Key-x> {tk_textCopy %W;break}
 bind $ui_diff <$M1B-Key-X> {tk_textCopy %W;break}
@@ -2738,6 +2763,11 @@ bind .   <$M1B-Key-t> do_add_selection
 bind .   <$M1B-Key-T> do_add_selection
 bind .   <$M1B-Key-i> do_add_all
 bind .   <$M1B-Key-I> do_add_all
+bind .   <$M1B-Key-minus> {show_less_context;break}
+bind .   <$M1B-Key-KP_Subtract> {show_less_context;break}
+bind .   <$M1B-Key-equal> {show_more_context;break}
+bind .   <$M1B-Key-plus> {show_more_context;break}
+bind .   <$M1B-Key-KP_Add> {show_more_context;break}
 bind .   <$M1B-Key-Return> do_commit
 foreach i [list $ui_index $ui_workdir] {
        bind $i <Button-1>       "toggle_or_diff         $i %x %y; break"
index d281938e33d86bf0e6dc1de479595d3a8b1ffaac..89b6d51ea011d5b0fc8a343ffdda078d659571cb 100644 (file)
@@ -9,7 +9,7 @@ msgstr ""
 "Project-Id-Version: fr\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2008-03-14 07:18+0100\n"
-"PO-Revision-Date: 2008-01-14 21:08+0100\n"
+"PO-Revision-Date: 2008-04-04 22:05+0200\n"
 "Last-Translator: Christian Couder <chriscool@tuxfamily.org>\n"
 "Language-Team: French\n"
 "MIME-Version: 1.0\n"
@@ -344,8 +344,7 @@ msgstr "Documentation en ligne"
 #: git-gui.sh:2238
 #, tcl-format
 msgid "fatal: cannot stat path %s: No such file or directory"
-msgstr ""
-"fatale : pas d'infos sur le chemin %s : Fichier ou répertoire inexistant"
+msgstr "erreur fatale : pas d'infos sur le chemin %s : Fichier ou répertoire inexistant"
 
 #: git-gui.sh:2271
 msgid "Current Branch:"
@@ -630,8 +629,7 @@ msgstr "Merci de choisir une branche de suivi"
 #: lib/branch_create.tcl:140
 #, tcl-format
 msgid "Tracking branch %s is not a branch in the remote repository."
-msgstr ""
-"La branche de suivi %s n'est pas une branche dans le référentiel distant."
+msgstr "La branche de suivi %s n'est pas une branche dans le référentiel distant."
 
 #: lib/branch_create.tcl:153 lib/branch_rename.tcl:86
 msgid "Please supply a branch name."
@@ -751,7 +749,7 @@ msgstr "Récupération de %s Ã  partir de %s"
 #: lib/checkout_op.tcl:127
 #, tcl-format
 msgid "fatal: Cannot resolve %s"
-msgstr "Erreur fatale : Impossible de résoudre %s"
+msgstr "erreur fatale : Impossible de résoudre %s"
 
 #: lib/checkout_op.tcl:140 lib/console.tcl:81 lib/database.tcl:31
 msgid "Close"
@@ -798,12 +796,9 @@ msgid ""
 "\n"
 "The rescan will be automatically started now.\n"
 msgstr ""
-"L'état lors de la dernière synchronisation ne correspond plus Ã  l'état du "
-"référentiel.\n"
+"L'état lors de la dernière synchronisation ne correspond plus Ã  l'état du référentiel.\n"
 "\n"
-"Un autre programme Git a modifié ce référentiel depuis la dernière "
-"synchronisation. Une resynchronisation doit Ãªtre effectuée avant de pouvoir "
-"modifier la branche courante.\n"
+"Un autre programme Git a modifié ce référentiel depuis la dernière synchronisation. Une resynchronisation doit Ãªtre effectuée avant de pouvoir modifier la branche courante.\n"
 "\n"
 "Cela va Ãªtre fait tout de suite automatiquement.\n"
 
@@ -814,13 +809,12 @@ msgstr "Mise Ã  jour du répertoire courant avec '%s'..."
 
 #: lib/checkout_op.tcl:323
 msgid "files checked out"
-msgstr ""
+msgstr "fichiers empruntés"
 
 #: lib/checkout_op.tcl:353
 #, tcl-format
 msgid "Aborted checkout of '%s' (file level merging is required)."
-msgstr ""
-"Emprunt de '%s' abandonné. (Il est nécessaire de fusionner des fichiers.)"
+msgstr "Emprunt de '%s' abandonné. (Il est nécessaire de fusionner des fichiers.)"
 
 #: lib/checkout_op.tcl:354
 msgid "File level merge required."
@@ -1089,8 +1083,7 @@ msgstr ""
 
 #: lib/choose_repository.tcl:880
 msgid "Cannot determine HEAD.  See console output for details."
-msgstr ""
-"Impossible de déterminer HEAD. Voir la sortie console pour plus de détails."
+msgstr "Impossible de déterminer HEAD. Voir la sortie console pour plus de détails."
 
 #: lib/choose_repository.tcl:889
 #, tcl-format
@@ -1292,32 +1285,31 @@ msgstr "attention : Tcl ne supporte pas l'encodage '%s'."
 
 #: lib/commit.tcl:221
 msgid "Calling pre-commit hook..."
-msgstr ""
+msgstr "Appel du programme externe d'avant commit..."
 
 #: lib/commit.tcl:236
 msgid "Commit declined by pre-commit hook."
-msgstr ""
+msgstr "Commit refusé par le programme externe d'avant commit."
 
 #: lib/commit.tcl:259
 msgid "Calling commit-msg hook..."
-msgstr ""
+msgstr "Appel du programme externe de message de commit..."
 
 #: lib/commit.tcl:274
 msgid "Commit declined by commit-msg hook."
-msgstr ""
+msgstr "Commit refusé par le programme externe de message de commit."
 
 #: lib/commit.tcl:287
 msgid "Committing changes..."
-msgstr ""
+msgstr "Commit des modifications..."
 
 #: lib/commit.tcl:303
 msgid "write-tree failed:"
 msgstr "write-tree a Ã©choué :"
 
 #: lib/commit.tcl:304 lib/commit.tcl:348 lib/commit.tcl:368
-#, fuzzy
 msgid "Commit failed."
-msgstr "Le clonage a Ã©choué."
+msgstr "Le commit a Ã©choué."
 
 #: lib/commit.tcl:321
 #, tcl-format
@@ -1479,8 +1471,7 @@ msgstr "Erreur lors du chargement des différences :"
 
 #: lib/diff.tcl:303
 msgid "Failed to unstage selected hunk."
-msgstr ""
-"La suppression dans le pré-commit de la section sélectionnée a Ã©chouée."
+msgstr "La suppression dans le pré-commit de la section sélectionnée a Ã©chouée."
 
 #: lib/diff.tcl:310
 msgid "Failed to stage selected hunk."
@@ -1510,8 +1501,7 @@ msgstr "Erreur de pré-commit"
 msgid ""
 "Updating the Git index failed.  A rescan will be automatically started to "
 "resynchronize git-gui."
-msgstr ""
-"Le pré-commit a Ã©choué. Une resynchronisation va Ãªtre lancée automatiquement."
+msgstr "Le pré-commit a Ã©choué. Une resynchronisation va Ãªtre lancée automatiquement."
 
 #: lib/index.tcl:27
 msgid "Continue"
@@ -1527,9 +1517,8 @@ msgid "Unstaging %s from commit"
 msgstr "Supprimer %s du commit"
 
 #: lib/index.tcl:313
-#, fuzzy
 msgid "Ready to commit."
-msgstr "Pré-commité"
+msgstr "Prêt ÃƒÂ  ÃƒÂªtre commité."
 
 #: lib/index.tcl:326
 #, tcl-format
@@ -1627,9 +1616,9 @@ msgid "%s of %s"
 msgstr "%s de %s"
 
 #: lib/merge.tcl:119
-#, fuzzy, tcl-format
+#, tcl-format
 msgid "Merging %s and %s..."
-msgstr "Fusion de %s et %s"
+msgstr "Fusion de %s et %s..."
 
 #: lib/merge.tcl:130
 msgid "Merge completed successfully."
@@ -1693,9 +1682,8 @@ msgid "Aborting"
 msgstr "Abandon"
 
 #: lib/merge.tcl:238
-#, fuzzy
 msgid "files reset"
-msgstr "fichiers"
+msgstr "fichiers réinitialisés"
 
 #: lib/merge.tcl:265
 msgid "Abort failed."
@@ -1759,9 +1747,8 @@ msgid "Number of Diff Context Lines"
 msgstr "Nombre de lignes de contexte dans les diffs"
 
 #: lib/option.tcl:127
-#, fuzzy
 msgid "Commit Message Text Width"
-msgstr "Message de commit :"
+msgstr "Largeur du texte de message de commit"
 
 #: lib/option.tcl:128
 msgid "New Branch Name Template"
@@ -1769,7 +1756,7 @@ msgstr "Nouveau modèle de nom de branche"
 
 #: lib/option.tcl:192
 msgid "Spelling Dictionary:"
-msgstr ""
+msgstr "Dictionnaire d'orthographe :"
 
 #: lib/option.tcl:216
 msgid "Change Font"
@@ -1898,40 +1885,40 @@ msgstr "Impossible d'écrire l'icône :"
 
 #: lib/spellcheck.tcl:57
 msgid "Unsupported spell checker"
-msgstr ""
+msgstr "Vérificateur d'orthographe non supporté"
 
 #: lib/spellcheck.tcl:65
 msgid "Spell checking is unavailable"
-msgstr ""
+msgstr "La vérification d'orthographe n'est pas disponible"
 
 #: lib/spellcheck.tcl:68
 msgid "Invalid spell checking configuration"
-msgstr ""
+msgstr "Configuration de vérification d'orthographe invalide"
 
 #: lib/spellcheck.tcl:70
 #, tcl-format
 msgid "Reverting dictionary to %s."
-msgstr ""
+msgstr "Réinitialisation du dictionnaire Ã  %s."
 
 #: lib/spellcheck.tcl:73
 msgid "Spell checker silently failed on startup"
-msgstr ""
+msgstr "La vérification d'orthographe a Ã©chouée silentieusement au démarrage"
 
 #: lib/spellcheck.tcl:80
 msgid "Unrecognized spell checker"
-msgstr ""
+msgstr "Vérificateur d'orthographe non reconnu"
 
 #: lib/spellcheck.tcl:180
 msgid "No Suggestions"
-msgstr ""
+msgstr "Aucune suggestion"
 
 #: lib/spellcheck.tcl:381
 msgid "Unexpected EOF from spell checker"
-msgstr ""
+msgstr "Fin de fichier innatendue envoyée par le vérificateur d'orthographe"
 
 #: lib/spellcheck.tcl:385
 msgid "Spell Checker Failed"
-msgstr ""
+msgstr "Le vérificateur d'orthographe a Ã©choué"
 
 #: lib/status_bar.tcl:83
 #, tcl-format
@@ -2002,3 +1989,4 @@ msgstr "Utiliser des petits paquets (pour les connexions lentes)"
 #: lib/transport.tcl:168
 msgid "Include tags"
 msgstr "Inclure les marques"
+
index 0c2b791eab3de64a8b642460b4b2b959936cca96..81afb5cfcd67731a6f8c76a032408a8f048cc1c4 100755 (executable)
@@ -1900,7 +1900,7 @@ sub prop_walk {
 
        foreach (sort keys %$dirent) {
                next if $dirent->{$_}->{kind} != $SVN::Node::dir;
-               $self->prop_walk($path . '/' . $_, $rev, $sub);
+               $self->prop_walk($p . $_, $rev, $sub);
        }
 }
 
@@ -2239,12 +2239,13 @@ sub find_parent_branch {
                # just grow a tail if we're not unique enough :x
                $ref_id .= '-' while find_ref($ref_id);
                print STDERR "Initializing parent: $ref_id\n";
-               my ($u, $p) = ($new_url, '');
+               my ($u, $p, $repo_id) = ($new_url, '', $ref_id);
                if ($u =~ s#^\Q$url\E(/|$)##) {
                        $p = $u;
                        $u = $url;
+                       $repo_id = $self->{repo_id};
                }
-               $gs = Git::SVN->init($u, $p, $self->{repo_id}, $ref_id, 1);
+               $gs = Git::SVN->init($u, $p, $repo_id, $ref_id, 1);
        }
        my ($r0, $parent) = $gs->find_rev_before($r, 1);
        if (!defined $r0 || !defined $parent) {
diff --git a/git.c b/git.c
index b7729d72cf8dcec32215e968d39dcf675302e216..c4e4644b30e184e6496fb5a4877f3141488f8f44 100644 (file)
--- a/git.c
+++ b/git.c
@@ -148,8 +148,9 @@ static int handle_alias(int *argcp, const char ***argv)
        const char** new_argv;
        const char *alias_command;
        char *alias_string;
+       int unused_nongit;
 
-       subdir = setup_git_directory_gently(NULL);
+       subdir = setup_git_directory_gently(&unused_nongit);
 
        alias_command = (*argv)[0];
        alias_string = alias_lookup(alias_command);
index 84ab02e15f6bdecdd04e8835e3aefd0875efea44..9a4d9c40cf6ec1bed01a2c2b950efb2d9887a8a5 100644 (file)
@@ -8045,11 +8045,11 @@ proc doprefs {} {
     grid $top.cdisp - -sticky w -pady 10
     label $top.bg -padx 40 -relief sunk -background $bgcolor
     button $top.bgbut -text [mc "Background"] -font optionfont \
-       -command [list choosecolor bgcolor 0 $top.bg background setbg]
+       -command [list choosecolor bgcolor {} $top.bg background setbg]
     grid x $top.bgbut $top.bg -sticky w
     label $top.fg -padx 40 -relief sunk -background $fgcolor
     button $top.fgbut -text [mc "Foreground"] -font optionfont \
-       -command [list choosecolor fgcolor 0 $top.fg foreground setfg]
+       -command [list choosecolor fgcolor {} $top.fg foreground setfg]
     grid x $top.fgbut $top.fg -sticky w
     label $top.diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
     button $top.diffoldbut -text [mc "Diff: old lines"] -font optionfont \
@@ -8069,7 +8069,7 @@ proc doprefs {} {
     grid x $top.hunksepbut $top.hunksep -sticky w
     label $top.selbgsep -padx 40 -relief sunk -background $selectbgcolor
     button $top.selbgbut -text [mc "Select bg"] -font optionfont \
-       -command [list choosecolor selectbgcolor 0 $top.selbgsep background setselbg]
+       -command [list choosecolor selectbgcolor {} $top.selbgsep background setselbg]
     grid x $top.selbgbut $top.selbgsep -sticky w
 
     label $top.cfont -text [mc "Fonts: press to choose"]
index ec73cb1256ba99a990648c548348ecdc3340a592..73d098a433f4238c43603ab03c838c1356e7ab7a 100755 (executable)
@@ -2164,7 +2164,7 @@ sub parse_difftree_raw_line {
                $res{'to_mode'} = $2;
                $res{'from_id'} = $3;
                $res{'to_id'} = $4;
-               $res{'status'} = $res{'status_str'} = $5;
+               $res{'status'} = $5;
                $res{'similarity'} = $6;
                if ($res{'status'} eq 'R' || $res{'status'} eq 'C') { # renamed or copied
                        ($res{'from_file'}, $res{'to_file'}) = map { unquote($_) } split("\t", $7);
@@ -2180,7 +2180,6 @@ sub parse_difftree_raw_line {
                $res{'to_mode'} = pop @{$res{'from_mode'}};
                $res{'from_id'} = [ split(' ', $3) ];
                $res{'to_id'} = pop @{$res{'from_id'}};
-               $res{'status_str'} = $4;
                $res{'status'} = [ split('', $4) ];
                $res{'to_file'} = unquote($5);
        }
@@ -3002,7 +3001,7 @@ sub fill_from_file_info {
 sub is_deleted {
        my $diffinfo = shift;
 
-       return $diffinfo->{'status_str'} =~ /D/;
+       return $diffinfo->{'to_id'} eq ('0' x 40);
 }
 
 # does patch correspond to [previous] difftree raw line
diff --git a/help.c b/help.c
index ecaca770d398e8068ec18e9f4c5058044001d4ea..10298fb0a197f18008783214de11e424fbadb77d 100644 (file)
--- a/help.c
+++ b/help.c
@@ -30,6 +30,7 @@ static struct option builtin_help_options[] = {
                        HELP_FORMAT_WEB),
        OPT_SET_INT('i', "info", &help_format, "show info page",
                        HELP_FORMAT_INFO),
+       OPT_END(),
 };
 
 static const char * const builtin_help_usage[] = {
index 5b2963998cc497177d913b6224799531d45dbb4a..9d54061601c2b378089a88142138ce3e0da1761e 100644 (file)
@@ -317,8 +317,10 @@ void show_log(struct rev_info *opt, const char *sep)
        if (opt->show_log_size)
                printf("log size %i\n", (int)msgbuf.len);
 
-       if (msgbuf.len)
-               printf("%s%s%s", msgbuf.buf, extra, sep);
+       if (msgbuf.len) {
+               fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout);
+               printf("%s%s", extra, sep);
+       }
        strbuf_release(&msgbuf);
 }
 
diff --git a/mktag.c b/mktag.c
index b05260c83fd8ef766eb2e16fa355501bf1f62fb5..0b34341f711a903d4a12fe96dc6ef63e55fb2f5b 100644 (file)
--- a/mktag.c
+++ b/mktag.c
@@ -8,10 +8,11 @@
  * message and a signature block that git itself doesn't care about,
  * but that can be verified with gpg or similar.
  *
- * The first three lines are guaranteed to be at least 63 bytes:
+ * The first four lines are guaranteed to be at least 83 bytes:
  * "object <sha1>\n" is 48 bytes, "type tag\n" at 9 bytes is the
- * shortest possible type-line, and "tag .\n" at 6 bytes is the
- * shortest single-character-tag line.
+ * shortest possible type-line, "tag .\n" at 6 bytes is the shortest
+ * single-character-tag line, and "tagger . <> 0 +0000\n" at 20 bytes is
+ * the shortest possible tagger-line.
  */
 
 /*
@@ -43,9 +44,10 @@ static int verify_tag(char *buffer, unsigned long size)
        int typelen;
        char type[20];
        unsigned char sha1[20];
-       const char *object, *type_line, *tag_line, *tagger_line;
+       const char *object, *type_line, *tag_line, *tagger_line, *lb, *rb;
+       size_t len;
 
-       if (size < 64)
+       if (size < 84)
                return error("wanna fool me ? you obviously got the size wrong !");
 
        buffer[size] = 0;
@@ -97,11 +99,51 @@ static int verify_tag(char *buffer, unsigned long size)
        /* Verify the tagger line */
        tagger_line = tag_line;
 
-       if (memcmp(tagger_line, "tagger", 6) || (tagger_line[6] == '\n'))
-               return error("char" PD_FMT ": could not find \"tagger\"", tagger_line - buffer);
-
-       /* TODO: check for committer info + blank line? */
-       /* Also, the minimum length is probably + "tagger .", or 63+8=71 */
+       if (memcmp(tagger_line, "tagger ", 7))
+               return error("char" PD_FMT ": could not find \"tagger \"",
+                       tagger_line - buffer);
+
+       /*
+        * Check for correct form for name and email
+        * i.e. " <" followed by "> " on _this_ line
+        * No angle brackets within the name or email address fields.
+        * No spaces within the email address field.
+        */
+       tagger_line += 7;
+       if (!(lb = strstr(tagger_line, " <")) || !(rb = strstr(lb+2, "> ")) ||
+               strpbrk(tagger_line, "<>\n") != lb+1 ||
+               strpbrk(lb+2, "><\n ") != rb)
+               return error("char" PD_FMT ": malformed tagger field",
+                       tagger_line - buffer);
+
+       /* Check for author name, at least one character, space is acceptable */
+       if (lb == tagger_line)
+               return error("char" PD_FMT ": missing tagger name",
+                       tagger_line - buffer);
+
+       /* timestamp, 1 or more digits followed by space */
+       tagger_line = rb + 2;
+       if (!(len = strspn(tagger_line, "0123456789")))
+               return error("char" PD_FMT ": missing tag timestamp",
+                       tagger_line - buffer);
+       tagger_line += len;
+       if (*tagger_line != ' ')
+               return error("char" PD_FMT ": malformed tag timestamp",
+                       tagger_line - buffer);
+       tagger_line++;
+
+       /* timezone, 5 digits [+-]hhmm, max. 1400 */
+       if (!((tagger_line[0] == '+' || tagger_line[0] == '-') &&
+             strspn(tagger_line+1, "0123456789") == 4 &&
+             tagger_line[5] == '\n' && atoi(tagger_line+1) <= 1400))
+               return error("char" PD_FMT ": malformed tag timezone",
+                       tagger_line - buffer);
+       tagger_line += 6;
+
+       /* Verify the blank line separating the header from the body */
+       if (*tagger_line != '\n')
+               return error("char" PD_FMT ": trailing garbage in tag header",
+                       tagger_line - buffer);
 
        /* The actual stuff afterwards we don't care about.. */
        return 0;
index 8e64316fe002fe90c58de61e4d6558ee4ad87157..e87cafbe4199acb39fd9113e4b5096de19a3a61c 100644 (file)
@@ -409,3 +409,10 @@ int parse_opt_abbrev_cb(const struct option *opt, const char *arg, int unset)
        *(int *)(opt->value) = v;
        return 0;
 }
+
+int parse_opt_approxidate_cb(const struct option *opt, const char *arg,
+                            int unset)
+{
+       *(unsigned long *)(opt->value) = approxidate(arg);
+       return 0;
+}
index 1af62b0485f2760607b7d3bc3e0ebdca09a53ea4..4ee443dafe146f05d1fe2a46e7e39ca6fdd608f9 100644 (file)
@@ -94,6 +94,9 @@ struct option {
 #define OPT_SET_PTR(s, l, v, h, p)  { OPTION_SET_PTR, (s), (l), (v), NULL, (h), 0, NULL, (p) }
 #define OPT_INTEGER(s, l, v, h)     { OPTION_INTEGER, (s), (l), (v), NULL, (h) }
 #define OPT_STRING(s, l, v, a, h)   { OPTION_STRING,  (s), (l), (v), (a), (h) }
+#define OPT_DATE(s, l, v, h) \
+       { OPTION_CALLBACK, (s), (l), (v), "time",(h), 0, \
+         parse_opt_approxidate_cb }
 #define OPT_CALLBACK(s, l, v, a, h, f) \
        { OPTION_CALLBACK, (s), (l), (v), (a), (h), 0, (f) }
 
@@ -110,6 +113,7 @@ extern NORETURN void usage_with_options(const char * const *usagestr,
 
 /*----- some often used options -----*/
 extern int parse_opt_abbrev_cb(const struct option *, const char *, int);
+extern int parse_opt_approxidate_cb(const struct option *, const char *, int);
 
 #define OPT__VERBOSE(var)  OPT_BOOLEAN('v', "verbose", (var), "be verbose")
 #define OPT__QUIET(var)    OPT_BOOLEAN('q', "quiet",   (var), "be quiet")
index 16bfb86cd3ce6d6b471cdc313114563ca78837dc..6c04176cb877bf78ca1336d40011edcba29996ae 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -457,6 +457,7 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
        const struct commit *commit = c->commit;
        const char *msg = commit->buffer;
        struct commit_list *p;
+       int h1, h2;
 
        /* these are independent of the commit */
        switch (placeholder[0]) {
@@ -478,6 +479,16 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
        case 'n':               /* newline */
                strbuf_addch(sb, '\n');
                return 1;
+       case 'x':
+               /* %x00 == NUL, %x0a == LF, etc. */
+               if (0 <= (h1 = hexval_table[0xff & placeholder[1]]) &&
+                   h1 <= 16 &&
+                   0 <= (h2 = hexval_table[0xff & placeholder[2]]) &&
+                   h2 <= 16) {
+                       strbuf_addch(sb, (h1<<4)|h2);
+                       return 3;
+               } else
+                       return 0;
        }
 
        /* these depend on the commit */
diff --git a/t/t2201-add-update-typechange.sh b/t/t2201-add-update-typechange.sh
new file mode 100755 (executable)
index 0000000..e15e3eb
--- /dev/null
@@ -0,0 +1,140 @@
+#!/bin/sh
+
+test_description='more git add -u'
+
+. ./test-lib.sh
+
+_z40=0000000000000000000000000000000000000000
+
+test_expect_success setup '
+       >xyzzy &&
+       _empty=$(git hash-object --stdin <xyzzy) &&
+       >yomin &&
+       >caskly &&
+       ln -s frotz nitfol &&
+       mkdir rezrov &&
+       >rezrov/bozbar &&
+       git add caskly xyzzy yomin nitfol rezrov/bozbar &&
+
+       test_tick &&
+       git commit -m initial
+
+'
+
+test_expect_success modify '
+       rm -f xyzzy yomin nitfol caskly &&
+       # caskly disappears (not a submodule)
+       mkdir caskly &&
+       # nitfol changes from symlink to regular
+       >nitfol &&
+       # rezrov/bozbar disappears
+       rm -fr rezrov &&
+       ln -s xyzzy rezrov &&
+       # xyzzy disappears (not a submodule)
+       mkdir xyzzy &&
+       echo gnusto >xyzzy/bozbar &&
+       # yomin gets replaced with a submodule
+       mkdir yomin &&
+       >yomin/yomin &&
+       (
+               cd yomin &&
+               git init &&
+               git add yomin &&
+               git commit -m "sub initial"
+       ) &&
+       yomin=$(GIT_DIR=yomin/.git git rev-parse HEAD) &&
+       # yonk is added and then turned into a submodule
+       # this should appear as T in diff-files and as A in diff-index
+       >yonk &&
+       git add yonk &&
+       rm -f yonk &&
+       mkdir yonk &&
+       >yonk/yonk &&
+       (
+               cd yonk &&
+               git init &&
+               git add yonk &&
+               git commit -m "sub initial"
+       ) &&
+       yonk=$(GIT_DIR=yonk/.git git rev-parse HEAD) &&
+       # zifmia is added and then removed
+       # this should appear in diff-files but not in diff-index.
+       >zifmia &&
+       git add zifmia &&
+       rm -f zifmia &&
+       mkdir zifmia &&
+       {
+               git ls-tree -r HEAD |
+               sed -e "s/^/:/" -e "
+                       /       caskly/{
+                               s/      caskly/ $_z40 D&/
+                               s/blob/000000/
+                       }
+                       /       nitfol/{
+                               s/      nitfol/ $_z40 T&/
+                               s/blob/100644/
+                       }
+                       /       rezrov.bozbar/{
+                               s/      rezrov.bozbar/ $_z40 D&/
+                               s/blob/000000/
+                       }
+                       /       xyzzy/{
+                               s/      xyzzy/ $_z40 D&/
+                               s/blob/000000/
+                       }
+                       /       yomin/{
+                           s/  yomin/ $_z40 T&/
+                               s/blob/160000/
+                       }
+               "
+       } >expect &&
+       {
+               cat expect
+               echo ":100644 160000 $_empty $_z40 T    yonk"
+               echo ":100644 000000 $_empty $_z40 D    zifmia"
+       } >expect-files &&
+       {
+               cat expect
+               echo ":000000 160000 $_z40 $_z40 A      yonk"
+       } >expect-index &&
+       {
+               echo "100644 $_empty 0  nitfol"
+               echo "160000 $yomin 0   yomin"
+               echo "160000 $yonk 0    yonk"
+       } >expect-final
+'
+
+test_expect_success diff-files '
+       git diff-files --raw >actual &&
+       diff -u expect-files actual
+'
+
+test_expect_success diff-index '
+       git diff-index --raw HEAD -- >actual &&
+       diff -u expect-index actual
+'
+
+test_expect_success 'add -u' '
+       rm -f ".git/saved-index" &&
+       cp -p ".git/index" ".git/saved-index" &&
+       git add -u &&
+       git ls-files -s >actual &&
+       diff -u expect-final actual
+'
+
+test_expect_success 'commit -a' '
+       if test -f ".git/saved-index"
+       then
+               rm -f ".git/index" &&
+               mv ".git/saved-index" ".git/index"
+       fi &&
+       git commit -m "second" -a &&
+       git ls-files -s >actual &&
+       diff -u expect-final actual &&
+       rm -f .git/index &&
+       git read-tree HEAD &&
+       git ls-files -s >actual &&
+       diff -u expect-final actual
+'
+
+test_done
index bdc6e132cacbccc72a903c1aad1bbfe1364471ab..df1fd6f86f11b40667dfbd8132fef8da45d03d75 100755 (executable)
@@ -44,6 +44,8 @@ cat >tag.sig <<EOF
 xxxxxx 139e9b33986b1c2670fff52c5067603117b3e895
 type tag
 tag mytag
+tagger . <> 0 +0000
+
 EOF
 
 check_verify_failure '"object" line label check' '^error: char0: .*"object "$'
@@ -55,6 +57,8 @@ cat >tag.sig <<EOF
 object zz9e9b33986b1c2670fff52c5067603117b3e895
 type tag
 tag mytag
+tagger . <> 0 +0000
+
 EOF
 
 check_verify_failure '"object" line SHA1 check' '^error: char7: .*SHA1 hash$'
@@ -66,6 +70,8 @@ cat >tag.sig <<EOF
 object 779e9b33986b1c2670fff52c5067603117b3e895
 xxxx tag
 tag mytag
+tagger . <> 0 +0000
+
 EOF
 
 check_verify_failure '"type" line label check' '^error: char47: .*"\\ntype "$'
@@ -85,6 +91,8 @@ cat >tag.sig <<EOF
 object 779e9b33986b1c2670fff52c5067603117b3e895
 type tag
 xxx mytag
+tagger . <> 0 +0000
+
 EOF
 
 check_verify_failure '"tag" line label check #1' \
@@ -121,6 +129,8 @@ cat >tag.sig <<EOF
 object 779e9b33986b1c2670fff52c5067603117b3e895
 type tagggg
 tag mytag
+tagger . <> 0 +0000
+
 EOF
 
 check_verify_failure 'verify object (SHA1/type) check' \
@@ -133,6 +143,8 @@ cat >tag.sig <<EOF
 object $head
 type commit
 tag my tag
+tagger . <> 0 +0000
+
 EOF
 
 check_verify_failure 'verify tag-name check' \
@@ -145,10 +157,12 @@ cat >tag.sig <<EOF
 object $head
 type commit
 tag mytag
+
+This is filler
 EOF
 
 check_verify_failure '"tagger" line label check #1' \
-       '^error: char70: could not find "tagger"$'
+       '^error: char70: could not find "tagger "$'
 
 ############################################################
 # 12. tagger line label check #2
@@ -158,19 +172,180 @@ object $head
 type commit
 tag mytag
 tagger
+
+This is filler
 EOF
 
 check_verify_failure '"tagger" line label check #2' \
-       '^error: char70: could not find "tagger"$'
+       '^error: char70: could not find "tagger "$'
 
 ############################################################
-# 13. create valid tag
+# 13. disallow missing tag author name
 
 cat >tag.sig <<EOF
 object $head
 type commit
 tag mytag
-tagger another@example.com
+tagger  <> 0 +0000
+
+This is filler
+EOF
+
+check_verify_failure 'disallow missing tag author name' \
+       '^error: char77: missing tagger name$'
+
+############################################################
+# 14. disallow missing tag author name
+
+cat >tag.sig <<EOF
+object $head
+type commit
+tag mytag
+tagger T A Gger <
+ > 0 +0000
+
+EOF
+
+check_verify_failure 'disallow malformed tagger' \
+       '^error: char77: malformed tagger field$'
+
+############################################################
+# 15. allow empty tag email
+
+cat >tag.sig <<EOF
+object $head
+type commit
+tag mytag
+tagger T A Gger <> 0 +0000
+
+EOF
+
+test_expect_success \
+    'allow empty tag email' \
+    'git-mktag <tag.sig >.git/refs/tags/mytag 2>message'
+
+############################################################
+# 16. disallow spaces in tag email
+
+cat >tag.sig <<EOF
+object $head
+type commit
+tag mytag
+tagger T A Gger <tag ger@example.com> 0 +0000
+
+EOF
+
+check_verify_failure 'disallow spaces in tag email' \
+       '^error: char77: malformed tagger field$'
+
+############################################################
+# 17. disallow missing tag timestamp
+
+cat >tag.sig <<EOF
+object $head
+type commit
+tag mytag
+tagger T A Gger <tagger@example.com>  
+
+EOF
+
+check_verify_failure 'disallow missing tag timestamp' \
+       '^error: char107: missing tag timestamp$'
+
+############################################################
+# 18. detect invalid tag timestamp1
+
+cat >tag.sig <<EOF
+object $head
+type commit
+tag mytag
+tagger T A Gger <tagger@example.com> Tue Mar 25 15:47:44 2008
+
+EOF
+
+check_verify_failure 'detect invalid tag timestamp1' \
+       '^error: char107: missing tag timestamp$'
+
+############################################################
+# 19. detect invalid tag timestamp2
+
+cat >tag.sig <<EOF
+object $head
+type commit
+tag mytag
+tagger T A Gger <tagger@example.com> 2008-03-31T12:20:15-0500
+
+EOF
+
+check_verify_failure 'detect invalid tag timestamp2' \
+       '^error: char111: malformed tag timestamp$'
+
+############################################################
+# 20. detect invalid tag timezone1
+
+cat >tag.sig <<EOF
+object $head
+type commit
+tag mytag
+tagger T A Gger <tagger@example.com> 1206478233 GMT
+
+EOF
+
+check_verify_failure 'detect invalid tag timezone1' \
+       '^error: char118: malformed tag timezone$'
+
+############################################################
+# 21. detect invalid tag timezone2
+
+cat >tag.sig <<EOF
+object $head
+type commit
+tag mytag
+tagger T A Gger <tagger@example.com> 1206478233 +  30
+
+EOF
+
+check_verify_failure 'detect invalid tag timezone2' \
+       '^error: char118: malformed tag timezone$'
+
+############################################################
+# 22. detect invalid tag timezone3
+
+cat >tag.sig <<EOF
+object $head
+type commit
+tag mytag
+tagger T A Gger <tagger@example.com> 1206478233 -1430
+
+EOF
+
+check_verify_failure 'detect invalid tag timezone3' \
+       '^error: char118: malformed tag timezone$'
+
+############################################################
+# 23. detect invalid header entry
+
+cat >tag.sig <<EOF
+object $head
+type commit
+tag mytag
+tagger T A Gger <tagger@example.com> 1206478233 -0500
+this line should not be here
+
+EOF
+
+check_verify_failure 'detect invalid header entry' \
+       '^error: char124: trailing garbage in tag header$'
+
+############################################################
+# 24. create valid tag
+
+cat >tag.sig <<EOF
+object $head
+type commit
+tag mytag
+tagger T A Gger <tagger@example.com> 1206478233 -0500
+
 EOF
 
 test_expect_success \
@@ -178,7 +353,7 @@ test_expect_success \
     'git-mktag <tag.sig >.git/refs/tags/mytag 2>message'
 
 ############################################################
-# 14. check mytag
+# 25. check mytag
 
 test_expect_success \
     'check mytag' \
index 64f34e329867cbef3c122c96a63cfd844b0953af..43943ab8ca181edbdcc6a68d208cf584b5cda86d 100755 (executable)
@@ -112,4 +112,17 @@ do
        '
 done
 
+test_expect_success 'two lines' '
+
+       >file &&
+       git add file &&
+       echo aaa >file &&
+       git diff >patch &&
+       git add file &&
+       echo bbb >file &&
+       git add file &&
+       test_must_fail git apply --check patch
+
+'
+
 test_done
index 47090c4cf528016bf864116232baf29aeb1e4bfe..9fd9d0700033027921c90290cedc0a31d71c7733 100644 (file)
@@ -78,4 +78,38 @@ test_expect_success 'gc: start with ok gc.pruneExpire' '
 
 '
 
+test_expect_success 'prune: prune nonsense parameters' '
+
+       test_must_fail git prune garbage &&
+       test_must_fail git prune --- &&
+       test_must_fail git prune --no-such-option
+
+'
+
+test_expect_success 'prune: prune unreachable heads' '
+
+       git config core.logAllRefUpdates false &&
+       mv .git/logs .git/logs.old &&
+       : > file2 &&
+       git add file2 &&
+       git commit -m temporary &&
+       tmp_head=$(git rev-list -1 HEAD) &&
+       git reset HEAD^ &&
+       git prune &&
+       test_must_fail git reset $tmp_head --
+
+'
+
+test_expect_success 'prune: do not prune heads listed as an argument' '
+
+       : > file2 &&
+       git add file2 &&
+       git commit -m temporary &&
+       tmp_head=$(git rev-list -1 HEAD) &&
+       git reset HEAD^ &&
+       git prune -- $tmp_head &&
+       git reset $tmp_head --
+
+'
+
 test_done
index 6827249da5182515847d713ae0bb1d23fc58b5c6..efd658adb6d6327863f430b10ab65aa3f112f996 100755 (executable)
@@ -17,6 +17,8 @@ test_expect_success 'setup' '
        make_commit B
        git checkout -b branch B
        make_commit D
+       mkdir dir
+       make_commit dir/D
        make_commit E
        git checkout master
        make_commit C
@@ -41,9 +43,23 @@ test_expect_success 'rewrite, renaming a specific file' '
 '
 
 test_expect_success 'test that the file was renamed' '
-       test d = $(git show HEAD:doh) &&
+       test d = "$(git show HEAD:doh --)" &&
+       ! test -f d &&
        test -f doh &&
-       test d = $(cat doh)
+       test d = "$(cat doh)"
+'
+
+test_expect_success 'rewrite, renaming a specific directory' '
+       git-filter-branch -f --tree-filter "mv dir diroh || :" HEAD
+'
+
+test_expect_success 'test that the directory was renamed' '
+       test dir/d = "$(git show HEAD:diroh/d --)" &&
+       ! test -d dir &&
+       test -d diroh &&
+       ! test -d diroh/dir &&
+       test -f diroh/d &&
+       test dir/d = "$(cat diroh/d)"
 '
 
 git tag oldD HEAD~4
index 75cd33bde8e5906ad68ecdcc904248745d79975c..1a7141ecd7ad1ffcd5081181548920b6a199ab2c 100755 (executable)
@@ -578,6 +578,14 @@ test_expect_success \
        git diff expect actual
 '
 
+# subsequent tests require gpg; check if it is available
+gpg --version >/dev/null
+if [ $? -eq 127 ]; then
+       echo "gpg not found - skipping tag signing and verification tests"
+       test_done
+       exit
+fi
+
 # trying to verify annotated non-signed tags:
 
 test_expect_success \
@@ -600,13 +608,6 @@ test_expect_success \
 
 # creating and verifying signed tags:
 
-gpg --version >/dev/null
-if [ $? -eq 127 ]; then
-       echo "Skipping signed tags tests, because gpg was not found"
-       test_done
-       exit
-fi
-
 # As said here: http://www.gnupg.org/documentation/faqs.html#q6.19
 # the gpg version 1.0.6 didn't parse trust packets correctly, so for
 # that version, creation of signed tags using the generated key fails.
index 6a74b3acfda6774d7996cf5787e9858654357328..2d919d69ef110408b820c76185d6b8da63ea183e 100755 (executable)
@@ -4,8 +4,6 @@ test_description='GIT_EDITOR, core.editor, and stuff'
 
 . ./test-lib.sh
 
-OLD_TERM="$TERM"
-
 for i in GIT_EDITOR core_editor EDITOR VISUAL vi
 do
        cat >e-$i.sh <<-EOF
@@ -116,6 +114,4 @@ test_expect_success 'core.editor with a space' '
 
 '
 
-TERM="$OLD_TERM"
-
 test_done
diff --git a/t/t9121-git-svn-fetch-renamed-dir.sh b/t/t9121-git-svn-fetch-renamed-dir.sh
new file mode 100755 (executable)
index 0000000..5143ed6
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/sh
+#
+# Copyright (c) 2008 Santhosh Kumar Mani
+
+
+test_description='git-svn can fetch renamed directories'
+
+. ./lib-git-svn.sh
+
+test_expect_success 'load repository with renamed directory' "
+       svnadmin load -q $rawsvnrepo < ../t9121/renamed-dir.dump
+       "
+
+test_expect_success 'init and fetch repository' "
+       git svn init $svnrepo/newname &&
+       git svn fetch
+       "
+
+test_done
+
diff --git a/t/t9121/renamed-dir.dump b/t/t9121/renamed-dir.dump
new file mode 100644 (file)
index 0000000..5f9127b
--- /dev/null
@@ -0,0 +1,90 @@
+SVN-fs-dump-format-version: 2
+
+UUID: 06b9b3ad-f546-4fbe-8328-fcb4e6ef5c3f
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2008-04-02T09:11:59.778557Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 117
+Content-length: 117
+
+K 7
+svn:log
+V 14
+initial import
+K 10
+svn:author
+V 8
+santhosh
+K 8
+svn:date
+V 27
+2008-04-02T09:13:03.170863Z
+PROPS-END
+
+Node-path: name
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: name/a.txt
+Node-kind: file
+Node-action: add
+Prop-content-length: 71
+Text-content-length: 6
+Text-content-md5: b1946ac92492d2347c6235b4d2611184
+Content-length: 77
+
+K 13
+svn:mime-type
+V 10
+text/plain
+K 13
+svn:eol-style
+V 2
+LF
+PROPS-END
+hello
+
+
+Revision-number: 2
+Prop-content-length: 109
+Content-length: 109
+
+K 7
+svn:log
+V 7
+renamed
+K 10
+svn:author
+V 8
+santhosh
+K 8
+svn:date
+V 27
+2008-04-02T09:14:22.952186Z
+PROPS-END
+
+Node-path: newname
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 1
+Node-copyfrom-path: name
+
+
+Node-path: name
+Node-action: delete
+
+
index b91b151417758758bba9a7afb89ed54bd9b1dc7a..166b43f783517debf1de716aed4c1952ab1fea4b 100755 (executable)
@@ -420,4 +420,54 @@ test_expect_success 'cvs update (merge no-op)' \
     GIT_CONFIG="$git_config" cvs -Q update &&
     diff -q merge ../merge'
 
+cd "$WORKDIR"
+test_expect_success 'cvs update (-p)' '
+    touch really-empty &&
+    echo Line 1 > no-lf &&
+    echo -n Line 2 >> no-lf &&
+    git add really-empty no-lf &&
+    git commit -q -m "Update -p test" &&
+    git push gitcvs.git >/dev/null &&
+    cd cvswork &&
+    GIT_CONFIG="$git_config" cvs update &&
+    rm -f failures &&
+    for i in merge no-lf empty really-empty; do
+        GIT_CONFIG="$git_config" cvs update -p "$i" >$i.out
+        diff $i.out ../$i >>failures 2>&1
+    done &&
+    test -z "$(cat failures)"
+'
+
+#------------
+# CVS STATUS
+#------------
+
+cd "$WORKDIR"
+test_expect_success 'cvs status' '
+    mkdir status.dir &&
+    echo Line > status.dir/status.file &&
+    echo Line > status.file &&
+    git add status.dir status.file &&
+    git commit -q -m "Status test" &&
+    git push gitcvs.git >/dev/null &&
+    cd cvswork &&
+    GIT_CONFIG="$git_config" cvs update &&
+    GIT_CONFIG="$git_config" cvs status | grep "^File: status.file" >../out &&
+    test $(wc -l <../out) = 2
+'
+
+cd "$WORKDIR"
+test_expect_success 'cvs status (nonrecursive)' '
+    cd cvswork &&
+    GIT_CONFIG="$git_config" cvs status -l | grep "^File: status.file" >../out &&
+    test $(wc -l <../out) = 1
+'
+
+cd "$WORKDIR"
+test_expect_success 'cvs status (no subdirs in header)' '
+    cd cvswork &&
+    GIT_CONFIG="$git_config" cvs status | grep ^File: >../out &&
+    ! grep / <../out
+'
+
 test_done