Merge with master to get diff fixes.
authorJunio C Hamano <junkio@cox.net>
Wed, 17 Aug 2005 05:30:46 +0000 (22:30 -0700)
committerJunio C Hamano <junkio@cox.net>
Wed, 17 Aug 2005 05:30:46 +0000 (22:30 -0700)
15 files changed:
Makefile
cache.h
diff-cache.c
diff-files.c
diff-tree.c
diffcore-pathspec.c
git-diff-script
git-format-patch-script
read-cache.c
rev-parse.c
setup.c [new file with mode: 0644]
sha1_file.c
tools/git-applymbox
tools/git-applypatch
tools/mailinfo.c

index 1623247..c0a8429 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -97,7 +97,7 @@ LIB_H=cache.h object.h blob.h tree.h commit.h tag.h delta.h epoch.h csum-file.h
 LIB_OBJS=read-cache.o sha1_file.o usage.o object.o commit.o tree.o blob.o \
         tag.o date.o index.o diff-delta.o patch-delta.o entry.o path.o \
         refs.o csum-file.o pack-check.o pkt-line.o connect.o ident.o \
-        sha1_name.o
+        sha1_name.o setup.o
 
 LIB_H += rev-cache.h
 LIB_OBJS += rev-cache.o
diff --git a/cache.h b/cache.h
index f14a4ce..6365381 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -140,6 +140,9 @@ extern char *get_graft_file(void);
 
 #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
 
+extern const char **get_pathspec(const char *prefix, char **pathspec);
+extern const char *setup_git_directory(void);
+
 #define alloc_nr(x) (((x)+16)*3/2)
 
 /* Initialize and use the cache information */
index 47a4e09..400a4cb 100644 (file)
@@ -168,10 +168,11 @@ static const char diff_cache_usage[] =
 "[<common diff options>] <tree-ish> [<path>...]"
 COMMON_DIFF_OPTIONS_HELP;
 
-int main(int argc, const char **argv)
+int main(int argc, char **argv)
 {
        const char *tree_name = NULL;
        unsigned char sha1[20];
+       const char *prefix = setup_git_directory();
        const char **pathspec = NULL;
        void *tree;
        unsigned long size;
@@ -179,15 +180,12 @@ int main(int argc, const char **argv)
        int allow_options = 1;
        int i;
 
-       read_cache();
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
 
                if (!allow_options || *arg != '-') {
-                       if (tree_name) {
-                               pathspec = argv + i;
+                       if (tree_name)
                                break;
-                       }
                        tree_name = arg;
                        continue;
                }
@@ -265,12 +263,16 @@ int main(int argc, const char **argv)
                usage(diff_cache_usage);
        }
 
+       pathspec = get_pathspec(prefix, argv + i);
+
        if (find_copies_harder && detect_rename != DIFF_DETECT_COPY)
                usage(diff_cache_usage);
 
        if (!tree_name || get_sha1(tree_name, sha1))
                usage(diff_cache_usage);
 
+       read_cache();
+
        /* The rest is for paths restriction. */
        diff_setup(diff_setup_opt);
 
index 2e6416e..89eb29b 100644 (file)
@@ -41,12 +41,12 @@ static void show_modified(int oldmode, int mode,
        diff_change(oldmode, mode, old_sha1, sha1, path, NULL);
 }
 
-int main(int argc, const char **argv)
+int main(int argc, char **argv)
 {
        static const unsigned char null_sha1[20] = { 0, };
        const char **pathspec;
-       int entries = read_cache();
-       int i;
+       const char *prefix = setup_git_directory();
+       int entries, i;
 
        while (1 < argc && argv[1][0] == '-') {
                if (!strcmp(argv[1], "-p") || !strcmp(argv[1], "-u"))
@@ -95,8 +95,9 @@ int main(int argc, const char **argv)
                argv++; argc--;
        }
 
-       /* Do we have a pathspec? */
-       pathspec = (argc > 1) ? argv + 1 : NULL;
+       /* Find the directory, and set up the pathspec */
+       pathspec = get_pathspec(prefix, argv + 1);
+       entries = read_cache();
 
        if (find_copies_harder && detect_rename != DIFF_DETECT_COPY)
                usage(diff_files_usage);
index 0dd3cda..fc87902 100644 (file)
@@ -395,16 +395,25 @@ static int diff_tree_stdin(char *line)
        return diff_tree_commit(commit, line);
 }
 
