はじめに
前回の記事では、SVNからGit/GitLabへの移行準備について記載しました。
今回はその続編として、移行する際の具体的な手順/コマンドと注意点、そして移行を担保する方法について記載します。
1. Git/GitLab 移行の実践手順とツール活用
SVNからGit/GitLabへの移行を実行に移すにあたり、git-svnコマンドの構文やオプション、 各種ケースへの対応方法、実行する上での注意点について具体的に記載します。
1.1. 環境要件
以下の環境を想定して記載します。
| 項目 | 前提条件 |
|---|---|
| OS | Windows 11 |
| Git | バージョン 2.50.0 以降 |
| git-svn | Gitに付属のバージョン |
| PowerShell | バージョン 5.1 以降 |
我々の作業時点(2025年6月)に用いた Git 2.50.0 以降を想定しています。 今後のリリースで仕様が変わる可能性があるため、適宜Gitの最新ドキュメントをご参照ください。
1.2. git-svn の基本構文と前提知識
git-svn は Git 本体に標準で付属するサブコマンドであり、SVN の履歴を Git に忠実に変換できる移行ツールです。
通常は Git を標準的なパッケージでインストールすることで利用可能です。
SVN のリビジョン履歴を Git のコミットとして再構築し、ブランチ・タグ情報も Git の形式で再現します。
基本構文
SVN から Git に履歴を移行する際は、以下いずれかの手順で実行します:
- 2段階方式(推奨): 柔軟な設定変更や段階的な履歴変換が可能です。エラー発生時点からの再開等も可能なため、こちらを推奨します。
git svn init [SVN_URL] [オプション]
git svn fetch [オプション]
- 一括方式: 一度ですべての履歴を変換します。(initとfetchが一度で実行されます。)
git svn clone [SVN_URL] [オプション] [出力先ディレクトリ]
主なオプション
| オプション | 説明 | 使用可能なコマンド | 備考 |
|---|---|---|---|
| --stdlayout | 標準構成(trunk/branches/tags)を自動認識して変換 | init, clone | - |
| --trunk --branches --tags |
カスタムレイアウト向けに個別パス指定 | init, clone | - |
| -authors-file= |
SVNユーザー名をGit形式に変換するマッピングファイル | init, fetch | - |
| -r |
特定のリビジョン範囲のみ変換 | fetch, clone | - |
| --ignore-paths= |
除外するパスを正規表現で指定 | init, clone | fetchは設定ファイルの変更で対応可 |
| --preserve-empty-dirs | 空ディレクトリを保持 | clone | fetchでは.git/configの設定が必要 |
SVNとGitの併用期間における双方向同期の注意と回避策
git-svn は Git と SVN の 双方向同期にも対応しており、git svn dcommit によって Git のコミットを SVN に反映できます。
ただし、双方向運用は、「SVN を一時的に併用する移行期間」や「特定部門のみ先行してGitへ移行する段階的運用」など、
明確な運用設計がある場合に限り使用することが推奨されます。
双方向同期の運用には、以下のリスクがあります:
- Git のマージやリベースの履歴が SVN 側で正しく再現されない
- コミット順や履歴整合性に関する制約
- 開発者の混乱や運用負荷の増大
1.3. 標準レイアウトでの移行手順
SVN リポジトリが trunk/、branches/、tags/ の標準構成の場合は、git-svn の --stdlayout オプションを使用することで 比較的容易に Git 形式へ変換できます。以下に、移行作業の基本的な流れを記載します。
1.3.1. Gitリポジトリを初期化
mkdir git-migration
cd git-migration
git svn init <SVN_URL> --stdlayout --authors-file=authors.txt
SVN_URLはリポジトリのルートURLを指定します。(例:svn+ssh://svn.example.com/project) authors.txtは SVN ユーザ名を Git の Author 形式に変換するマッピングファイルです。
1.3.2. 履歴を変換
git svn fetch
- SVNのすべての履歴が順次変換され、ローカルのGitの履歴に反映されます。
- 初回は -r
: オプションにて一部分だけ変換を行い動作確認することが推奨されます。 - 特定のパスやバイナリファイルの除外方法は後述の「1.5 バイナリファイルの除外と管理方針」を参照ください。
トラブルシュート(Unknown authorエラー)
authors.txt の記述ミスで「Unknown author」エラーが出た場合は authors.txt を修正し、 fetchを再実行できます。途中で止まっても再実行すれば続行可能です。
1.3.3. 改行コード(auto.crlf)の設定の事前確認
Windows 環境で Git を利用する際、core.autocrlf の設定により 改行コード(LF/CRLF)が自動的に変換されることがあります。 特にLinux向けスクリプト(.shファイルなど)を扱う場合、改行がCRLFに変換されると、 Linux上でエラーになる等の不具合を引き起こす可能性があります。 Windows 版 Git ではインストール時にこの設定を指定できますが、 誤って設定を省略した場合は、以下の対応を検討します。
- gitattributes ファイルで明示的に LF を指定する
*.sh text eol=lf
- Windowsでも以下のように設定することで改行コードの自動変換を無効にできます。
git config --global core.autocrlf false
1.3.4. パフォーマンス最適化
大規模リポジトリを移行する際は以下オプションの使用を追加で検討します。
- -r
: で履歴を範囲指定し段階的にGitへ変換 - --no-metadata でコミットメッセージ内の SVN 情報を除外し、軽量化
- --log-window-size でSVNから一度に取得する履歴数を調整し、効率化 --log-window-sizeオプションの設定値は、ネットワーク環境やメモリ状況に応じてエラーにならない値に調整が必要です。
1.3.5. 変換内容の確認
git log --graph --all
git branch -a
- SVN の Trunk、ブランチ、タグが、Git 側では master、リモートブランチ、およびタグ相当の参照として変換・生成されていることを確認します。 以下は、git-svn による標準レイアウトの変換結果を概念的に示した図です。

tags は remotes/tags/… ブランチとして取り込まれ、Git タグとしては扱われない点にご注意ください。
1.3.6. リモートに push(必要に応じて)
git remote add origin https://gitlab.example.com/group/repo.git
git push -u origin master
リモートの SSH キーの登録等は適宜行ってください。
1.4. Git タグとして再定義する手順と注意点
SVN の /tags/ ディレクトリは、git-svn によって Git に変換される際、 正式な Git タグではなく「リモートブランチのような参照」として取り込まれます。 そのため、Git 上でタグとして適切に運用するには、手動で再定義する必要があります。
git tag v1.0 refs/remotes/tags/v1.0
git push origin v1.0 # 必要に応じてリモートに反映
なぜタグの再定義が必要なのか?
git-svnはSVN の /tags/ を Git のタグ(refs/tags/...)ではなく、refs/remotes/tags/...という リモートブランチのような参照として取り込みます。 SVN における「タグ」は、そのブランチと同様に変更可能なディレクトリのコピーであり、Git のような不変性や特別な意味を持ちません。 一方、Git のタグは「不変のバージョン識別子」として、GitLabのUI表示やCI/CDトリガー、パッケージ管理などで特別な意味を持ちます。 この違いにより、SVN のタグは Git 上ではブランチとして扱われるため、正式な Git タグとして利用するには、git tag コマンドによる手動定義が必要です。
1.5. カスタムレイアウトでの移行手順
標準的な trunk/, branches/, tags/レイアウトでないSVNリポジトリに対しては、 git svn init の際に --trunk や --branches、--tags オプションを明示的に指定する必要があります。 ここでは、よくあるカスタム構成パターンを例に、具体的な移行手順を記載します。
1.5.1 構成パターンの代表例
- ケース1:trunkがサブディレクトリにある
/svn-root/
├── project-x/
│ └── trunk/
│ └── branches/
│ └── tags/
この場合、以下のように --trunk などを明示的に指定します。
git svn init svn+ssh://svn.example.com/project `
--trunk=trunk `
--branches=branches `
--tags=tags `
--authors-file=authors.txt
- ケース2:branchesが複数階層に分かれている
/svn-root/
└── trunk/
└── branches/
├── dev/feature-a/
├── dev/feature-b/
└── hotfix/issue-123/
このような階層的なブランチ構成(例:branches/dev/feature-a や branches/hotfix/issue-001 など)が存在する場合は、 --branches オプションで 各ブランチの親ディレクトリを明示的に複数指定する必要があります。 ワイルドカードによる branches// のような再帰的指定は git-svn ではサポートされていません。
git svn init svn+ssh://svn.example.com/project `
--trunk=trunk `
--branches=branches/dev `
--branches=branches/hotfix `
--tags=tags `
--authors-file=authors.txt
1.5.2 事前検証について
本番の履歴変換に入る前に、限定的な条件で動作検証を行うことで、 意図した通りにブランチやタグが正しく取り込まれるかを確認できます。
リビジョン限定フェッチ(-r
特定のリビジョンだけを対象にすることで、処理時間を抑えて構成の確認が必要です。 ただし、そのリビジョン範囲に対象ブランチ・タグへのコミットが存在しない場合、 Git 上にその参照(例:refs/remotes/feature-x)が生成されない点に注意が必要です。
# リビジョン1~10までの履歴を変換する
git svn fetch -r1:10
1.6. バイナリファイルの除外と管理方針
1.6.1. バイナリファイルの除外基準
バイナリファイルは、Git による通常のバージョン管理には適しておらず、以下のような課題が発生する可能性があります。
- リポジトリサイズの肥大化
- 差分の取得・マージの困難さ
- cloneやCI/CDパイプラインの処理負荷の増加
そのため、バイナリファイルは原則として Git での直接管理を避け、成果物専用リポジトリや GitHub/GitLab のアーティファクト管理機能等へ移管することが推奨されます。 これらのファイルは .gitignore での除外が基本方針となり、これは移行後の誤コミット防止にもつながります。
除外対象の例
- ビルド済みバイナリ(例:.exe, .jar, .dll)
- 一時的に生成されるアーカイブファイル(例:.zip, .tar.gz)
- 開発ツールやIDEによるキャッシュ・中間生成物(例:.class, .log, .tmp)
- 静的アセット(画像・音声・動画など)のうち、頻繁に変更されるもの
必要に応じて、Git LFS(Large File Storage)による管理を検討します。 後述のGit LFS を利用することで、バイナリファイルを Git リポジトリに含めつつ、サイズ管理・転送効率を最適化することが可能です。
1.6.2 --ignore-paths オプションによる除外
git svn init/clone において--ignore-pathsオプションを指定することで、除外すべきディレクトリ・ファイルを正規表現で除外することが可能です。
git svn init [SVN_URL] --ignore-paths="\.exe$|\.jar$"
fetch 時にも適用するには?
git svn fetch では --ignore-paths を直接指定できないため、事前に .git/config に該当設定を追記することで除外設定を反映させる必要があります。
以下は設定例です:
[svn-remote "svn"]
url = svn+ssh://svn.example.com/project
fetch = trunk:refs/remotes/trunk
ignore-paths = \.exe$|\.jar$
1.6.3 Git LFS の活用(大容量バイナリの必要時)
バイナリファイルを Git リポジトリ上で管理せざるを得ないケースでは、 履歴の肥大化やパフォーマンス低下を回避するために、Git LFSの導入が強く推奨されます。 Git LFS を使用すると、大容量ファイルの実体は外部ストレージに格納され、Git にはポインタのみが記録されるため、 Gitリポジトリの肥大化を抑止することができます。 以下は設定例です。
git lfs install
git lfs track "*.zip"
「バイナリファイルが履歴に含まれる前(初回fetch前)」にgit lfsのインストール及び.gitattributesおよびLFS trackを設定していることを確認することで手戻りを防止できます。
1.7. 移行後の整合性・品質確認チェック
Git への移行が完了した後、本格運用を開始する前に、以下の観点で事前確認を行うことが推奨されます。 これにより、履歴の欠落や差分、ビルド失敗などの問題を未然に防ぐことができます。
1.7.1 Git移行後のファイル整合性検証(ハッシュ突合チェック)
SVN 側のエクスポート結果と、Git に取り込んだ作業ツリーの内容が完全に一致しているかを確認することで、 移行漏れや変換ミスの有無を検出できます。 以下の PowerShell スクリプトでは、2つのフォルダに含まれるファイルのハッシュを比較し、 差異があるファイルをリストアップします。svn export したディレクトリと、git checkout したディレクトリの差分比較を想定しています。
サンプルコード
param(
[Parameter(Mandatory = $true)][string]$Folder1,
[Parameter(Mandatory = $true)][string]$Folder2
)
function Get-FolderHashes {
[CmdletBinding()]
param(
[Parameter(Mandatory)][string]$RootPath
)
ls $RootPath -Recurse -File |
? { $_.FullName -notmatch '\\\.git(\\|$)' -and $_.FullName -notmatch '\\\.svn(\\|$)' } |
% {
Push-Location $RootPath
$relative = Resolve-Path $_.FullName -Relative
$hash = (Get-FileHash $_.FullName -Algorithm SHA256).Hash
[PSCustomObject]@{
FilePath = $relative
Hash = $hash
}
Pop-Location
}
}
$hashes1 = Get-FolderHashes -RootPath $Folder1
$hashes2 = Get-FolderHashes -RootPath $Folder2
$diffs = Compare-Object -ReferenceObject $hashes1 `
-DifferenceObject $hashes2 `
-Property FilePath,Hash
if ($diffs) {
Write-Host "Differences detected." -ForegroundColor Red
$diffs |
Select-Object `
@{Name='Folder';Expression={ `
if ($_.SideIndicator -eq '<=') { "$(Split-Path $Folder1 -Leaf)" } `
else { "$(Split-Path $Folder2 -Leaf)" } }}, FilePath,Hash | Format-Table -AutoSize
}
else {
Write-Host "OK. No differences found." -ForegroundColor Green
}
実行イメージ:

1.7.2 改行コードの検証
Windows上で動作するスクリプトや設定ファイルがCRLFになっていること、 Linux上で動作するスクリプトや設定ファイルの改行コードがLFになっていることを確認します。
1.7.3 ビルドチェック
ビルドスクリプトが動作するかの確認や、ビルド・テスト・静的解析が成功することを確認します。
まとめ
本記事では、SVNからGit/GitLabへの移行による改善効果の整理から、検討ポイント、 具体的な移行手順、注意すべき技術的・運用的な事項までを解説しました。
Gitへの移行は単なるツール変更ではなく、開発プロセスの見直しや効率化を進める機会でもあります。 本記事が、Git/GitLabへのスムーズな移行と、より良い開発プロセスの構築に向けた一助となれば幸いです。

