Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package svn2git for openSUSE:Factory checked in at 2026-05-05 15:15:16 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/svn2git (Old) and /work/SRC/openSUSE:Factory/.svn2git.new.30200 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "svn2git" Tue May 5 15:15:16 2026 rev:6 rq:1350749 version:1.0.20 Changes: -------- --- /work/SRC/openSUSE:Factory/svn2git/svn2git.changes 2023-07-17 19:24:04.870013658 +0200 +++ /work/SRC/openSUSE:Factory/.svn2git.new.30200/svn2git.changes 2026-05-05 15:16:34.410134060 +0200 @@ -1,0 +2,20 @@ +Mon May 4 15:38:13 UTC 2026 - Dirk Müller <[email protected]> + +- update to 1.0.20: + * Support both Qt 5 and Qt 6 at the same time (fixes #163) + * **Full Changelog**: https://github.com/svn-all-fast- + export/svn2git/compare/1.0.19...1.0.20 +- update to 1.0.19: + * Fail test execution if there were duplicate test names + * Fix some typos in the README and add a pointer to where + annotated tags + * Support git default branch name + * Error out if error happens in fast import process + * Do not warn the user if default branch does not exist + * Notes on end slash requirement + * Revert "Error out if error happens in fast import process" + * Add ubuntu22.04 build + * Update Dockerfile and CI it + * Revive CI + +------------------------------------------------------------------- Old: ---- svn2git-1.0.18.tar.gz New: ---- svn2git-1.0.20.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ svn2git.spec ++++++ --- /var/tmp/diff_new_pack.NqE8fa/_old 2026-05-05 15:16:35.018159287 +0200 +++ /var/tmp/diff_new_pack.NqE8fa/_new 2026-05-05 15:16:35.018159287 +0200 @@ -17,7 +17,7 @@ Name: svn2git -Version: 1.0.18 +Version: 1.0.20 Release: 0 Summary: Importer for one time conversion from SVN to Git License: GPL-3.0-only @@ -26,7 +26,8 @@ Source0: https://github.com/svn-all-fast-export/%{name}/archive/%{version}.tar.gz#/%{name}-%{version}.tar.gz BuildRequires: pkgconfig BuildRequires: subversion-devel -BuildRequires: pkgconfig(Qt5Core) +BuildRequires: pkgconfig(Qt6Core) +BuildRequires: pkgconfig(Qt6Core5Compat) Requires: git Requires: subversion @@ -38,7 +39,7 @@ %setup -q %build -%qmake5 -o Makefile fast-export2.pro CONFIG+=RELEASE +%qmake6 -o Makefile fast-export2.pro CONFIG+=RELEASE %make_jobs %install ++++++ svn2git-1.0.18.tar.gz -> svn2git-1.0.20.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/svn2git-1.0.18/.github/workflows/build.yaml new/svn2git-1.0.20/.github/workflows/build.yaml --- old/svn2git-1.0.18/.github/workflows/build.yaml 2020-04-20 08:58:53.000000000 +0200 +++ new/svn2git-1.0.20/.github/workflows/build.yaml 2025-04-28 14:27:55.000000000 +0200 @@ -14,16 +14,44 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -name: Build (Linux, Ubuntu 18.04) +name: Build (Linux, Ubuntu) on: -- pull_request -- push + pull_request: + push: + schedule: + - cron: '0 2 * * 5' # Every Friday at 2am + workflow_dispatch: + +# Reduce permissions to minimum for security +permissions: + contents: read jobs: build: - name: Build (Linux, Ubuntu 18.04) - runs-on: ubuntu-18.04 + strategy: + fail-fast: false + matrix: + include: + - runs-on: ubuntu-24.04 + qt_major: 6 + qt_qmake: qmake6 + qt_packages: qmake6 qt6-base-dev qt6-5compat-dev + - runs-on: ubuntu-24.04 + qt_major: 5 + qt_qmake: qmake + qt_packages: qt5-qmake qtbase5-dev + - runs-on: ubuntu-22.04 + qt_major: 6 + qt_qmake: qmake6 + qt_packages: qmake6 qt6-base-dev libqt6core5compat6-dev + - runs-on: ubuntu-22.04 + qt_major: 5 + qt_qmake: qmake + qt_packages: qt5-qmake qtbase5-dev + + name: Build (Linux, ${{ matrix.runs-on }}, Qt ${{ matrix.qt_major }}) + runs-on: ${{ matrix.runs-on }} steps: - name: 'Install build dependencies' run: |- @@ -33,17 +61,19 @@ build-essential \ libapr1-dev \ libsvn-dev \ - qt5-default \ - qtbase5-dev + ${{ matrix.qt_packages }} \ + subversion - name: 'Checkout Git branch' - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: submodules: true - name: 'Configure' + env: + QMAKE: ${{ matrix.qt_qmake }} run: |- - qmake + ${QMAKE} - name: 'Build' run: |- @@ -58,3 +88,16 @@ set -e make INSTALL_ROOT="${PWD}"/ROOT install find ROOT | sort + + docker: + name: Check Dockerfile + runs-on: ubuntu-latest + steps: + - name: 'Checkout Git branch' + uses: actions/checkout@v3 + with: + submodules: true + + - name: 'Build' + run: |- + docker build . diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/svn2git-1.0.18/Dockerfile new/svn2git-1.0.20/Dockerfile --- old/svn2git-1.0.18/Dockerfile 2020-04-20 08:58:53.000000000 +0200 +++ new/svn2git-1.0.20/Dockerfile 2025-04-28 14:27:55.000000000 +0200 @@ -1,14 +1,24 @@ -FROM debian:8.11 +FROM ubuntu:22.04 -RUN apt update && apt install -y \ - make g++ libapr1-dev libsvn-dev libqt4-dev \ - git subversion \ - && rm -rf /var/lib/apt/lists/* \ - && mkdir /usr/local/svn2git +# Change locale to let svn handle international characters +ENV LC_ALL C.UTF-8 -ADD . /usr/local/svn2git +# Install dependencies +RUN apt-get update && apt-get install --yes --no-install-recommends \ + build-essential \ + libapr1-dev \ + libsvn-dev \ + qt5-qmake \ + qtbase5-dev \ + git \ + subversion \ + && rm -rf /var/lib/apt/lists/* +# Build the binary +RUN mkdir /usr/local/svn2git +ADD . /usr/local/svn2git RUN cd /usr/local/svn2git && qmake && make +# Docker interface WORKDIR /workdir CMD /usr/local/svn2git/svn-all-fast-export diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/svn2git-1.0.18/README.md new/svn2git-1.0.20/README.md --- old/svn2git-1.0.18/README.md 2020-04-20 08:58:53.000000000 +0200 +++ new/svn2git-1.0.20/README.md 2025-04-28 14:27:55.000000000 +0200 @@ -22,7 +22,7 @@ Sample usage with input mounted in /tmp and output produced in /workdir: ``` docker build -t svn2git . -docker run --rm -it -v `pwd`/workdir:/workdir -v /var/lib/svn/project1:/tmp/svn -v `pwd`/conf:/tmp/conf svn2git /usr/local/svn2git/svn-all-fast-export --identity-map /tmp/conf/project1.authors --rules /tmp/conf/project1.rules --add-metadata --svn-branches --debug-rules --svn-ignore --empty-dirs /tmp/svn/ +docker run --rm -it -v `pwd`/workdir:/workdir -v /var/lib/svn/project1:/tmp/svn -v `pwd`/conf:/tmp/conf svn2git /usr/local/svn2git/svn-all-fast-export --identity-map /tmp/conf/project1.authors --rules /tmp/conf/project1.rules --add-metadata --svn-branches --debug-rules --svn-ignore --empty-dirs /tmp/svn/ ``` Building the tool @@ -80,6 +80,10 @@ ``` Creates a rule that matches paths by `REGEX` and applies some `PARAMETERS` to them. Matching groups can be created, and the values used in the parameters. +You need to make sure the regex matching a SVN directory path matches also the end slash (e.g. `./`) otherwise Git fast-import will crash with an `fatal: Empty path component found in input` errors. +For example, the rule `/project/trunk/.*/myFolder`, should become `/project/trunk/.*/myFolder/`. + + `PARAMETERS` is any number of: @@ -93,9 +97,9 @@ - `export` I have no idea what this does - `ignore` ignores this path - - `recurse` tells svn2git to ignore this path and continue searching it's children. + - `recurse` tells svn2git to ignore this path and continue searching its children. -- `annotate true` creates annotated tags instead of lightweight tags +- `annotated true` creates annotated tags instead of lightweight tags. You can see the commit log with `git tag -n`. ### `include FILENAME` @@ -113,4 +117,4 @@ Some SVN tricks --------------- You can access your newly rsynced SVN repo with commands like `svn ls file:///path/to/repo/trunk/KDE`. -A common issue is tracking when an item left playground for kdereview and then went from kdereview to its final destination. There is no straightforward way to do this. So the following command comes in handy: `svn log -v file:///path/to/repo/kde-svn/kde/trunk/kdereview | grep /trunk/kdereview/mplayerthumbs -A 5 -B 5` This will print all commits relevant to the package you are trying to track. You can also pipe the above command to head or tail to see the the first and last commit it was in that directory. +A common issue is tracking when an item left playground for kdereview and then went from kdereview to its final destination. There is no straightforward way to do this. So the following command comes in handy: `svn log -v file:///path/to/repo/kde-svn/kde/trunk/kdereview | grep /trunk/kdereview/mplayerthumbs -A 5 -B 5` This will print all commits relevant to the package you are trying to track. You can also pipe the above command to head or tail to see the first and last commit it was in that directory. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/svn2git-1.0.18/src/CommandLineParser.cpp new/svn2git-1.0.20/src/CommandLineParser.cpp --- old/svn2git-1.0.18/src/CommandLineParser.cpp 2020-04-20 08:58:53.000000000 +0200 +++ new/svn2git-1.0.20/src/CommandLineParser.cpp 2025-04-28 14:27:55.000000000 +0200 @@ -79,7 +79,7 @@ QString option = QString::fromLatin1(options[i].specification); // options with optional params are written as "--option required[, optional] if (option.indexOf(QLatin1Char(',')) >= 0 && ( option.indexOf(QLatin1Char('[')) < 0 || option.indexOf(QLatin1Char(']')) < 0) ) { - QStringList optionParts = option.split(QLatin1Char(','), QString::SkipEmptyParts); + QStringList optionParts = option.split(QLatin1Char(','), Qt::SkipEmptyParts); if (optionParts.count() != 2) { qWarning() << "WARN: option definition '" << option << "' is faulty; only one ',' allowed"; continue; @@ -104,7 +104,7 @@ if(definition.name.isEmpty()) continue; if (option.indexOf(QLatin1Char(' ')) > 0) { - QStringList optionParts = definition.name.split(QLatin1Char(' '), QString::SkipEmptyParts); + QStringList optionParts = definition.name.split(QLatin1Char(' '), Qt::SkipEmptyParts); definition.name = optionParts[0]; bool first = true; foreach (QString s, optionParts) { @@ -137,7 +137,7 @@ { requiredArguments = 0; argumentDefinition = QString::fromLatin1(defs); - QStringList optionParts = argumentDefinition.split(QLatin1Char(' '), QString::SkipEmptyParts); + QStringList optionParts = argumentDefinition.split(QLatin1Char(' '), Qt::SkipEmptyParts); bool inArg = false; foreach (QString s, optionParts) { s = s.trimmed(); @@ -327,7 +327,11 @@ void CommandLineParser::usage(const QString &name, const QString &argumentDescription) { +#if QT_VERSION >= 0x060000 + QTextStream cout(stdout, QIODeviceBase::WriteOnly); +#else QTextStream cout(stdout, QIODevice::WriteOnly); +#endif cout << "Usage: " << d->argumentStrings[0]; if (! name.isEmpty()) cout << " " << name; @@ -335,10 +339,10 @@ cout << " [OPTION]"; if (! argumentDescription.isEmpty()) cout << " " << argumentDescription; - cout << endl << endl; + cout << Qt::endl << Qt::endl; if (d->definitions.count() > 0) - cout << "Options:" << endl; + cout << "Options:" << Qt::endl; int commandLength = 0; foreach (Private::OptionDefinition definition, d->definitions) commandLength = qMax(definition.name.length(), commandLength); @@ -352,7 +356,7 @@ cout << definition.name; for (int i = definition.name.length(); i <= commandLength; i++) cout << ' '; - cout << definition.comment <<endl; + cout << definition.comment << Qt::endl; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/svn2git-1.0.18/src/main.cpp new/svn2git-1.0.20/src/main.cpp --- old/svn2git-1.0.18/src/main.cpp 2020-04-20 08:58:53.000000000 +0200 +++ new/svn2git-1.0.20/src/main.cpp 2025-04-28 14:27:55.000000000 +0200 @@ -184,7 +184,7 @@ foreach (QString option, args->undefinedOptions()) { if (!first) out << " : "; - out << "unrecognized option or missing argument for; `" << option << "'" << endl; + out << "unrecognized option or missing argument for; `" << option << "'" << Qt::endl; first = false; } return 10; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/svn2git-1.0.18/src/repository.cpp new/svn2git-1.0.20/src/repository.cpp --- old/svn2git-1.0.18/src/repository.cpp 2020-04-20 08:58:53.000000000 +0200 +++ new/svn2git-1.0.20/src/repository.cpp 2025-04-28 14:27:55.000000000 +0200 @@ -113,6 +113,7 @@ QVector<int> marks; }; + QString defaultBranch; QHash<QString, Branch> branches; QHash<QString, QByteArray> branchNotes; QHash<QString, AnnotatedTag> annotatedTags; @@ -326,8 +327,18 @@ branches.insert(branchRule.name, branch); } - // create the default branch - branches["master"].created = 1; + // create the defaultBranch from the config + QProcess config; + config.start("git", QStringList() << "config" << "init.defaultBranch"); + config.waitForFinished(-1); + defaultBranch = QString(config.readAllStandardOutput()).trimmed(); + + // Create the default branch + if (defaultBranch.isEmpty()) { + defaultBranch = "master"; + } + + branches[defaultBranch].created = 1; if (!CommandLineParser::instance()->contains("dry-run") && !CommandLineParser::instance()->contains("create-dump")) { fastImport.setWorkingDirectory(name); @@ -605,7 +616,7 @@ return brFrom.marks.last(); } - QVector<int>::const_iterator it = qUpperBound(brFrom.commits, branchRevNum); + QVector<int>::const_iterator it = std::upper_bound(brFrom.commits.constBegin(), brFrom.commits.constEnd(), branchRevNum); if (it == brFrom.commits.begin()) { return 0; } @@ -725,8 +736,8 @@ Repository::Transaction *FastImportRepository::newTransaction(const QString &branch, const QString &svnprefix, int revnum) { - if (!branches.contains(branch)) { - qWarning() << "WARN: Transaction:" << branch << "is not a known branch in repository" << name << endl + if (!branchExists(branch)) { + qWarning() << "WARN: Transaction:" << branch << "is not a known branch in repository" << name << Qt::endl << "Going to create it automatically"; } @@ -1016,7 +1027,7 @@ modifiedFiles.append(" :"); modifiedFiles.append(QByteArray::number(mark)); modifiedFiles.append(' '); - modifiedFiles.append(repository->prefix + path.toUtf8()); + modifiedFiles.append(repository->prefix.toUtf8() + path.toUtf8()); modifiedFiles.append("\n"); // it is returned for being written to, so start the process in any case @@ -1069,11 +1080,11 @@ QByteArray s(""); s.append("commit refs/notes/commits\n"); s.append("mark :" + QByteArray::number(maxMark) + "\n"); - s.append("committer " + author + " " + QString::number(datetime) + " +0000" + "\n"); - s.append("data " + QString::number(message.length()) + "\n"); + s.append("committer " + author + " " + QByteArray::number(datetime) + " +0000" + "\n"); + s.append("data " + QByteArray::number(message.length()) + "\n"); s.append(message + "\n"); s.append("N inline " + commitRef + "\n"); - s.append("data " + QString::number(text.length()) + "\n"); + s.append("data " + QByteArray::number(text.length()) + "\n"); s.append(text + "\n"); repository->startFastImport(); repository->fastImport.write(s); @@ -1122,8 +1133,9 @@ if (br.created && !br.marks.isEmpty() && br.marks.last()) { parentmark = br.marks.last(); } else { - if (revnum > 1) { - // Any branch at revision 1 isn't going to exist, so lets not alarm the user. + if (revnum > 1 && branch != repository->defaultBranch) { + // Any branch at revision 1 isn't going to exist -> do not alarm the user. + // Default branch might also not exist yet -> do not alarm the user. qWarning() << "WARN: Branch" << branch << "in repository" << repository->name << "doesn't exist at revision" << revnum << "-- did you resume from the wrong revision?"; } @@ -1140,7 +1152,7 @@ s.append("commit " + branchRef + "\n"); s.append("mark :" + QByteArray::number(mark) + "\n"); s.append("committer " + author + " " + QString::number(datetime).toUtf8() + " +0000" + "\n"); - s.append("data " + QString::number(message.length()) + "\n"); + s.append("data " + QByteArray::number(message.length()) + "\n"); s.append(message + "\n"); repository->fastImport.write(s); @@ -1149,7 +1161,7 @@ mark_t i = !!parentmark; // if parentmark != 0, there's at least one parent if(log.contains("This commit was manufactured by cvs2svn") && merges.count() > 1) { - qSort(merges); + std::sort(merges.begin(), merges.end()); repository->fastImport.write("merge :" + QByteArray::number(merges.last()) + "\n"); merges.pop_back(); qWarning() << "WARN: Discarding all but the highest merge point as a workaround for cvs2svn created branch/tag" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/svn2git-1.0.18/src/ruleparser.cpp new/svn2git-1.0.20/src/ruleparser.cpp --- old/svn2git-1.0.18/src/ruleparser.cpp 2020-04-20 08:58:53.000000000 +0200 +++ new/svn2git-1.0.20/src/ruleparser.cpp 2025-04-28 14:27:55.000000000 +0200 @@ -156,7 +156,7 @@ qFatal("Could not read the rules file: %s", qPrintable(filename)); QTextStream s(&file); - QStringList lines = s.readAll().split('\n', QString::KeepEmptyParts); + QStringList lines = s.readAll().split('\n', Qt::KeepEmptyParts); QStringList::iterator it; for(it = lines.begin(); it != lines.end(); ++it) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/svn2git-1.0.18/src/ruleparser.h new/svn2git-1.0.20/src/ruleparser.h --- old/svn2git-1.0.18/src/ruleparser.h 2020-04-20 08:58:53.000000000 +0200 +++ new/svn2git-1.0.20/src/ruleparser.h 2025-04-28 14:27:55.000000000 +0200 @@ -63,7 +63,11 @@ QString replacement; bool isValid() { return !pattern.isEmpty(); } +#if QT_VERSION >= 0x060000 + QString apply(QString &string) { return pattern.replaceIn(string, replacement); } +#else QString& apply(QString &string) { return string.replace(pattern, replacement); } +#endif }; QRegExp rx; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/svn2git-1.0.18/src/src.pro new/svn2git-1.0.20/src/src.pro --- old/svn2git-1.0.18/src/src.pro 2020-04-20 08:58:53.000000000 +0200 +++ new/svn2git-1.0.20/src/src.pro 2025-04-28 14:27:55.000000000 +0200 @@ -10,6 +10,8 @@ VERSION = $$system(git --no-pager show --pretty=oneline --no-notes | head -1 | cut -b-40) } +DEFINES += QT_DISABLE_DEPRECATED_UP_TO=0x05FFFF + VERSTR = '\\"$${VERSION}\\"' # place quotes around the version string DEFINES += VER=\"$${VERSTR}\" # create a VER macro containing the version string @@ -27,6 +29,16 @@ DEPENDPATH += . QT = core +_MIN_QT_VERSION = 5.14.0 + +!versionAtLeast(QT_VERSION, $${_MIN_QT_VERSION}) { + error("Qt $${QT_VERSION} found but Qt >=$${_MIN_QT_VERSION} required, cannot continue.") +} + +greaterThan(QT_MAJOR_VERSION, 5) { + QT += core5compat +} + INCLUDEPATH += . $$SVN_INCLUDE $$APR_INCLUDE !isEmpty(SVN_LIBDIR): LIBS += -L$$SVN_LIBDIR LIBS += -lsvn_fs-1 -lsvn_repos-1 -lapr-1 -lsvn_subr-1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/svn2git-1.0.18/src/svn.cpp new/svn2git-1.0.20/src/svn.cpp --- old/svn2git-1.0.18/src/svn.cpp 2020-04-20 08:58:53.000000000 +0200 +++ new/svn2git-1.0.20/src/svn.cpp 2025-04-28 14:27:55.000000000 +0200 @@ -438,7 +438,11 @@ if (repository_p) { *repository_p = svnprefix; +#if QT_VERSION >= 0x060000 + *repository_p = rule.rx.replaceIn(*repository_p, rule.repository); +#else repository_p->replace(rule.rx, rule.repository); +#endif foreach (Rules::Match::Substitution subst, rule.repo_substs) { subst.apply(*repository_p); } @@ -446,7 +450,11 @@ if (effectiveRepository_p) { *effectiveRepository_p = svnprefix; +#if QT_VERSION >= 0x060000 + *effectiveRepository_p = rule.rx.replaceIn(*effectiveRepository_p, rule.repository); +#else effectiveRepository_p->replace(rule.rx, rule.repository); +#endif foreach (Rules::Match::Substitution subst, rule.repo_substs) { subst.apply(*effectiveRepository_p); } @@ -458,7 +466,11 @@ if (branch_p) { *branch_p = svnprefix; +#if QT_VERSION >= 0x060000 + *branch_p = rule.rx.replaceIn(*branch_p, rule.branch); +#else branch_p->replace(rule.rx, rule.branch); +#endif foreach (Rules::Match::Substitution subst, rule.branch_substs) { subst.apply(*branch_p); } @@ -466,7 +478,11 @@ if (path_p) { QString prefix = svnprefix; +#if QT_VERSION >= 0x060000 + prefix = rule.rx.replaceIn(prefix, rule.prefix); +#else prefix.replace(rule.rx, rule.prefix); +#endif *path_p = prefix + pathName.mid(svnprefix.length()); } } @@ -477,7 +493,11 @@ apr_hash_t *changes; SVN_ERR(svn_fs_paths_changed2(&changes, fs_root, pool)); +#if QT_VERSION >= 0x060000 + QMultiMap<QByteArray, svn_fs_path_change2_t*> map; +#else QMap<QByteArray, svn_fs_path_change2_t*> map; +#endif for (apr_hash_index_t *i = apr_hash_first(pool, changes); i; i = apr_hash_next(i)) { const void *vkey; void *value; @@ -497,10 +517,18 @@ fflush(stderr); exit(1); } +#if QT_VERSION >= 0x060000 + map.insert(QByteArray(key), change); +#else map.insertMulti(QByteArray(key), change); +#endif } +#if QT_VERSION >= 0x060000 + QMultiMapIterator<QByteArray, svn_fs_path_change2_t*> i(map); +#else QMapIterator<QByteArray, svn_fs_path_change2_t*> i(map); +#endif while (i.hasNext()) { i.next(); if (exportEntry(i.key(), i.value(), changes) == EXIT_FAILURE) @@ -975,16 +1003,28 @@ // While we get a hash, put it in a map for sorted lookup, so we can // repeat the conversions and get the same git commit hashes. +#if QT_VERSION >= 0x060000 + QMultiMap<QByteArray, svn_node_kind_t> map; +#else QMap<QByteArray, svn_node_kind_t> map; +#endif for (apr_hash_index_t *i = apr_hash_first(pool, entries); i; i = apr_hash_next(i)) { const void *vkey; void *value; apr_hash_this(i, &vkey, NULL, &value); svn_fs_dirent_t *dirent = reinterpret_cast<svn_fs_dirent_t *>(value); +#if QT_VERSION >= 0x060000 + map.insert(QByteArray(dirent->name), dirent->kind); +#else map.insertMulti(QByteArray(dirent->name), dirent->kind); +#endif } +#if QT_VERSION >= 0x060000 + QMultiMapIterator<QByteArray, svn_node_kind_t> i(map); +#else QMapIterator<QByteArray, svn_node_kind_t> i(map); +#endif while (i.hasNext()) { dirpool.clear(); i.next(); @@ -1043,17 +1083,29 @@ // While we get a hash, put it in a map for sorted lookup, so we can // repeat the conversions and get the same git commit hashes. +#if QT_VERSION >= 0x060000 + QMultiMap<QByteArray, svn_node_kind_t> map; +#else QMap<QByteArray, svn_node_kind_t> map; +#endif for (apr_hash_index_t *i = apr_hash_first(pool, entries); i; i = apr_hash_next(i)) { dirpool.clear(); const void *vkey; void *value; apr_hash_this(i, &vkey, NULL, &value); svn_fs_dirent_t *dirent = reinterpret_cast<svn_fs_dirent_t *>(value); +#if QT_VERSION >= 0x060000 + map.insert(QByteArray(dirent->name), dirent->kind); +#else map.insertMulti(QByteArray(dirent->name), dirent->kind); +#endif } +#if QT_VERSION >= 0x060000 + QMultiMapIterator<QByteArray, svn_node_kind_t> i(map); +#else QMapIterator<QByteArray, svn_node_kind_t> i(map); +#endif while (i.hasNext()) { dirpool.clear(); i.next(); @@ -1271,16 +1323,28 @@ return EXIT_FAILURE; } +#if QT_VERSION >= 0x060000 + QMultiMap<QByteArray, svn_node_kind_t> map; +#else QMap<QByteArray, svn_node_kind_t> map; +#endif for (apr_hash_index_t *i = apr_hash_first(pool, entries); i; i = apr_hash_next(i)) { const void *vkey; void *value; apr_hash_this(i, &vkey, NULL, &value); svn_fs_dirent_t *dirent = reinterpret_cast<svn_fs_dirent_t *>(value); +#if QT_VERSION >= 0x060000 + map.insert(QByteArray(dirent->name), dirent->kind); +#else map.insertMulti(QByteArray(dirent->name), dirent->kind); +#endif } +#if QT_VERSION >= 0x060000 + QMultiMapIterator<QByteArray, svn_node_kind_t> i(map); +#else QMapIterator<QByteArray, svn_node_kind_t> i(map); +#endif while (i.hasNext()) { i.next(); QString entryName = key + "/" + i.key(); @@ -1306,9 +1370,17 @@ *ignore = QString(prop->data); // remove patterns with slashes or backslashes, // they didn't match anything in Subversion but would in Git eventually +#if QT_VERSION >= 0x060000 + *ignore = QRegExp("^[^\\r\\n]*[\\\\/][^\\r\\n]*(?:[\\r\\n]|$)|[\\r\\n][^\\r\\n]*[\\\\/][^\\r\\n]*(?=[\\r\\n]|$)").removeIn(*ignore); +#else ignore->remove(QRegExp("^[^\\r\\n]*[\\\\/][^\\r\\n]*(?:[\\r\\n]|$)|[\\r\\n][^\\r\\n]*[\\\\/][^\\r\\n]*(?=[\\r\\n]|$)")); +#endif // add a slash in front to have the same meaning in Git of only working on the direct children +#if QT_VERSION >= 0x060000 + *ignore = QRegExp("(^|[\\r\\n])\\s*(?![\\r\\n]|$)").replaceIn(*ignore, "\\1/"); +#else ignore->replace(QRegExp("(^|[\\r\\n])\\s*(?![\\r\\n]|$)"), "\\1/"); +#endif if (ignore->trimmed().isEmpty()) { *ignore = QString(); } @@ -1323,14 +1395,22 @@ QString global_ignore = QString(prop->data); // remove patterns with slashes or backslashes, // they didn't match anything in Subversion but would in Git eventually +#if QT_VERSION >= 0x060000 + global_ignore = QRegExp("^[^\\r\\n]*[\\\\/][^\\r\\n]*(?:[\\r\\n]|$)|[\\r\\n][^\\r\\n]*[\\\\/][^\\r\\n]*(?=[\\r\\n]|$)").removeIn(global_ignore); +#else global_ignore.remove(QRegExp("^[^\\r\\n]*[\\\\/][^\\r\\n]*(?:[\\r\\n]|$)|[\\r\\n][^\\r\\n]*[\\\\/][^\\r\\n]*(?=[\\r\\n]|$)")); +#endif if (!global_ignore.trimmed().isEmpty()) { ignore->append(global_ignore); } } // replace multiple asterisks Subversion meaning by Git meaning +#if QT_VERSION >= 0x060000 + *ignore = QRegExp("\\*+").replaceIn(*ignore, "*"); +#else ignore->replace(QRegExp("\\*+"), "*"); +#endif return EXIT_SUCCESS; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/svn2git-1.0.18/test/empty-dirs.bats new/svn2git-1.0.20/test/empty-dirs.bats --- old/svn2git-1.0.18/test/empty-dirs.bats 2020-04-20 08:58:53.000000000 +0200 +++ new/svn2git-1.0.20/test/empty-dirs.bats 2025-04-28 14:27:55.000000000 +0200 @@ -1060,7 +1060,7 @@ assert_equal "$(git -C git-repo show branch-a:dir-a/.gitignore)" '/ignore-a' } -@test 'branching with svn-ignore, svn-branches and empty-dirs parameter should not replace filled .gitignore files with empty ones' { +@test 'branching with svn-ignore, svn-branches and empty-dirs parameter should not replace filled .gitignore files with empty ones (nested)' { svn mkdir project-a cd project-a svn mkdir --parents trunk/dir-a diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/svn2git-1.0.18/test.sh new/svn2git-1.0.20/test.sh --- old/svn2git-1.0.18/test.sh 2020-04-20 08:58:53.000000000 +0200 +++ new/svn2git-1.0.20/test.sh 2025-04-28 14:27:55.000000000 +0200 @@ -38,4 +38,28 @@ fi mkdir -p "$SCRIPT_DIR/build/tmp" -TMPDIR="$SCRIPT_DIR/build/tmp" test/libs/bats-core/bin/bats "$@" +{ + TMPDIR="$SCRIPT_DIR/build/tmp" \ + test/libs/bats-core/bin/bats "$@" \ + 4>&1 1>&2 2>&4 | + awk ' + BEGIN { + duplicate_test_names = "" + } + + { + print + } + + /duplicate test name/ { + duplicate_test_names = duplicate_test_names "\n\t" $0 + } + + END { + if (length(duplicate_test_names)) { + print "\nERROR: duplicate test name(s) found:" duplicate_test_names + exit 1 + } + } + ' +} 4>&1 1>&2 2>&4