+static int count_paths(const char **paths)
+{
+       int i = 0;
+       while (*paths++)
+               i++;
+       return i;
+}
+
 static const char diff_tree_usage[] =
 "git-diff-tree [--stdin] [-m] [-s] [-v] [--pretty] [-t] "
 "[<common diff options>] <tree-ish> <tree-ish>"
 COMMON_DIFF_OPTIONS_HELP;
 
-int main(int argc, const char **argv)
+int main(int argc, char **argv)
 {
        int nr_sha1;
        char line[1000];
        unsigned char sha1[2][20];
+       const char *prefix = setup_git_directory();
 
        nr_sha1 = 0;
        for (;;) {
@@ -523,11 +532,11 @@ int main(int argc, const char **argv)
        if (find_copies_harder && detect_rename != DIFF_DETECT_COPY)
                usage(diff_tree_usage);
 
-       if (argc > 0) {
+       paths = get_pathspec(prefix, argv);
+       if (paths) {
                int i;
 
-               paths = argv;
-               nr_paths = argc;
+               nr_paths = count_paths(paths);
                pathlens = xmalloc(nr_paths * sizeof(int));
                for (i=0; i<nr_paths; i++)
                        pathlens[i] = strlen(paths[i]);
index a48acbc..68fe009 100644 (file)
@@ -29,6 +29,8 @@ static int matches_pathspec(const char *name, struct path_spec *s, int cnt)
                    name[len] == 0 ||
                    name[len] == '/')
                        return 1;
+               if (!len)
+                       return 1;
        }
        return 0;
 }
index 03ed555..926f594 100755 (executable)
@@ -1,7 +1,5 @@
 #!/bin/sh
-. git-sh-setup-script || die "Not a git archive"
-
-rev=($(git-rev-parse --revs-only "$@"))
+rev=($(git-rev-parse --revs-only "$@")) || exit
 flags=($(git-rev-parse --no-revs --flags "$@"))
 files=($(git-rev-parse --no-revs --no-flags "$@"))
 case "${#rev[*]}" in
index 78bb089..3c3413b 100755 (executable)
@@ -6,7 +6,7 @@
 . git-sh-setup-script || die "Not a git archive."
 
 usage () {
-    echo >&2 "usage: $0"' [-n] [-o dir] [--mbox] [--check] [--signoff] [-<diff options>...] upstream [ our-head ]
+    echo >&2 "usage: $0"' [-n] [-o dir] [--keep-subject] [--mbox] [--check] [--signoff] [-<diff options>...] upstream [ our-head ]
 
 Prepare each commit with its patch since our-head forked from upstream,
 one file per patch, for e-mail submission.  Each output file is
@@ -44,6 +44,9 @@ do
     date=t ;;
     -m|--m|--mb|--mbo|--mbox)
     date=t author=t mbox=t ;;
+    -k|--k|--ke|--kee|--keep|--keep-|--keep-s|--keep-su|--keep-sub|\
+    --keep-subj|--keep-subje|--keep-subjec|--keep-subject)
+    keep_subject=t ;;
     -n|--n|--nu|--num|--numb|--numbe|--number|--numbere|--numbered)
     numbered=t ;;
     -s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
@@ -64,6 +67,11 @@ do
     shift
 done
 
+case "$keep_subject$numbered" in
+tt)
+       die '--keep-subject and --numbered are incompatible.' ;;
+esac
+
 revpair=
 case "$#" in
 2)
@@ -142,21 +150,22 @@ do
     {
        mailScript='
        /./d
-       /^$/n
-       s|^\[PATCH[^]]*\] *||'
-
-       case "$mbox" in
-       t)
-           echo 'From nobody Mon Sep 17 00:00:00 2001' ;# UNIX "From" line
-           mailScript="$mailScript"'
-           s|^|Subject: [PATCH'"$num"'] |'
-           ;;
+       /^$/n'
+       case "$keep_subject" in
+       t)  ;;
        *)
            mailScript="$mailScript"'
+           s|^\[PATCH[^]]*\] *||
            s|^|[PATCH'"$num"'] |'
            ;;
        esac
-
+       mailScript="$mailScript"'
+       s|^|Subject: |'
+       case "$mbox" in
+       t)
+           echo 'From nobody Mon Sep 17 00:00:00 2001' ;# UNIX "From" line
+           ;;
+       esac
        eval "$(sed -ne "$whosepatchScript" $commsg)"
        test "$author,$au" = ",$me" || {
                mailScript="$mailScript"'
index 5820f18..ced5973 100644 (file)
@@ -191,6 +191,8 @@ int ce_path_match(const struct cache_entry *ce, const char **pathspec)
                        return 1;
                if (name[matchlen] == '/' || !name[matchlen])
                        return 1;
+               if (!matchlen)
+                       return 1;
        }
        return 0;
 }
index 1c6ae76..39cf635 100644 (file)
@@ -134,7 +134,8 @@ int main(int argc, char **argv)
 {
        int i, as_is = 0;
        unsigned char sha1[20];
-
+       const char *prefix = setup_git_directory();
+       
        for (i = 1; i < argc; i++) {
                char *arg = argv[i];
                char *dotdot;
@@ -189,6 +190,10 @@ int main(int argc, char **argv)
                                for_each_ref(show_reference);
                                continue;
                        }
+                       if (!strcmp(arg, "--show-prefix")) {
+                               puts(prefix);
+                               continue;
+                       }
                        show_arg(arg);
                        continue;
                }
diff --git a/setup.c b/setup.c
new file mode 100644 (file)
index 0000000..1710b16
--- /dev/null
+++ b/setup.c
@@ -0,0 +1,118 @@
+#include "cache.h"
+
+static char *prefix_path(const char *prefix, int len, char *path)
+{
+       char *orig = path;
+       for (;;) {
+               char c;
+               if (*path != '.')
+                       break;
+               c = path[1];
+               /* "." */
+               if (!c) {
+                       path++;
+                       break;
+               }
+               /* "./" */
+               if (c == '/') {
+                       path += 2;
+                       continue;
+               }
+               if (c != '.')
+                       break;
+               c = path[2];
+               if (!c)
+                       path += 2;
+               else if (c == '/')
+                       path += 3;
+               else
+                       break;
+               /* ".." and "../" */
+               /* Remove last component of the prefix */
+               do {
+                       if (!len)
+                               die("'%s' is outside repository", orig);
+                       len--;
+               } while (len && prefix[len-1] != '/');
+               continue;
+       }
+       if (len) {
+               int speclen = strlen(path);
+               char *n = xmalloc(speclen + len + 1);
+       
+               memcpy(n, prefix, len);
+               memcpy(n + len, path, speclen+1);
+               path = n;
+       }
+       return path;
+}
+
+const char **get_pathspec(const char *prefix, char **pathspec)
+{
+       char *entry = *pathspec;
+       char **p;
+       int prefixlen;
+
+       if (!prefix && !entry)
+               return NULL;
+
+       if (!entry) {
+               static const char *spec[2];
+               spec[0] = prefix;
+               spec[1] = NULL;
+               return spec;
+       }
+
+       /* Otherwise we have to re-write the entries.. */
+       p = pathspec;
+       prefixlen = prefix ? strlen(prefix) : 0;
+       do {
+               *p = prefix_path(prefix, prefixlen, entry);
+       } while ((entry = *++p) != NULL);
+       return (const char **) pathspec;
+}
+
+const char *setup_git_directory(void)
+{
+       static char cwd[PATH_MAX+1];
+       int len, offset;
+
+       /*
+        * If GIT_DIR is set explicitly, we're not going
+        * to do any discovery
+        */
+       if (gitenv(GIT_DIR_ENVIRONMENT))
+               return NULL;
+
+       if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')
+               die("Unable to read current working directory");
+
+       offset = len = strlen(cwd);
+       for (;;) {
+               /*
+                * We always want to see a .git/refs/ subdirectory
+                */
+               if (!access(".git/refs/", X_OK)) {
+                       /*
+                        * Then we need either a GIT_OBJECT_DIRECTORY define
+                        * or a .git/objects/ directory
+                        */
+                       if (gitenv(DB_ENVIRONMENT) || !access(".git/objects/", X_OK))
+                               break;
+               }
+               chdir("..");
+               do {
+                       if (!offset)
+                               die("Not a git repository");
+               } while (cwd[--offset] != '/');
+       }
+
+       if (offset == len)
+               return NULL;
+
+       /* Make "offset" point to past the '/', and add a '/' at the end */
+       offset++;
+       cwd[len++] = '/';
+       cwd[len] = 0;
+       return cwd + offset;
+}
index b6ebbc5..7766977 100644 (file)
@@ -240,14 +240,21 @@ static struct alternate_object_database **alt_odb_tail;
  * SHA1, an extra slash for the first level indirection, and the
  * terminating NUL.
  */
