Skip to content

Commit 334fba6

Browse files
jrngitster
authored andcommitted
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 <[email protected]> Cc: Sverre Rabbelier <[email protected]> Signed-off-by: Jonathan Nieder <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 45e9a82 commit 334fba6

File tree

3 files changed

+75
-11
lines changed

3 files changed

+75
-11
lines changed

Documentation/git-fast-import.txt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -482,9 +482,11 @@ External data format::
482482
'M' SP <mode> SP <dataref> SP <path> LF
483483
....
484484
+
485-
Here `<dataref>` can be either a mark reference (`:<idnum>`)
485+
Here usually `<dataref>` must be either a mark reference (`:<idnum>`)
486486
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`.
488490

489491
Inline data format::
490492
The data content for the file has not been supplied yet.
@@ -509,6 +511,8 @@ in octal. Git only supports the following modes:
509511
* `160000`: A gitlink, SHA-1 of the object refers to a commit in
510512
another repository. Git links can only be specified by SHA or through
511513
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`.
512516

513517
In both formats `<path>` is the complete path of the file to be added
514518
(if not already existing) or modified (if already existing).

fast-import.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2131,6 +2131,7 @@ static void file_change_m(struct branch *b)
21312131
case S_IFREG | 0644:
21322132
case S_IFREG | 0755:
21332133
case S_IFLNK:
2134+
case S_IFDIR:
21342135
case S_IFGITLINK:
21352136
/* ok */
21362137
break;
@@ -2176,23 +2177,28 @@ static void file_change_m(struct branch *b)
21762177
* another repository.
21772178
*/
21782179
} else if (inline_data) {
2180+
if (S_ISDIR(mode))
2181+
die("Directories cannot be specified 'inline': %s",
2182+
command_buf.buf);
21792183
if (p != uq.buf) {
21802184
strbuf_addstr(&uq, p);
21812185
p = uq.buf;
21822186
}
21832187
read_next_command();
21842188
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);
21892189
} 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);
21912194
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);
21962202
}
21972203

21982204
tree_content_set(&b->branch_tree, p, sha1, mode, NULL);

t/t9300-fast-import.sh

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,60 @@ test_expect_success \
796796
'git fast-import <input &&
797797
test `git rev-parse N2^{tree}` = `git rev-parse N3^{tree}`'
798798

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+
799853
###
800854
### series O
801855
###

0 commit comments

Comments
 (0)