Merge branch 'jc/1.7.0-diff-whitespace-only-status'
[gitweb.git] / builtin-mktree.c
index 133ab4b0f88aac70a78bd0f3382672236a1bd174..098395fda1932674e29f8d2cb332c722a6cb275f 100644 (file)
@@ -63,15 +63,16 @@ static void write_tree(unsigned char *sha1)
 }
 
 static const char *mktree_usage[] = {
-       "git mktree [-z]",
+       "git mktree [-z] [--missing] [--batch]",
        NULL
 };
 
-static void mktree_line(char *buf, size_t len, int line_termination)
+static void mktree_line(char *buf, size_t len, int line_termination, int allow_missing)
 {
        char *ptr, *ntr;
        unsigned mode;
-       enum object_type type;
+       enum object_type mode_type; /* object type derived from mode */
+       enum object_type obj_type; /* object type derived from sha */
        char *path;
        unsigned char sha1[20];
 
@@ -89,12 +90,13 @@ static void mktree_line(char *buf, size_t len, int line_termination)
            ntr[41] != '\t' ||
            get_sha1_hex(ntr + 1, sha1))
                die("input format error: %s", buf);
-       type = sha1_object_info(sha1, NULL);
-       if (type < 0)
-               die("object %s unavailable", sha1_to_hex(sha1));
+
+       /* It is perfectly normal if we do not have a commit from a submodule */
+       if (S_ISGITLINK(mode))
+               allow_missing = 1;
+
+
        *ntr++ = 0; /* now at the beginning of SHA1 */
-       if (type != type_from_string(ptr))
-               die("object type %s mismatch (%s)", ptr, typename(type));
 
        path = ntr + 41;  /* at the beginning of name */
        if (line_termination && path[0] == '"') {
@@ -103,6 +105,37 @@ static void mktree_line(char *buf, size_t len, int line_termination)
                        die("invalid quoting");
                path = strbuf_detach(&p_uq, NULL);
        }
+
+       /*
+        * Object type is redundantly derivable three ways.
+        * These should all agree.
+        */
+       mode_type = object_type(mode);
+       if (mode_type != type_from_string(ptr)) {
+               die("entry '%s' object type (%s) doesn't match mode type (%s)",
+                       path, ptr, typename(mode_type));
+       }
+
+       /* Check the type of object identified by sha1 */
+       obj_type = sha1_object_info(sha1, NULL);
+       if (obj_type < 0) {
+               if (allow_missing) {
+                       ; /* no problem - missing objects are presumed to be of the right type */
+               } else {
+                       die("entry '%s' object %s is unavailable", path, sha1_to_hex(sha1));
+               }
+       } else {
+               if (obj_type != mode_type) {
+                       /*
+                        * The object exists but is of the wrong type.
+                        * This is a problem regardless of allow_missing
+                        * because the new tree entry will never be correct.
+                        */
+                       die("entry '%s' object %s is a %s but specified type was (%s)",
+                               path, sha1_to_hex(sha1), typename(obj_type), typename(mode_type));
+               }
+       }
+
        append_to_tree(mode, sha1, path);
 }
 
@@ -111,19 +144,47 @@ int cmd_mktree(int ac, const char **av, const char *prefix)
        struct strbuf sb = STRBUF_INIT;
        unsigned char sha1[20];
        int line_termination = '\n';
+       int allow_missing = 0;
+       int is_batch_mode = 0;
+       int got_eof = 0;
+
        const struct option option[] = {
                OPT_SET_INT('z', NULL, &line_termination, "input is NUL terminated", '\0'),
+               OPT_SET_INT( 0 , "missing", &allow_missing, "allow missing objects", 1),
+               OPT_SET_INT( 0 , "batch", &is_batch_mode, "allow creation of more than one tree", 1),
                OPT_END()
        };
 
-       ac = parse_options(ac, av, option, mktree_usage, 0);
-
-       while (strbuf_getline(&sb, stdin, line_termination) != EOF)
-               mktree_line(sb.buf, sb.len, line_termination);
-
+       ac = parse_options(ac, av, prefix, option, mktree_usage, 0);
+
+       while (!got_eof) {
+               while (1) {
+                       if (strbuf_getline(&sb, stdin, line_termination) == EOF) {
+                               got_eof = 1;
+                               break;
+                       }
+                       if (sb.buf[0] == '\0') {
+                               /* empty lines denote tree boundaries in batch mode */
+                               if (is_batch_mode)
+                                       break;
+                               die("input format error: (blank line only valid in batch mode)");
+                       }
+                       mktree_line(sb.buf, sb.len, line_termination, allow_missing);
+               }
+               if (is_batch_mode && got_eof && used < 1) {
+                       /*
+                        * Execution gets here if the last tree entry is terminated with a
+                        * new-line.  The final new-line has been made optional to be
+                        * consistent with the original non-batch behaviour of mktree.
+                        */
+                       ; /* skip creating an empty tree */
+               } else {
+                       write_tree(sha1);
+                       puts(sha1_to_hex(sha1));
+                       fflush(stdout);
+               }
+               used=0; /* reset tree entry buffer for re-use in batch mode */
+       }
        strbuf_release(&sb);
-
-       write_tree(sha1);
-       puts(sha1_to_hex(sha1));
        exit(0);
 }