-static void link_alt_odb_entries(const char *alt, const char *ep)
+static void link_alt_odb_entries(const char *alt, const char *ep, int sep)
 {
        const char *cp, *last;
        struct alternate_object_database *ent;
 
        last = alt;
-       do {
-               for (cp = last; cp < ep && *cp != ':'; cp++)
+       while (last < ep) {
+               cp = last;
+               if (cp < ep && *cp == '#') {
+                       while (cp < ep && *cp != sep)
+                               cp++;
+                       last = cp + 1;
+                       continue;
+               }
+               for ( ; cp < ep && *cp != sep; cp++)
                        ;
                if (last != cp) {
                        /* 43 = 40-byte + 2 '/' + terminating NUL */
@@ -264,16 +271,16 @@ static void link_alt_odb_entries(const char *alt, const char *ep)
                        ent->base[pfxlen] = ent->base[pfxlen + 3] = '/';
                        ent->base[entlen-1] = 0;
                }
-               while (cp < ep && *cp == ':')
+               while (cp < ep && *cp == sep)
                        cp++;
                last = cp;
-       } while (cp < ep);
+       }
 }
 
 void prepare_alt_odb(void)
 {
        char path[PATH_MAX];
-       char *map, *ep;
+       char *map;
        int fd;
        struct stat st;
        char *alt = gitenv(ALTERNATE_DB_ENVIRONMENT) ? : "";
@@ -282,7 +289,7 @@ void prepare_alt_odb(void)
        if (alt_odb_tail)
                return;
        alt_odb_tail = &alt_odb_list;
-       link_alt_odb_entries(alt, alt + strlen(alt));
+       link_alt_odb_entries(alt, alt + strlen(alt), ':');
 
        fd = open(path, O_RDONLY);
        if (fd < 0)
@@ -296,10 +303,7 @@ void prepare_alt_odb(void)
        if (map == MAP_FAILED)
                return;
 
-       /* Remove the trailing newline */
-       for (ep = map + st.st_size - 1; map < ep && ep[-1] == '\n'; ep--)
-               ;
-       link_alt_odb_entries(map, ep);
+       link_alt_odb_entries(map, map + st.st_size, '\n');
        munmap(map, st.st_size);
 }
 
