@matheusbsbs / matheus-bagliano / commits / 334fba656b
Fork 0

Teach fast-import to import subtrees named by tree id

To simulate the svn cp command, it would be very useful to be replace an arbitrary file in the current revision by an arbitrary directory from a previous one. Modify the filemodify command to allow that: M 040000 <tree id> pathname This would be most useful in combination with a facility to print the commit ids for new revisions as they are written. Cc: Shawn O. Pearce <spearce@spearce.org> Cc: Sverre Rabbelier <srabbelier@gmail.com> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jonathan Nieder committed Jun 30, 2010 at 22:18 UTC 334fba656b50c92345586970bc6b100a449e1fc5
3 files changed +75 -11
Documentation/git-fast-import.txt
+6 -2
@@ -482,9 +482,11 @@ External data format::
482 'M' SP <mode> SP <dataref> SP <path> LF
483 ....
484 +
485 -Here `<dataref>` can be either a mark reference (`:<idnum>`)
485 +Here usually `<dataref>` must be either a mark reference (`:<idnum>`)
486 set by a prior `blob` command, or a full 40-byte SHA-1 of an
487 -existing Git blob object.
487 +existing Git blob object. If `<mode>` is `040000`` then
488 +`<dataref>` must be the full 40-byte SHA-1 of an existing
489 +Git tree object or a mark reference set with `--import-marks`.
490
491 Inline data format::
492 The data content for the file has not been supplied yet.
@@ -509,6 +511,8 @@ in octal. Git only supports the following modes:
511 * `160000`: A gitlink, SHA-1 of the object refers to a commit in
512 another repository. Git links can only be specified by SHA or through
513 a commit mark. They are used to implement submodules.
514 +* `040000`: A subdirectory. Subdirectories can only be specified by
515 + SHA or through a tree mark set with `--import-marks`.
516
517 In both formats `<path>` is the complete path of the file to be added
518 (if not already existing) or modified (if already existing).
fast-import.c
+15 -9
@@ -2131,6 +2131,7 @@ static void file_change_m(struct branch *b)
2131 case S_IFREG | 0644:
2132 case S_IFREG | 0755:
2133 case S_IFLNK:
2134 + case S_IFDIR:
2135 case S_IFGITLINK:
2136 /* ok */
2137 break;
@@ -2176,23 +2177,28 @@ static void file_change_m(struct branch *b)
2177 * another repository.
2178 */
2179 } else if (inline_data) {
2180 + if (S_ISDIR(mode))
2181 + die("Directories cannot be specified 'inline': %s",
2182 + command_buf.buf);
2183 if (p != uq.buf) {
2184 strbuf_addstr(&uq, p);
2185 p = uq.buf;
2186 }
2187 read_next_command();
2188 parse_and_store_blob(&last_blob, sha1, 0);
2185 - } else if (oe) {
2186 - if (oe->type != OBJ_BLOB)
2187 - die("Not a blob (actually a %s): %s",
2188 - typename(oe->type), command_buf.buf);
2189 } else {
2190 - enum object_type type = sha1_object_info(sha1, NULL);
2190 + enum object_type expected = S_ISDIR(mode) ?
2191 + OBJ_TREE: OBJ_BLOB;
2192 + enum object_type type = oe ? oe->type :
2193 + sha1_object_info(sha1, NULL);
2194 if (type < 0)
2192 - die("Blob not found: %s", command_buf.buf);
2193 - if (type != OBJ_BLOB)
2194 - die("Not a blob (actually a %s): %s",
2195 - typename(type), command_buf.buf);
2195 + die("%s not found: %s",
2196 + S_ISDIR(mode) ? "Tree" : "Blob",
2197 + command_buf.buf);
2198 + if (type != expected)
2199 + die("Not a %s (actually a %s): %s",
2200 + typename(expected), typename(type),
2201 + command_buf.buf);
2202 }
2203
2204 tree_content_set(&b->branch_tree, p, sha1, mode, NULL);
t/t9300-fast-import.sh
+54
@@ -796,6 +796,60 @@ test_expect_success \
796 'git fast-import <input &&
797 test `git rev-parse N2^{tree}` = `git rev-parse N3^{tree}`'
798
799 +test_expect_success \
800 + 'N: copy directory by id' \
801 + 'cat >expect <<-\EOF &&
802 + :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf file3/newf
803 + :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100 file2/oldf file3/oldf
804 + EOF
805 + subdir=$(git rev-parse refs/heads/branch^0:file2) &&
806 + cat >input <<-INPUT_END &&
807 + commit refs/heads/N4
808 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
809 + data <<COMMIT
810 + copy by tree hash
811 + COMMIT
812 +
813 + from refs/heads/branch^0
814 + M 040000 $subdir file3
815 + INPUT_END
816 + git fast-import <input &&
817 + git diff-tree -C --find-copies-harder -r N4^ N4 >actual &&
818 + compare_diff_raw expect actual'
819 +
820 +test_expect_success \
821 + 'N: modify copied tree' \
822 + 'cat >expect <<-\EOF &&
823 + :100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 C100 newdir/interesting file3/file5
824 + :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100 file2/newf file3/newf
825 + :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100 file2/oldf file3/oldf
826 + EOF
827 + subdir=$(git rev-parse refs/heads/branch^0:file2) &&
828 + cat >input <<-INPUT_END &&
829 + commit refs/heads/N5
830 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
831 + data <<COMMIT
832 + copy by tree hash
833 + COMMIT
834 +
835 + from refs/heads/branch^0
836 + M 040000 $subdir file3
837 +
838 + commit refs/heads/N5
839 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
840 + data <<COMMIT
841 + modify directory copy
842 + COMMIT
843 +
844 + M 644 inline file3/file5
845 + data <<EOF
846 + $file5_data
847 + EOF
848 + INPUT_END
849 + git fast-import <input &&
850 + git diff-tree -C --find-copies-harder -r N5^^ N5 >actual &&
851 + compare_diff_raw expect actual'
852 +
853 ###
854 ### series O
855 ###