Merge branch 'jh/fast-import-notes'
* jh/fast-import-notes: fast-import: Fix incorrect fanout level when modifying existing notes refs t9301: Add 2nd testcase exposing bugs in fast-import's notes fanout handling t9301: Fix testcase covering up a bug in fast-import's notes fanout handling
This commit is contained in:
@ -2173,6 +2173,11 @@ static uintmax_t do_change_note_fanout(
|
|||||||
|
|
||||||
if (tmp_hex_sha1_len == 40 && !get_sha1_hex(hex_sha1, sha1)) {
|
if (tmp_hex_sha1_len == 40 && !get_sha1_hex(hex_sha1, sha1)) {
|
||||||
/* This is a note entry */
|
/* This is a note entry */
|
||||||
|
if (fanout == 0xff) {
|
||||||
|
/* Counting mode, no rename */
|
||||||
|
num_notes++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
construct_path_with_fanout(hex_sha1, fanout, realpath);
|
construct_path_with_fanout(hex_sha1, fanout, realpath);
|
||||||
if (!strcmp(fullpath, realpath)) {
|
if (!strcmp(fullpath, realpath)) {
|
||||||
/* Note entry is in correct location */
|
/* Note entry is in correct location */
|
||||||
@ -2379,7 +2384,7 @@ static void file_change_cr(struct branch *b, int rename)
|
|||||||
leaf.tree);
|
leaf.tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void note_change_n(struct branch *b, unsigned char old_fanout)
|
static void note_change_n(struct branch *b, unsigned char *old_fanout)
|
||||||
{
|
{
|
||||||
const char *p = command_buf.buf + 2;
|
const char *p = command_buf.buf + 2;
|
||||||
static struct strbuf uq = STRBUF_INIT;
|
static struct strbuf uq = STRBUF_INIT;
|
||||||
@ -2390,6 +2395,23 @@ static void note_change_n(struct branch *b, unsigned char old_fanout)
|
|||||||
uint16_t inline_data = 0;
|
uint16_t inline_data = 0;
|
||||||
unsigned char new_fanout;
|
unsigned char new_fanout;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When loading a branch, we don't traverse its tree to count the real
|
||||||
|
* number of notes (too expensive to do this for all non-note refs).
|
||||||
|
* This means that recently loaded notes refs might incorrectly have
|
||||||
|
* b->num_notes == 0, and consequently, old_fanout might be wrong.
|
||||||
|
*
|
||||||
|
* Fix this by traversing the tree and counting the number of notes
|
||||||
|
* when b->num_notes == 0. If the notes tree is truly empty, the
|
||||||
|
* calculation should not take long.
|
||||||
|
*/
|
||||||
|
if (b->num_notes == 0 && *old_fanout == 0) {
|
||||||
|
/* Invoke change_note_fanout() in "counting mode". */
|
||||||
|
b->num_notes = change_note_fanout(&b->branch_tree, 0xff);
|
||||||
|
*old_fanout = convert_num_notes_to_fanout(b->num_notes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now parse the notemodify command. */
|
||||||
/* <dataref> or 'inline' */
|
/* <dataref> or 'inline' */
|
||||||
if (*p == ':') {
|
if (*p == ':') {
|
||||||
char *x;
|
char *x;
|
||||||
@ -2450,7 +2472,7 @@ static void note_change_n(struct branch *b, unsigned char old_fanout)
|
|||||||
typename(type), command_buf.buf);
|
typename(type), command_buf.buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
construct_path_with_fanout(sha1_to_hex(commit_sha1), old_fanout, path);
|
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))
|
||||||
b->num_notes--;
|
b->num_notes--;
|
||||||
|
|
||||||
@ -2637,7 +2659,7 @@ static void parse_new_commit(void)
|
|||||||
else if (!prefixcmp(command_buf.buf, "C "))
|
else if (!prefixcmp(command_buf.buf, "C "))
|
||||||
file_change_cr(b, 0);
|
file_change_cr(b, 0);
|
||||||
else if (!prefixcmp(command_buf.buf, "N "))
|
else if (!prefixcmp(command_buf.buf, "N "))
|
||||||
note_change_n(b, prev_fanout);
|
note_change_n(b, &prev_fanout);
|
||||||
else if (!strcmp("deleteall", command_buf.buf))
|
else if (!strcmp("deleteall", command_buf.buf))
|
||||||
file_change_deleteall(b);
|
file_change_deleteall(b);
|
||||||
else if (!prefixcmp(command_buf.buf, "ls "))
|
else if (!prefixcmp(command_buf.buf, "ls "))
|
||||||
|
@ -505,9 +505,63 @@ test_expect_success 'verify that non-notes are untouched by a fanout change' '
|
|||||||
test_cmp expect_non-note3 actual
|
test_cmp expect_non-note3 actual
|
||||||
|
|
||||||
'
|
'
|
||||||
|
|
||||||
|
# Change the notes for the three top commits
|
||||||
|
test_tick
|
||||||
|
cat >input <<INPUT_END
|
||||||
|
commit refs/notes/many_notes
|
||||||
|
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
||||||
|
data <<COMMIT
|
||||||
|
changing notes for the top three commits
|
||||||
|
COMMIT
|
||||||
|
from refs/notes/many_notes^0
|
||||||
|
INPUT_END
|
||||||
|
|
||||||
|
rm expect
|
||||||
|
i=$num_commits
|
||||||
|
j=0
|
||||||
|
while test $j -lt 3
|
||||||
|
do
|
||||||
|
cat >>input <<INPUT_END
|
||||||
|
N inline refs/heads/many_commits~$j
|
||||||
|
data <<EOF
|
||||||
|
changed note for commit #$i
|
||||||
|
EOF
|
||||||
|
INPUT_END
|
||||||
|
cat >>expect <<EXPECT_END
|
||||||
|
commit #$i
|
||||||
|
changed note for commit #$i
|
||||||
|
EXPECT_END
|
||||||
|
i=$(($i - 1))
|
||||||
|
j=$(($j + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
test_expect_success 'change a few existing notes' '
|
||||||
|
|
||||||
|
git fast-import <input &&
|
||||||
|
GIT_NOTES_REF=refs/notes/many_notes git log -n3 refs/heads/many_commits |
|
||||||
|
grep "^ " > actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'verify that changing notes respect existing fanout' '
|
||||||
|
|
||||||
|
# None of the entries in the top-level notes tree should be a full SHA1
|
||||||
|
git ls-tree --name-only refs/notes/many_notes |
|
||||||
|
while read path
|
||||||
|
do
|
||||||
|
if test $(expr length "$path") -ge 40
|
||||||
|
then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
'
|
||||||
|
|
||||||
remaining_notes=10
|
remaining_notes=10
|
||||||
test_tick
|
test_tick
|
||||||
cat >>input <<INPUT_END
|
cat >input <<INPUT_END
|
||||||
commit refs/notes/many_notes
|
commit refs/notes/many_notes
|
||||||
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
||||||
data <<COMMIT
|
data <<COMMIT
|
||||||
@ -516,12 +570,11 @@ COMMIT
|
|||||||
from refs/notes/many_notes^0
|
from refs/notes/many_notes^0
|
||||||
INPUT_END
|
INPUT_END
|
||||||
|
|
||||||
i=$remaining_notes
|
i=$(($num_commits - $remaining_notes))
|
||||||
while test $i -lt $num_commits
|
for sha1 in $(git rev-list -n $i refs/heads/many_commits)
|
||||||
do
|
do
|
||||||
i=$(($i + 1))
|
|
||||||
cat >>input <<INPUT_END
|
cat >>input <<INPUT_END
|
||||||
N 0000000000000000000000000000000000000000 :$i
|
N 0000000000000000000000000000000000000000 $sha1
|
||||||
INPUT_END
|
INPUT_END
|
||||||
done
|
done
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user