index e44f5d7..889d4c1 100755 (executable)
@@ -9,7 +9,7 @@
 ## You give it a mbox-format collection of emails, and it will try to
 ## apply them to the kernel using "applypatch"
 ##
-## applymbox [ -q ] (-c .dotest/msg-number | mail_archive) [Signoff_file]"
+## applymbox [ -k ] [ -q ] (-c .dotest/msg-number | mail_archive) [Signoff_file]"
 ##
 ## The patch application may fail in the middle.  In which case:
 ## (1) look at .dotest/patch and fix it up to apply
 ## use a Signoff_file, because applypatch wants to append the sign-off
 ## message to msg-clean every time it is run.
 
-query_apply= continue= resume=t
+keep_subject= query_apply= continue= resume=t
 while case "$#" in 0) break ;; esac
 do
        case "$1" in
+       -k)     keep_subject=-k ;;
        -q)     query_apply=t ;;
        -c)     continue="$2"; resume=f; shift ;;
        -*)     usage ;;
@@ -41,6 +42,9 @@ esac
 case "$query_apply" in
 t)     touch .dotest/.query_apply
 esac
+case "$keep_subject" in
+-k)    : >.dotest/.keep_subject
+esac
 
 signoff="$1"
 set x .dotest/0*
@@ -52,7 +56,8 @@ do
     f,$i)      resume=t;;
     f,*)       continue;;
     *)
-           git-mailinfo .dotest/msg .dotest/patch <$i >.dotest/info || exit 1
+           git-mailinfo $keep_subject \
+               .dotest/msg .dotest/patch <$i >.dotest/info || exit 1
            git-stripspace < .dotest/msg > .dotest/msg-clean
            ;;
     esac
index 5a3a44b..406fef3 100755 (executable)
@@ -16,6 +16,7 @@ final=.dotest/final-commit
 ## If this file exists, we ask before applying
 ##
 query_apply=.dotest/.query_apply
+keep_subject=.dotest/.keep_subject
 MSGFILE=$1
 PATCHFILE=$2
 INFO=$3
@@ -30,8 +31,10 @@ export SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' .dotest/info)"
 if [ -n "$signoff" -a -f "$signoff" ]; then
        cat $signoff >> $MSGFILE
 fi
+patch_header=
+test -f "$keep_subject" || patch_header='[PATCH] '
 
-(echo "[PATCH] $SUBJECT" ; if [ -s $MSGFILE ]; then echo ; cat $MSGFILE; fi ) > $final
+(echo "$patch_header$SUBJECT" ; if [ -s $MSGFILE ]; then echo ; cat $MSGFILE; fi ) > $final
 
 f=0
 [ -f $query_apply ] || f=1
index fb2ea2b..a36123a 100644 (file)
@@ -9,6 +9,7 @@
 
 static FILE *cmitmsg, *patchfile;
 
+static int keep_subject = 0;
 static char line[1000];
 static char date[1000];
 static char name[1000];
@@ -101,6 +102,8 @@ static void check_line(char *line, int len)
 
 static char * cleanup_subject(char *subject)
 {
+       if (keep_subject)
+               return subject;
        for (;;) {
                char *p;
                int len, remove;
@@ -242,8 +245,20 @@ static void usage(void)
        exit(1);
 }
 
+static const char mailinfo_usage[] =
+"git-mailinfo [-k] msg patch <mail >info";
 int main(int argc, char ** argv)
 {
+       while (1 < argc && argv[1][0] == '-') {
+               if (!strcmp(argv[1], "-k"))
+                       keep_subject = 1;
+               else {
+                       fprintf(stderr, "usage: %s\n", mailinfo_usage);
+                       exit(1);
+               }
+               argc--; argv++;
+       }
+
        if (argc != 3)
                usage();
        cmitmsg = fopen(argv[1], "w");