From 78d508b59c0a61bb506d5f37fec6878f222ceb7e Mon Sep 17 00:00:00 2001 From: James Lacey Date: Fri, 28 Jun 2019 12:50:38 -0700 Subject: [PATCH] Handle case sensitive directory renames. --- Vss2Git/GitExporter.cs | 47 +++++++++++++++--------------------------- Vss2Git/GitWrapper.cs | 13 ++++++++++-- 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/Vss2Git/GitExporter.cs b/Vss2Git/GitExporter.cs index d963ef1..0df6cb0 100755 --- a/Vss2Git/GitExporter.cs +++ b/Vss2Git/GitExporter.cs @@ -18,6 +18,7 @@ using System.Diagnostics; using System.Globalization; using System.IO; +using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading; @@ -369,7 +370,7 @@ private bool ReplayRevision(VssPathMapper pathMapper, Revision revision, { // renaming a file or a project that contains files? var projectInfo = itemInfo as VssProjectInfo; - if (projectInfo == null || projectInfo.ContainsFiles()) + if (projectInfo == null || (projectInfo.ContainsFiles() && projectInfo.Items.All(x => !x.Destroyed))) { CaseSensitiveRename(sourcePath, targetPath, git.Move); needCommit = true; @@ -377,7 +378,7 @@ private bool ReplayRevision(VssPathMapper pathMapper, Revision revision, else { // git doesn't care about directories with no files - CaseSensitiveRename(sourcePath, targetPath, Directory.Move); + CaseSensitiveRename(sourcePath, targetPath, CaseSensitiveDirectoryMove); } } else @@ -403,15 +404,16 @@ private bool ReplayRevision(VssPathMapper pathMapper, Revision revision, { if (sourcePath != null && Directory.Exists(sourcePath)) { + var isSamePath = sourcePath.Equals(targetPath, StringComparison.OrdinalIgnoreCase); if (projectInfo.ContainsFiles()) { - git.Move(sourcePath, targetPath); + git.Move(sourcePath, targetPath, isSamePath); needCommit = true; } else { // git doesn't care about directories with no files - Directory.Move(sourcePath, targetPath); + CaseSensitiveDirectoryMove(sourcePath, targetPath, isSamePath); } } else @@ -715,39 +717,24 @@ private void WriteStream(Stream inputStream, string path) } } - private delegate void RenameDelegate(string sourcePath, string destPath); + private delegate void RenameDelegate(string sourcePath, string destPath, bool force); private void CaseSensitiveRename(string sourcePath, string destPath, RenameDelegate renamer) { - if (sourcePath.Equals(destPath, StringComparison.OrdinalIgnoreCase)) - { - // workaround for case-only renames on case-insensitive file systems: - - var sourceDir = Path.GetDirectoryName(sourcePath); - var sourceFile = Path.GetFileName(sourcePath); - var destDir = Path.GetDirectoryName(destPath); - var destFile = Path.GetFileName(destPath); - - if (sourceDir != destDir) - { - // recursively rename containing directories that differ in case - CaseSensitiveRename(sourceDir, destDir, renamer); - - // fix up source path based on renamed directory - sourcePath = Path.Combine(destDir, sourceFile); - } + renamer(sourcePath, destPath, sourcePath.Equals(destPath, StringComparison.OrdinalIgnoreCase)); + } - if (sourceFile != destFile) - { - // use temporary filename to rename files that differ in case - var tempPath = sourcePath + ".mvtmp"; - CaseSensitiveRename(sourcePath, tempPath, renamer); - CaseSensitiveRename(tempPath, destPath, renamer); - } + private void CaseSensitiveDirectoryMove(string sourcePath, string targetPath, bool force) + { + if (force) + { + var tmpPath = targetPath + ".mvtmp"; + Directory.Move(sourcePath, tmpPath); + Directory.Move(tmpPath, targetPath); } else { - renamer(sourcePath, destPath); + Directory.Move(sourcePath, targetPath); } } } diff --git a/Vss2Git/GitWrapper.cs b/Vss2Git/GitWrapper.cs index 9c970a1..f551478 100755 --- a/Vss2Git/GitWrapper.cs +++ b/Vss2Git/GitWrapper.cs @@ -138,9 +138,18 @@ public void Remove(string path, bool recursive) GitExec("rm " + (recursive ? "-r " : "") + "-- " + Quote(path)); } - public void Move(string sourcePath, string destPath) + public void Move(string sourcePath, string destPath, bool force) { - GitExec("mv -- " + Quote(sourcePath) + " " + Quote(destPath)); + if (force) + { + var tempPath = destPath + ".mvtmp"; + GitExec("mv -- " + Quote(sourcePath) + " " + Quote(tempPath)); + GitExec("mv -- " + Quote(tempPath) + " " + Quote(destPath)); + } + else + { + GitExec("mv -- " + Quote(sourcePath) + " " + Quote(destPath)); + } } class TempFile : IDisposable