Skip to content

Commit 0833cc2

Browse files
Vampiretnyblom
authored andcommitted
Do not dump added directories multiple times if svn-properties or empty-dirs is used
1 parent 9da781b commit 0833cc2

File tree

4 files changed

+184
-3
lines changed

4 files changed

+184
-3
lines changed

src/svn.cpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,7 @@ int SvnRevision::exportInternal(const char *key, const svn_fs_path_change2_t *ch
730730
QString previous;
731731
QString prevsvnprefix, prevrepository, preveffectiverepository, prevbranch, prevpath;
732732

733+
bool needRecursiveDump = false;
733734
if (path_from != NULL) {
734735
previous = QString::fromUtf8(path_from);
735736
if (wasDir(fs, rev_from, path_from, pool.data())) {
@@ -744,6 +745,7 @@ int SvnRevision::exportInternal(const char *key, const svn_fs_path_change2_t *ch
744745
} else {
745746
qWarning() << "WARN: SVN reports a \"copy from\" @" << revnum << "from" << path_from << "@" << rev_from << "but no matching rules found! Ignoring copy, treating as a modification";
746747
path_from = NULL;
748+
needRecursiveDump = true;
747749
}
748750
}
749751

@@ -878,8 +880,23 @@ int SvnRevision::exportInternal(const char *key, const svn_fs_path_change2_t *ch
878880
}
879881
}
880882

881-
txn->deleteFile(path);
882-
checkParentNotEmpty(pool, key, path, fs_root, txn);
883+
// if adding, modifying or replacing directory from empty path,
884+
// we only came here to handle empty-dirs and svn-ignore
885+
// do not redump the directory recursively, as all added files are
886+
// included as separate file changes anyway, otherwise the whole
887+
// directory tree is dumped multiple times
888+
//
889+
// needRecursiveDump is true if we come here because it actually was
890+
// a copy, but the source is not available in the target repo, so
891+
// we make a full dump instead here.
892+
bool dumpDirectory = needRecursiveDump
893+
|| !((change->change_kind == svn_fs_path_change_add || change->change_kind == svn_fs_path_change_modify || change->change_kind == svn_fs_path_change_replace)
894+
&& (path_from == NULL));
895+
896+
if (dumpDirectory) {
897+
txn->deleteFile(path);
898+
checkParentNotEmpty(pool, key, path, fs_root, txn);
899+
}
883900

884901
// Add GitIgnore with svn:ignore
885902
int ignoreSet = false;
@@ -902,7 +919,9 @@ int SvnRevision::exportInternal(const char *key, const svn_fs_path_change2_t *ch
902919
}
903920
}
904921

905-
recursiveDumpDir(txn, fs, fs_root, key, path, pool, revnum, rule, matchRules, ruledebug, ignoreSet);
922+
if (dumpDirectory) {
923+
recursiveDumpDir(txn, fs, fs_root, key, path, pool, revnum, rule, matchRules, ruledebug, ignoreSet);
924+
}
906925
}
907926

908927
if (rule.annotate) {

test/copy-directories.bats

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
load 'common'
2+
3+
@test 'copying a directory with source not in target repo should dump full directory' {
4+
svn mkdir --parents project-a/dir-a
5+
touch project-a/dir-a/file-a
6+
svn add project-a/dir-a/file-a
7+
svn commit -m 'add project-a/dir-a/file-a'
8+
svn mkdir --parents project-b
9+
svn commit -m 'add project-b'
10+
svn cp project-a/dir-a project-b
11+
svn commit -m 'copy project-a/dir-a to project-b'
12+
13+
cd "$TEST_TEMP_DIR"
14+
svn2git "$SVN_REPO" --debug-rules --rules <(echo "
15+
create repository git-repo
16+
end repository
17+
18+
match /project-b/
19+
repository git-repo
20+
branch master
21+
end match
22+
23+
match /project-a/
24+
end match
25+
")
26+
27+
assert git -C git-repo show master:dir-a/file-a
28+
}

test/empty-dirs.bats

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,45 @@ load 'common'
171171

172172
assert_equal "$(git -C git-repo show master:dir-a/.gitignore)" 'ignore-a'
173173
}
174+
175+
@test 'empty-dirs parameter should not cause added directories to be dumped multiple times' {
176+
svn mkdir dir-a
177+
echo content-a >dir-a/file-a
178+
svn add dir-a/file-a
179+
svn commit -m 'add dir-a/file-a'
180+
181+
cd "$TEST_TEMP_DIR"
182+
svn2git "$SVN_REPO" --empty-dirs --create-dump --rules <(echo "
183+
create repository git-repo
184+
end repository
185+
186+
match /
187+
repository git-repo
188+
branch master
189+
end match
190+
")
191+
192+
assert [ "$(grep -c '^M .* dir-a/file-a$' git-repo.fi)" -eq 1 ]
193+
}
194+
195+
@test 'empty-dirs parameter should not cause added directories to be dumped multiple times (nested)' {
196+
svn mkdir project-a
197+
cd project-a
198+
svn mkdir dir-a
199+
echo content-a >dir-a/file-a
200+
svn add dir-a/file-a
201+
svn commit -m 'add dir-a/file-a'
202+
203+
cd "$TEST_TEMP_DIR"
204+
svn2git "$SVN_REPO" --empty-dirs --create-dump --rules <(echo "
205+
create repository git-repo
206+
end repository
207+
208+
match /project-a/
209+
repository git-repo
210+
branch master
211+
end match
212+
")
213+
214+
assert [ "$(grep -c '^M .* dir-a/file-a$' git-repo.fi)" -eq 1 ]
215+
}

test/svn-ignore.bats

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,95 @@ load 'common'
129129
EOF
130130
)"
131131
}
132+
133+
@test 'svn-ignore parameter should not cause added directories to be dumped multiple times' {
134+
svn mkdir dir-a
135+
echo content-a >dir-a/file-a
136+
svn add dir-a/file-a
137+
svn commit -m 'add dir-a/file-a'
138+
139+
cd "$TEST_TEMP_DIR"
140+
svn2git "$SVN_REPO" --svn-ignore --create-dump --rules <(echo "
141+
create repository git-repo
142+
end repository
143+
144+
match /
145+
repository git-repo
146+
branch master
147+
end match
148+
")
149+
150+
assert [ "$(grep -c '^M .* dir-a/file-a$' git-repo.fi)" -eq 1 ]
151+
}
152+
153+
@test 'svn-ignore parameter should not cause added directories to be dumped multiple times (nested)' {
154+
svn mkdir project-a
155+
cd project-a
156+
svn mkdir dir-a
157+
echo content-a >dir-a/file-a
158+
svn add dir-a/file-a
159+
svn commit -m 'add dir-a/file-a'
160+
161+
cd "$TEST_TEMP_DIR"
162+
svn2git "$SVN_REPO" --svn-ignore --create-dump --rules <(echo "
163+
create repository git-repo
164+
end repository
165+
166+
match /project-a/
167+
repository git-repo
168+
branch master
169+
end match
170+
")
171+
172+
assert [ "$(grep -c '^M .* dir-a/file-a$' git-repo.fi)" -eq 1 ]
173+
}
174+
175+
@test 'svn-ignore translation should not delete unrelated files' {
176+
svn mkdir dir-a
177+
echo content-a >dir-a/file-a
178+
svn add dir-a/file-a
179+
svn commit -m 'add dir-a/file-a'
180+
svn update
181+
svn propset svn:ignore 'ignore-a' dir-a
182+
svn commit -m 'ignore ignore-a on dir-a'
183+
184+
cd "$TEST_TEMP_DIR"
185+
svn2git "$SVN_REPO" --svn-ignore --rules <(echo "
186+
create repository git-repo
187+
end repository
188+
189+
match /
190+
repository git-repo
191+
branch master
192+
end match
193+
")
194+
195+
assert_equal "$(git -C git-repo show master:dir-a/.gitignore)" '/ignore-a'
196+
assert git -C git-repo show master:dir-a/file-a
197+
}
198+
199+
@test 'svn-ignore translation should not delete unrelated files (nested)' {
200+
svn mkdir project-a
201+
cd project-a
202+
svn mkdir dir-a
203+
echo content-a >dir-a/file-a
204+
svn add dir-a/file-a
205+
svn commit -m 'add dir-a/file-a'
206+
svn update
207+
svn propset svn:ignore 'ignore-a' dir-a
208+
svn commit -m 'ignore ignore-a on dir-a'
209+
210+
cd "$TEST_TEMP_DIR"
211+
svn2git "$SVN_REPO" --svn-ignore --rules <(echo "
212+
create repository git-repo
213+
end repository
214+
215+
match /project-a/
216+
repository git-repo
217+
branch master
218+
end match
219+
")
220+
221+
assert_equal "$(git -C git-repo show master:dir-a/.gitignore)" '/ignore-a'
222+
assert git -C git-repo show master:dir-a/file-a
223+
}

0 commit comments

Comments
 (0)