Merge branch 'di/fast-import-deltified-tree'
* di/fast-import-deltified-tree: fast-import: prevent producing bad delta fast-import: add a test for tree delta base corruption
This commit is contained in:
commit
45792b64c1
@ -170,6 +170,11 @@ Format of STDIN stream:
|
|||||||
#define DEPTH_BITS 13
|
#define DEPTH_BITS 13
|
||||||
#define MAX_DEPTH ((1<<DEPTH_BITS)-1)
|
#define MAX_DEPTH ((1<<DEPTH_BITS)-1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We abuse the setuid bit on directories to mean "do not delta".
|
||||||
|
*/
|
||||||
|
#define NO_DELTA S_ISUID
|
||||||
|
|
||||||
struct object_entry {
|
struct object_entry {
|
||||||
struct pack_idx_entry idx;
|
struct pack_idx_entry idx;
|
||||||
struct object_entry *next;
|
struct object_entry *next;
|
||||||
@ -1416,7 +1421,8 @@ static void mktree(struct tree_content *t, int v, struct strbuf *b)
|
|||||||
struct tree_entry *e = t->entries[i];
|
struct tree_entry *e = t->entries[i];
|
||||||
if (!e->versions[v].mode)
|
if (!e->versions[v].mode)
|
||||||
continue;
|
continue;
|
||||||
strbuf_addf(b, "%o %s%c", (unsigned int)e->versions[v].mode,
|
strbuf_addf(b, "%o %s%c",
|
||||||
|
(unsigned int)(e->versions[v].mode & ~NO_DELTA),
|
||||||
e->name->str_dat, '\0');
|
e->name->str_dat, '\0');
|
||||||
strbuf_add(b, e->versions[v].sha1, 20);
|
strbuf_add(b, e->versions[v].sha1, 20);
|
||||||
}
|
}
|
||||||
@ -1427,7 +1433,7 @@ static void store_tree(struct tree_entry *root)
|
|||||||
struct tree_content *t = root->tree;
|
struct tree_content *t = root->tree;
|
||||||
unsigned int i, j, del;
|
unsigned int i, j, del;
|
||||||
struct last_object lo = { STRBUF_INIT, 0, 0, /* no_swap */ 1 };
|
struct last_object lo = { STRBUF_INIT, 0, 0, /* no_swap */ 1 };
|
||||||
struct object_entry *le;
|
struct object_entry *le = NULL;
|
||||||
|
|
||||||
if (!is_null_sha1(root->versions[1].sha1))
|
if (!is_null_sha1(root->versions[1].sha1))
|
||||||
return;
|
return;
|
||||||
@ -1437,6 +1443,7 @@ static void store_tree(struct tree_entry *root)
|
|||||||
store_tree(t->entries[i]);
|
store_tree(t->entries[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(root->versions[0].mode & NO_DELTA))
|
||||||
le = find_object(root->versions[0].sha1);
|
le = find_object(root->versions[0].sha1);
|
||||||
if (S_ISDIR(root->versions[0].mode) && le && le->pack_id == pack_id) {
|
if (S_ISDIR(root->versions[0].mode) && le && le->pack_id == pack_id) {
|
||||||
mktree(t, 0, &old_tree);
|
mktree(t, 0, &old_tree);
|
||||||
@ -1471,6 +1478,7 @@ static void tree_content_replace(
|
|||||||
{
|
{
|
||||||
if (!S_ISDIR(mode))
|
if (!S_ISDIR(mode))
|
||||||
die("Root cannot be a non-directory");
|
die("Root cannot be a non-directory");
|
||||||
|
hashclr(root->versions[0].sha1);
|
||||||
hashcpy(root->versions[1].sha1, sha1);
|
hashcpy(root->versions[1].sha1, sha1);
|
||||||
if (root->tree)
|
if (root->tree)
|
||||||
release_tree_content_recursive(root->tree);
|
release_tree_content_recursive(root->tree);
|
||||||
@ -1515,6 +1523,23 @@ static int tree_content_set(
|
|||||||
if (e->tree)
|
if (e->tree)
|
||||||
release_tree_content_recursive(e->tree);
|
release_tree_content_recursive(e->tree);
|
||||||
e->tree = subtree;
|
e->tree = subtree;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to leave e->versions[0].sha1 alone
|
||||||
|
* to avoid modifying the preimage tree used
|
||||||
|
* when writing out the parent directory.
|
||||||
|
* But after replacing the subdir with a
|
||||||
|
* completely different one, it's not a good
|
||||||
|
* delta base any more, and besides, we've
|
||||||
|
* thrown away the tree entries needed to
|
||||||
|
* make a delta against it.
|
||||||
|
*
|
||||||
|
* So let's just explicitly disable deltas
|
||||||
|
* for the subtree.
|
||||||
|
*/
|
||||||
|
if (S_ISDIR(e->versions[0].mode))
|
||||||
|
e->versions[0].mode |= NO_DELTA;
|
||||||
|
|
||||||
hashclr(root->versions[1].sha1);
|
hashclr(root->versions[1].sha1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -2938,7 +2963,7 @@ static void print_ls(int mode, const unsigned char *sha1, const char *path)
|
|||||||
/* mode SP type SP object_name TAB path LF */
|
/* mode SP type SP object_name TAB path LF */
|
||||||
strbuf_reset(&line);
|
strbuf_reset(&line);
|
||||||
strbuf_addf(&line, "%06o %s %s\t",
|
strbuf_addf(&line, "%06o %s %s\t",
|
||||||
mode, type, sha1_to_hex(sha1));
|
mode & ~NO_DELTA, type, sha1_to_hex(sha1));
|
||||||
quote_c_style(path, &line, NULL, 0);
|
quote_c_style(path, &line, NULL, 0);
|
||||||
strbuf_addch(&line, '\n');
|
strbuf_addch(&line, '\n');
|
||||||
}
|
}
|
||||||
|
@ -833,6 +833,47 @@ test_expect_success \
|
|||||||
git diff-tree --abbrev --raw L^ L >output &&
|
git diff-tree --abbrev --raw L^ L >output &&
|
||||||
test_cmp expect output'
|
test_cmp expect output'
|
||||||
|
|
||||||
|
cat >input <<INPUT_END
|
||||||
|
blob
|
||||||
|
mark :1
|
||||||
|
data <<EOF
|
||||||
|
the data
|
||||||
|
EOF
|
||||||
|
|
||||||
|
commit refs/heads/L2
|
||||||
|
committer C O Mitter <committer@example.com> 1112912473 -0700
|
||||||
|
data <<COMMIT
|
||||||
|
init L2
|
||||||
|
COMMIT
|
||||||
|
M 644 :1 a/b/c
|
||||||
|
M 644 :1 a/b/d
|
||||||
|
M 644 :1 a/e/f
|
||||||
|
|
||||||
|
commit refs/heads/L2
|
||||||
|
committer C O Mitter <committer@example.com> 1112912473 -0700
|
||||||
|
data <<COMMIT
|
||||||
|
update L2
|
||||||
|
COMMIT
|
||||||
|
C a g
|
||||||
|
C a/e g/b
|
||||||
|
M 644 :1 g/b/h
|
||||||
|
INPUT_END
|
||||||
|
|
||||||
|
cat <<EOF >expect
|
||||||
|
g/b/f
|
||||||
|
g/b/h
|
||||||
|
EOF
|
||||||
|
|
||||||
|
test_expect_success \
|
||||||
|
'L: nested tree copy does not corrupt deltas' \
|
||||||
|
'git fast-import <input &&
|
||||||
|
git ls-tree L2 g/b/ >tmp &&
|
||||||
|
cat tmp | cut -f 2 >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
git fsck `git rev-parse L2`'
|
||||||
|
|
||||||
|
git update-ref -d refs/heads/L2
|
||||||
|
|
||||||
###
|
###
|
||||||
### series M
|
### series M
|
||||||
###
|
###
|
||||||
|
Loading…
Reference in New Issue
Block a user