Merge branch 'jn/fast-import-subtree'
authorJunio C Hamano <gitster@pobox.com>
Wed, 18 Aug 2010 19:14:41 +0000 (12:14 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 18 Aug 2010 19:14:41 +0000 (12:14 -0700)
* jn/fast-import-subtree:
Teach fast-import to import subtrees named by tree id

1  2 
Documentation/git-fast-import.txt
fast-import.c
t/t9300-fast-import.sh
index 77a0a2481a34f987aab4688002a6e6a0ae2e497f,f4d9aeb13761806041303c8c85b75483c8496fb1..966ba4f21337e72f7be0a5b852e76a8b12192f7f
@@@ -439,7 -439,7 +439,7 @@@ Marks must be declared (via `mark`) bef
  * A complete 40 byte or abbreviated commit SHA-1 in hex.
  
  * Any valid Git SHA-1 expression that resolves to a commit.  See
 -  ``SPECIFYING REVISIONS'' in linkgit:git-rev-parse[1] for details.
 +  ``SPECIFYING REVISIONS'' in linkgit:gitrevisions[1] for details.
  
  The special case of restarting an incremental import from the
  current branch value should be written as:
@@@ -482,9 -482,11 +482,11 @@@ External data format:
        'M' SP <mode> SP <dataref> SP <path> LF
  ....
  +
- Here `<dataref>` can be either a mark reference (`:<idnum>`)
+ Here usually `<dataref>` must be either a mark reference (`:<idnum>`)
  set by a prior `blob` command, or a full 40-byte SHA-1 of an
- existing Git blob object.
+ existing Git blob object.  If `<mode>` is `040000`` then
+ `<dataref>` must be the full 40-byte SHA-1 of an existing
+ Git tree object or a mark reference set with `--import-marks`.
  
  Inline data format::
        The data content for the file has not been supplied yet.
@@@ -509,6 -511,8 +511,8 @@@ in octal.  Git only supports the follow
  * `160000`: A gitlink, SHA-1 of the object refers to a commit in
    another repository. Git links can only be specified by SHA or through
    a commit mark. They are used to implement submodules.
+ * `040000`: A subdirectory.  Subdirectories can only be specified by
+   SHA or through a tree mark set with `--import-marks`.
  
  In both formats `<path>` is the complete path of the file to be added
  (if not already existing) or modified (if already existing).
diff --combined fast-import.c
index ddad289dae37c2115f57f88dc207f0d2fa6ab1f3,ad6843a8b6cf0a59466a87a89a90165751923273..dd51ac48b60d93031aa761d6731dd066c04e6989
@@@ -1666,7 -1666,7 +1666,7 @@@ static void dump_marks_helper(FILE *f
        if (m->shift) {
                for (k = 0; k < 1024; k++) {
                        if (m->data.sets[k])
 -                              dump_marks_helper(f, (base + k) << m->shift,
 +                              dump_marks_helper(f, base + (k << m->shift),
                                        m->data.sets[k]);
                }
        } else {
@@@ -2131,6 -2131,7 +2131,7 @@@ static void file_change_m(struct branc
        case S_IFREG | 0644:
        case S_IFREG | 0755:
        case S_IFLNK:
+       case S_IFDIR:
        case S_IFGITLINK:
                /* ok */
                break;
                 * another repository.
                 */
        } else if (inline_data) {
+               if (S_ISDIR(mode))
+                       die("Directories cannot be specified 'inline': %s",
+                               command_buf.buf);
                if (p != uq.buf) {
                        strbuf_addstr(&uq, p);
                        p = uq.buf;
                }
                read_next_command();
                parse_and_store_blob(&last_blob, sha1, 0);
-       } else if (oe) {
-               if (oe->type != OBJ_BLOB)
-                       die("Not a blob (actually a %s): %s",
-                               typename(oe->type), command_buf.buf);
        } else {
-               enum object_type type = sha1_object_info(sha1, NULL);
+               enum object_type expected = S_ISDIR(mode) ?
+                                               OBJ_TREE: OBJ_BLOB;
+               enum object_type type = oe ? oe->type :
+                                       sha1_object_info(sha1, NULL);
                if (type < 0)
-                       die("Blob not found: %s", command_buf.buf);
-               if (type != OBJ_BLOB)
-                       die("Not a blob (actually a %s): %s",
-                           typename(type), command_buf.buf);
+                       die("%s not found: %s",
+                                       S_ISDIR(mode) ?  "Tree" : "Blob",
+                                       command_buf.buf);
+               if (type != expected)
+                       die("Not a %s (actually a %s): %s",
+                               typename(expected), typename(type),
+                               command_buf.buf);
        }
  
        tree_content_set(&b->branch_tree, p, sha1, mode, NULL);
diff --combined t/t9300-fast-import.sh
index 2aeed7bd0601a0587f99250377001be6287772e5,50d5913cc12ae5e67ec5b99cd001a7adf106ee4f..96d07f183377f8822257cb3a1dad29023b391462
@@@ -166,63 -166,6 +166,63 @@@ test_expect_success 
         test `git rev-parse --verify master:file2` \
            = `git rev-parse --verify verify--import-marks:copy-of-file2`'
  
 +test_tick
 +mt=$(git hash-object --stdin < /dev/null)
 +: >input.blob
 +: >marks.exp
 +: >tree.exp
 +
 +cat >input.commit <<EOF
 +commit refs/heads/verify--dump-marks
 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
 +data <<COMMIT
 +test the sparse array dumping routines with exponentially growing marks
 +COMMIT
 +EOF
 +
 +i=0
 +l=4
 +m=6
 +n=7
 +while test "$i" -lt 27; do
 +    cat >>input.blob <<EOF
 +blob
 +mark :$l
 +data 0
 +blob
 +mark :$m
 +data 0
 +blob
 +mark :$n
 +data 0
 +EOF
 +    echo "M 100644 :$l l$i" >>input.commit
 +    echo "M 100644 :$m m$i" >>input.commit
 +    echo "M 100644 :$n n$i" >>input.commit
 +
 +    echo ":$l $mt" >>marks.exp
 +    echo ":$m $mt" >>marks.exp
 +    echo ":$n $mt" >>marks.exp
 +
 +    printf "100644 blob $mt\tl$i\n" >>tree.exp
 +    printf "100644 blob $mt\tm$i\n" >>tree.exp
 +    printf "100644 blob $mt\tn$i\n" >>tree.exp
 +
 +    l=$(($l + $l))
 +    m=$(($m + $m))
 +    n=$(($l + $n))
 +
 +    i=$((1 + $i))
 +done
 +
 +sort tree.exp > tree.exp_s
 +
 +test_expect_success 'A: export marks with large values' '
 +      cat input.blob input.commit | git fast-import --export-marks=marks.large &&
 +      git ls-tree refs/heads/verify--dump-marks >tree.out &&
 +      test_cmp tree.exp_s tree.out &&
 +      test_cmp marks.exp marks.large'
 +
  ###
  ### series B
  ###
@@@ -853,6 -796,60 +853,60 @@@ test_expect_success 
        'git fast-import <input &&
         test `git rev-parse N2^{tree}` = `git rev-parse N3^{tree}`'
  
+ test_expect_success \
+       'N: copy directory by id' \
+       'cat >expect <<-\EOF &&
+       :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100   file2/newf      file3/newf
+       :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100   file2/oldf      file3/oldf
+       EOF
+        subdir=$(git rev-parse refs/heads/branch^0:file2) &&
+        cat >input <<-INPUT_END &&
+       commit refs/heads/N4
+       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+       data <<COMMIT
+       copy by tree hash
+       COMMIT
+       from refs/heads/branch^0
+       M 040000 $subdir file3
+       INPUT_END
+        git fast-import <input &&
+        git diff-tree -C --find-copies-harder -r N4^ N4 >actual &&
+        compare_diff_raw expect actual'
+ test_expect_success \
+       'N: modify copied tree' \
+       'cat >expect <<-\EOF &&
+       :100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 C100   newdir/interesting      file3/file5
+       :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100   file2/newf      file3/newf
+       :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100   file2/oldf      file3/oldf
+       EOF
+        subdir=$(git rev-parse refs/heads/branch^0:file2) &&
+        cat >input <<-INPUT_END &&
+       commit refs/heads/N5
+       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+       data <<COMMIT
+       copy by tree hash
+       COMMIT
+       from refs/heads/branch^0
+       M 040000 $subdir file3
+       commit refs/heads/N5
+       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+       data <<COMMIT
+       modify directory copy
+       COMMIT
+       M 644 inline file3/file5
+       data <<EOF
+       $file5_data
+       EOF
+       INPUT_END
+        git fast-import <input &&
+        git diff-tree -C --find-copies-harder -r N5^^ N5 >actual &&
+        compare_diff_raw expect actual'
  ###
  ### series O
  ###