Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Repo Migrate Folder With History
void Main()
{
var originalRepo = "git@github.com:_**_/_**_.git";
var originalRepoBranch = "master";
var newRepo = "git@github.com:_**_/_**_.git";
var newRepoBranch = "master";
var workInProgressDir = @"C:\Temp\RepoCopy";
var relativeFolderToMigrate = "src/path";
MigrateRepo(originalRepo, originalRepoBranch, newRepo, newRepoBranch, workInProgressDir, relativeFolderToMigrate);
}
private void MigrateRepo(string originalRepo, string originalRepoBranch, string newRepo, string newRepoBranch, string workInProgressDir, string relativeFolderToMigrate)
{
var runId = Guid.NewGuid().ToString();
Console.WriteLine("-----------------------------");
Console.WriteLine($"RunId: {runId}");
var runDirectory = Path.Combine(workInProgressDir, runId);
var fromRepoPath = Path.Combine(runDirectory, "FromRepo");
var fromRepoCleanUpPath = Path.Combine(runDirectory, "FromRepoCleanUp");
var toRepoPath = Path.Combine(runDirectory, "ToRepo");
EnsureDirectoryClean(runDirectory);
Console.WriteLine("-----------------------------");
Console.WriteLine($"Creating filtered version of {originalRepo}");
RunGit(workInProgressDir, $"clone {originalRepo} {fromRepoPath}");
RunGit(fromRepoPath, "remote rm origin");
RunGit(fromRepoPath, $"checkout {originalRepoBranch}");
RunGit(fromRepoPath, $"filter-branch --subdirectory-filter {relativeFolderToMigrate} -- --all");
Console.WriteLine("-----------------------------");
Console.WriteLine($"Moving {fromRepoPath} content back into the relative folder of {relativeFolderToMigrate}");
var subDirs = Directory.GetDirectories(fromRepoPath);
var subFiles = Directory.GetFiles(fromRepoPath);
var newLocationRoot = Path.Combine(fromRepoPath, relativeFolderToMigrate);
Console.WriteLine($"Creating Dir: {newLocationRoot}");
Directory.CreateDirectory(newLocationRoot);
foreach (var subDir in subDirs)
{
if(subDir.EndsWith(".git")) continue;
var relativeSubDir = subDir.Replace(fromRepoPath, "").Substring(1);
var newLocation = Path.Combine(fromRepoPath, relativeFolderToMigrate, relativeSubDir);
Console.WriteLine($"Moving Dir: {subDir} -> {newLocation}");
Directory.Move(subDir, newLocation);
}
foreach (var subFile in subFiles)
{
var relativeSubFile = subFile.Replace(fromRepoPath, "").Substring(1);
var newLocation = Path.Combine(fromRepoPath, relativeFolderToMigrate, relativeSubFile);
Console.WriteLine($"Moving File: {subFile} -> {newLocation}");
File.Move(subFile, newLocation);
}
RunGit(fromRepoPath, $"add .");
RunGit(fromRepoPath, $"commit -m \"Revert folder structure post filter\"");
Console.WriteLine("-----------------------------");
Console.WriteLine($"Merging filtered version of {originalRepo} into {newRepo}");
RunGit(workInProgressDir, $"clone {newRepo} {toRepoPath}");
RunGit(toRepoPath, $"remote add FromRepo {fromRepoPath}");
RunGit(toRepoPath, $"pull FromRepo {originalRepoBranch}", true);
RunGit(toRepoPath, $"branch feature/RepoMigrate origin/{newRepoBranch}");
RunGit(toRepoPath, "checkout feature/RepoMigrate");
RunGit(toRepoPath, $"merge FromRepo/{originalRepoBranch} --allow-unrelated-histories");
RunGit(toRepoPath, "remote rm FromRepo");
RunGit(toRepoPath, "push origin feature/RepoMigrate");
Console.WriteLine("-----------------------------");
Console.WriteLine($"Cleaning {originalRepo}");
RunGit(workInProgressDir, $"clone {originalRepo} {fromRepoCleanUpPath}");
RunGit(fromRepoCleanUpPath, "branch feature/RepoMigrate");
RunGit(fromRepoCleanUpPath, "checkout feature/RepoMigrate");
Directory.Delete(Path.Combine(fromRepoCleanUpPath, relativeFolderToMigrate), true);
RunGit(fromRepoCleanUpPath, $"add .");
RunGit(fromRepoCleanUpPath, $"commit -a -m \"Remove migrated folder {relativeFolderToMigrate} as moved to {newRepo}\"");
RunGit(fromRepoCleanUpPath, "push origin feature/RepoMigrate");
}
private void RunGit(string workingDirectory, string args, bool ignoreError = false)
{
RunCommand(workingDirectory, "git", args, ignoreError);
}
private void RunCommand(string workingDirectory, string fileName, string args, bool ignoreError = false)
{
Process process = new Process();
Console.WriteLine("-----------------------------");
Console.WriteLine($"WorkingDirectory: {workingDirectory}");
Console.WriteLine($"Exec: {fileName} {args}");
try
{
process.StartInfo.FileName = fileName;
process.StartInfo.WorkingDirectory = workingDirectory;
process.StartInfo.Arguments = args;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.EnableRaisingEvents = false;
process.OutputDataReceived += (sender, eventArgs) => WriteConsoleOutput("stdOut", eventArgs);
process.ErrorDataReceived += (sender, eventArgs) => WriteConsoleOutput("stdErr", eventArgs);
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
if(process.ExitCode == 0)
{
Console.WriteLine($"SUCCESS: Process exited with code of {process.ExitCode}");
}
else if (ignoreError)
{
Console.WriteLine($"WARN: Process exited with code of {process.ExitCode}");
}
else
{
Console.WriteLine($"ERROR: Process exited with code of {process.ExitCode}");
throw new Exception($"Process exited with non-zero exit code of {process.ExitCode}");
}
}
finally
{
process.Close();
}
}
private void WriteConsoleOutput(string type, DataReceivedEventArgs eventArgs)
{
if (eventArgs.Data != null)
{
Console.WriteLine($"{type} : {eventArgs.Data}");
}
}
private void EnsureDirectoryClean(string path)
{
if (Directory.Exists(path))
{
Console.WriteLine("-----------------------------");
Console.WriteLine($"Directory {path} already exists, delete manually");
Console.WriteLine("Press enter to continue");
Console.ReadLine();
Directory.CreateDirectory(path);
}
else
{
Directory.CreateDirectory(path);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment