using System.Diagnostics; using System.Text; using MergeHub.Services; // MergeHub 발표 시연 재료를 만든다. 실제 업무 소스는 열지 않는다 - 전부 지어낸 코드다. // // dotnet run --project demo\tools\DemoMaker -- <저장소 경로> // // demo 폴더 아래 (저장소에 커밋해 둔다) // plain\left, plain\right 폴더 비교 // style\Default.cs, style\Aurora.cs C# 스타일 맞춤 // mergetool\Weld_BASE.cs · Weld_LOCAL.cs · Weld_REMOTE.cs · Weld.cs git mergetool 네 칸 // big\Big7479_left.cs · Big7479_right.cs 큰 파일 // 저장소 경로 (기본 D:\MergeHubDemo\repo, 커밋하지 않는다 - 매번 새로 만든다) // master · feature/mine · feature/theirs. feature/mine 에 서서 feature/theirs 를 병합하면 여러 갈래 충돌이 난다. Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); var cp949 = Encoding.GetEncoding(949); var utf8Bom = new UTF8Encoding(true); var demoDir = Path.GetFullPath(args.Length > 0 ? args[0] : Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "..")); var repoRoot = Path.GetFullPath(args.Length > 1 ? args[1] : @"D:\MergeHubDemo\repo"); Console.WriteLine($"demo 폴더: {demoDir}"); Console.WriteLine($"저장소: {repoRoot}"); void WriteText(string path, string text, Encoding? encoding = null) { Directory.CreateDirectory(Path.GetDirectoryName(path)!); File.WriteAllText(path, text, encoding ?? utf8Bom); } string Crlf(params string[] rows) => string.Join("\r\n", rows) + "\r\n"; void ResetFolder(string dir) { Directory.CreateDirectory(dir); foreach (var f in Directory.EnumerateFiles(dir, "*", SearchOption.AllDirectories)) File.SetAttributes(f, FileAttributes.Normal); foreach (var f in Directory.EnumerateFiles(dir)) File.Delete(f); foreach (var d in Directory.EnumerateDirectories(dir)) Directory.Delete(d, true); } // ================= 1. 폴더 비교 ================= { var left = Path.Combine(demoDir, "plain", "left"); var right = Path.Combine(demoDir, "plain", "right"); ResetFolder(left); ResetFolder(right); var same = Crlf("namespace Demo.Weld", "{", " public static class Units", " {", " public const double Kilo = 1000.0;", " }", "}"); WriteText(Path.Combine(left, "Same.cs"), same); WriteText(Path.Combine(right, "Same.cs"), same); WriteText(Path.Combine(left, "CodeDiff.cs"), Crlf("namespace Demo.Weld", "{", " public sealed class Cooling", " {", " public int WaitMs { get; set; } = 1500;", " }", "}")); WriteText(Path.Combine(right, "CodeDiff.cs"), Crlf("namespace Demo.Weld", "{", " public sealed class Cooling", " {", " public int WaitMs { get; set; } = 1800;", " }", "}")); WriteText(Path.Combine(left, "CommentOnly.cs"), Crlf("namespace Demo.Weld", "{", " // 예열 단계", " public sealed class Preheat", " {", " public int Temperature { get; set; } = 180; // 섭씨", " }", "}")); WriteText(Path.Combine(right, "CommentOnly.cs"), Crlf("namespace Demo.Weld", "{", " // 예열 단계 - 소재 두께에 따라 바뀜", " public sealed class Preheat", " {", " public int Temperature { get; set; } = 180;", " }", "}")); WriteText(Path.Combine(left, "MergeNoteOnly.cs"), Crlf("namespace Demo.Weld", "{", " public sealed class Laser", " {", " public int Power { get; set; } = 150;", " public int Focus { get; set; } = 12;", " }", "}")); WriteText(Path.Combine(right, "MergeNoteOnly.cs"), Crlf("namespace Demo.Weld", "{", " public sealed class Laser", " {", " // [김승준] 2026-09-10 출력 통일", " public int Power { get; set; } = 150;", " public int Focus { get; set; } = 12; // [박지훈] 2026-09-11", " }", "}")); var styleDefault = StyleSample(); WriteText(Path.Combine(left, "StyleOnly.cs"), styleDefault); WriteText(Path.Combine(right, "StyleOnly.cs"), CSharpStyle.Format(styleDefault, CSharpBraceStyle.Aurora)); WriteText(Path.Combine(left, "LeftOnly.cs"), Crlf("namespace Demo.Weld", "{", " public sealed class OldSensor", " {", " }", "}")); WriteText(Path.Combine(right, "RightOnly.cs"), Crlf("namespace Demo.Weld", "{", " public sealed class NewSensor", " {", " }", "}")); WriteText(Path.Combine(left, "Views", "Recipe.xaml"), Crlf("", "