Merge branch 'jk/fast-import-empty-ls'
* jk/fast-import-empty-ls: fast-import: allow moving the root tree fast-import: allow ls or filecopy of the root tree fast-import: set valid mode on root tree in "ls" t9300: document fast-import empty path issuesmaint
						commit
						7e39472020
					
				|  | @ -1568,7 +1568,8 @@ static int tree_content_set( | |||
| static int tree_content_remove( | ||||
| 	struct tree_entry *root, | ||||
| 	const char *p, | ||||
| 	struct tree_entry *backup_leaf) | ||||
| 	struct tree_entry *backup_leaf, | ||||
| 	int allow_root) | ||||
| { | ||||
| 	struct tree_content *t; | ||||
| 	const char *slash1; | ||||
|  | @ -1583,6 +1584,12 @@ static int tree_content_remove( | |||
|  | ||||
| 	if (!root->tree) | ||||
| 		load_tree(root); | ||||
|  | ||||
| 	if (!*p && allow_root) { | ||||
| 		e = root; | ||||
| 		goto del_entry; | ||||
| 	} | ||||
|  | ||||
| 	t = root->tree; | ||||
| 	for (i = 0; i < t->entry_count; i++) { | ||||
| 		e = t->entries[i]; | ||||
|  | @ -1599,7 +1606,7 @@ static int tree_content_remove( | |||
| 				goto del_entry; | ||||
| 			if (!e->tree) | ||||
| 				load_tree(e); | ||||
| 			if (tree_content_remove(e, slash1 + 1, backup_leaf)) { | ||||
| 			if (tree_content_remove(e, slash1 + 1, backup_leaf, 0)) { | ||||
| 				for (n = 0; n < e->tree->entry_count; n++) { | ||||
| 					if (e->tree->entries[n]->versions[1].mode) { | ||||
| 						hashclr(root->versions[1].sha1); | ||||
|  | @ -1629,7 +1636,8 @@ del_entry: | |||
| static int tree_content_get( | ||||
| 	struct tree_entry *root, | ||||
| 	const char *p, | ||||
| 	struct tree_entry *leaf) | ||||
| 	struct tree_entry *leaf, | ||||
| 	int allow_root) | ||||
| { | ||||
| 	struct tree_content *t; | ||||
| 	const char *slash1; | ||||
|  | @ -1641,31 +1649,39 @@ static int tree_content_get( | |||
| 		n = slash1 - p; | ||||
| 	else | ||||
| 		n = strlen(p); | ||||
| 	if (!n) | ||||
| 	if (!n && !allow_root) | ||||
| 		die("Empty path component found in input"); | ||||
|  | ||||
| 	if (!root->tree) | ||||
| 		load_tree(root); | ||||
|  | ||||
| 	if (!n) { | ||||
| 		e = root; | ||||
| 		goto found_entry; | ||||
| 	} | ||||
|  | ||||
| 	t = root->tree; | ||||
| 	for (i = 0; i < t->entry_count; i++) { | ||||
| 		e = t->entries[i]; | ||||
| 		if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) { | ||||
| 			if (!slash1) { | ||||
| 			if (!slash1) | ||||
| 				goto found_entry; | ||||
| 			if (!S_ISDIR(e->versions[1].mode)) | ||||
| 				return 0; | ||||
| 			if (!e->tree) | ||||
| 				load_tree(e); | ||||
| 			return tree_content_get(e, slash1 + 1, leaf, 0); | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
|  | ||||
| found_entry: | ||||
| 	memcpy(leaf, e, sizeof(*leaf)); | ||||
| 	if (e->tree && is_null_sha1(e->versions[1].sha1)) | ||||
| 		leaf->tree = dup_tree_content(e->tree); | ||||
| 	else | ||||
| 		leaf->tree = NULL; | ||||
| 	return 1; | ||||
| 			} | ||||
| 			if (!S_ISDIR(e->versions[1].mode)) | ||||
| 				return 0; | ||||
| 			if (!e->tree) | ||||
| 				load_tree(e); | ||||
| 			return tree_content_get(e, slash1 + 1, leaf); | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int update_branch(struct branch *b) | ||||
|  | @ -2179,7 +2195,7 @@ static uintmax_t do_change_note_fanout( | |||
| 			} | ||||
|  | ||||
| 			/* Rename fullpath to realpath */ | ||||
| 			if (!tree_content_remove(orig_root, fullpath, &leaf)) | ||||
| 			if (!tree_content_remove(orig_root, fullpath, &leaf, 0)) | ||||
| 				die("Failed to remove path %s", fullpath); | ||||
| 			tree_content_set(orig_root, realpath, | ||||
| 				leaf.versions[1].sha1, | ||||
|  | @ -2314,7 +2330,7 @@ static void file_change_m(struct branch *b) | |||
|  | ||||
| 	/* Git does not track empty, non-toplevel directories. */ | ||||
| 	if (S_ISDIR(mode) && !memcmp(sha1, EMPTY_TREE_SHA1_BIN, 20) && *p) { | ||||
| 		tree_content_remove(&b->branch_tree, p, NULL); | ||||
| 		tree_content_remove(&b->branch_tree, p, NULL, 0); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
|  | @ -2375,7 +2391,7 @@ static void file_change_d(struct branch *b) | |||
| 			die("Garbage after path in: %s", command_buf.buf); | ||||
| 		p = uq.buf; | ||||
| 	} | ||||
| 	tree_content_remove(&b->branch_tree, p, NULL); | ||||
| 	tree_content_remove(&b->branch_tree, p, NULL, 1); | ||||
| } | ||||
|  | ||||
| static void file_change_cr(struct branch *b, int rename) | ||||
|  | @ -2413,9 +2429,9 @@ static void file_change_cr(struct branch *b, int rename) | |||
|  | ||||
| 	memset(&leaf, 0, sizeof(leaf)); | ||||
| 	if (rename) | ||||
| 		tree_content_remove(&b->branch_tree, s, &leaf); | ||||
| 		tree_content_remove(&b->branch_tree, s, &leaf, 1); | ||||
| 	else | ||||
| 		tree_content_get(&b->branch_tree, s, &leaf); | ||||
| 		tree_content_get(&b->branch_tree, s, &leaf, 1); | ||||
| 	if (!leaf.versions[1].mode) | ||||
| 		die("Path %s not in branch", s); | ||||
| 	if (!*d) {	/* C "path/to/subdir" "" */ | ||||
|  | @ -2521,7 +2537,7 @@ static void note_change_n(struct branch *b, unsigned char *old_fanout) | |||
| 	} | ||||
|  | ||||
| 	construct_path_with_fanout(sha1_to_hex(commit_sha1), *old_fanout, path); | ||||
| 	if (tree_content_remove(&b->branch_tree, path, NULL)) | ||||
| 	if (tree_content_remove(&b->branch_tree, path, NULL, 0)) | ||||
| 		b->num_notes--; | ||||
|  | ||||
| 	if (is_null_sha1(sha1)) | ||||
|  | @ -3051,6 +3067,8 @@ static void parse_ls(struct branch *b) | |||
| 		struct object_entry *e = parse_treeish_dataref(&p); | ||||
| 		root = new_tree_entry(); | ||||
| 		hashcpy(root->versions[1].sha1, e->idx.sha1); | ||||
| 		if (!is_null_sha1(root->versions[1].sha1)) | ||||
| 			root->versions[1].mode = S_IFDIR; | ||||
| 		load_tree(root); | ||||
| 		if (*p++ != ' ') | ||||
| 			die("Missing space after tree-ish: %s", command_buf.buf); | ||||
|  | @ -3065,7 +3083,7 @@ static void parse_ls(struct branch *b) | |||
| 			die("Garbage after path in: %s", command_buf.buf); | ||||
| 		p = uq.buf; | ||||
| 	} | ||||
| 	tree_content_get(root, p, &leaf); | ||||
| 	tree_content_get(root, p, &leaf, 1); | ||||
| 	/* | ||||
| 	 * A directory in preparation would have a sha1 of zero | ||||
| 	 * until it is saved.  Save, for simplicity. | ||||
|  |  | |||
|  | @ -1031,6 +1031,32 @@ test_expect_success \ | |||
| 	 git diff-tree -M -r M3^ M3 >actual && | ||||
| 	 compare_diff_raw expect actual' | ||||
|  | ||||
| cat >input <<INPUT_END | ||||
| commit refs/heads/M4 | ||||
| committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE | ||||
| data <<COMMIT | ||||
| rename root | ||||
| COMMIT | ||||
|  | ||||
| from refs/heads/M2^0 | ||||
| R "" sub | ||||
|  | ||||
| INPUT_END | ||||
|  | ||||
| cat >expect <<EOF | ||||
| :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 R100	file2/oldf	sub/file2/oldf | ||||
| :100755 100755 85df50785d62d3b05ab03d9cbf7e4a0b49449730 85df50785d62d3b05ab03d9cbf7e4a0b49449730 R100	file4	sub/file4 | ||||
| :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc R100	i/am/new/to/you	sub/i/am/new/to/you | ||||
| :100755 100755 e74b7d465e52746be2b4bae983670711e6e66657 e74b7d465e52746be2b4bae983670711e6e66657 R100	newdir/exec.sh	sub/newdir/exec.sh | ||||
| :100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 R100	newdir/interesting	sub/newdir/interesting | ||||
| EOF | ||||
| test_expect_success \ | ||||
| 	'M: rename root to subdirectory' \ | ||||
| 	'git fast-import <input && | ||||
| 	 git diff-tree -M -r M4^ M4 >actual && | ||||
| 	 cat actual && | ||||
| 	 compare_diff_raw expect actual' | ||||
|  | ||||
| ### | ||||
| ### series N | ||||
| ### | ||||
|  | @ -1227,6 +1253,29 @@ test_expect_success \ | |||
| 	 git diff-tree -C --find-copies-harder -r N4 N6 >actual && | ||||
| 	 compare_diff_raw expect actual' | ||||
|  | ||||
| test_expect_success \ | ||||
| 	'N: copy root by path' \ | ||||
| 	'cat >expect <<-\EOF && | ||||
| 	:100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100	file2/newf	oldroot/file2/newf | ||||
| 	:100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100	file2/oldf	oldroot/file2/oldf | ||||
| 	:100755 100755 85df50785d62d3b05ab03d9cbf7e4a0b49449730 85df50785d62d3b05ab03d9cbf7e4a0b49449730 C100	file4	oldroot/file4 | ||||
| 	:100755 100755 e74b7d465e52746be2b4bae983670711e6e66657 e74b7d465e52746be2b4bae983670711e6e66657 C100	newdir/exec.sh	oldroot/newdir/exec.sh | ||||
| 	:100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 C100	newdir/interesting	oldroot/newdir/interesting | ||||
| 	EOF | ||||
| 	 cat >input <<-INPUT_END && | ||||
| 	commit refs/heads/N-copy-root-path | ||||
| 	committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE | ||||
| 	data <<COMMIT | ||||
| 	copy root directory by (empty) path | ||||
| 	COMMIT | ||||
|  | ||||
| 	from refs/heads/branch^0 | ||||
| 	C "" oldroot | ||||
| 	INPUT_END | ||||
| 	 git fast-import <input && | ||||
| 	 git diff-tree -C --find-copies-harder -r branch N-copy-root-path >actual && | ||||
| 	 compare_diff_raw expect actual' | ||||
|  | ||||
| test_expect_success \ | ||||
| 	'N: delete directory by copying' \ | ||||
| 	'cat >expect <<-\EOF && | ||||
|  | @ -2934,4 +2983,20 @@ test_expect_success 'S: ls with garbage after sha1 must fail' ' | |||
| 	test_i18ngrep "space after tree-ish" err | ||||
| ' | ||||
|  | ||||
| ### | ||||
| ### series T (ls) | ||||
| ### | ||||
| # Setup is carried over from series S. | ||||
|  | ||||
| test_expect_success 'T: ls root tree' ' | ||||
| 	sed -e "s/Z\$//" >expect <<-EOF && | ||||
| 	040000 tree $(git rev-parse S^{tree})	Z | ||||
| 	EOF | ||||
| 	sha1=$(git rev-parse --verify S) && | ||||
| 	git fast-import --import-marks=marks <<-EOF >actual && | ||||
| 	ls $sha1 "" | ||||
| 	EOF | ||||
| 	test_cmp expect actual | ||||
| ' | ||||
|  | ||||
| test_done | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Junio C Hamano
						Junio C Hamano