6차 A-1: 충돌 해결 저장이 내 쪽 파일의 줄끝과 인코딩을 따른다
3분할로 푼 파일을 저장하면 줄끝이 전부 LF 가 됐다. 3,363줄 CRLF 파일에서 충돌 6개를 풀었는데 git 에는 파일 전체가 바뀐 것으로 나왔다. 원인은 둘이었다. - ResolveConflictWithContent 가 인코딩만 맞추고 줄끝을 안 봤다. 편집기 글은 줄마다 \n 이라 늘 LF 로 써졌다. - 원본으로 워킹트리 파일을 읽었다. 충돌 중에는 git 이 LF 로 충돌 표시를 넣어 두어 원본이 아니다. - TextFile.Encode: 저장 바이트 규칙을 한 곳으로. "원본 유지" 는 넘겨받은 원본 바이트를 따르고, 줄끝은 가장 많은 것, BOM 은 한 번 - TextFile.Write: 디스크 파일을 원본으로 Encode 를 쓴다 - ResolveConflictWithContent: 원본을 ours blob 으로(없으면 theirs, base). 고른 저장 형식을 받는다 - HomeViewModel 세 자리가 저장 형식을 넘긴다 Io/Unit12.cs +399 줄 -> +2 -1, CRLF 유지 Motion/Unit0.cs +3367 -3363 -> +8 -4 한글설명.cs CP949 와 CRLF 유지 LineEnding.cs 상대가 LF 로 바꿔도 내 쪽 CRLF 줄바꿈 LF 를 고르면 LF 검사 모음이 빌드 실패를 삼키고 옛 실행 파일을 돌리던 것을 찾았다. LangTest(5차 B-1 의 CarryOver 변경), ReportTest(파일 누락), TokenTest(Program.cs 없음, 새로 씀)를 고쳤다. 이제 모두 다시 빌드한 새 실행 파일만 센다. 21벌 745건 통과. 경고 0, 오류 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
0485c60745
commit
538efdcd50
@ -79,4 +79,70 @@
|
|||||||
- **줄끝(CRLF → LF)은 그대로다.** 해결로 저장도 지금은 `ResolveConflictWithContent` 를 거치므로 A-1 이 남아 있다.
|
- **줄끝(CRLF → LF)은 그대로다.** 해결로 저장도 지금은 `ResolveConflictWithContent` 를 거치므로 A-1 이 남아 있다.
|
||||||
저장 길이 한 곳으로 모였으니 A-1 은 거기서 고친다.
|
저장 길이 한 곳으로 모였으니 A-1 은 거기서 고친다.
|
||||||
- 로그의 첫 번째 "건너뜀" 은 여전히 찍힌다. 기다렸다 다시 세우므로 화면에는 티가 안 난다.
|
- 로그의 첫 번째 "건너뜀" 은 여전히 찍힌다. 기다렸다 다시 세우므로 화면에는 티가 안 난다.
|
||||||
새로고침 도중에 목록을 다시 세우려는 것 자체는 B-1 에서 본다.
|
새로고침 도중에 목록을 다시 세우려는 것 자체는 B-1 에서 본다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## A-1. 3분할로 푼 파일을 저장하면 CRLF 가 LF 로 바뀐다 (2026-09-14, 완료)
|
||||||
|
|
||||||
|
### 고치기 전에 다시 났다
|
||||||
|
|
||||||
|
새로 만든 저장소에서 A-2 의 [해결로 저장] 으로 두 파일을 풀었다.
|
||||||
|
|
||||||
|
| 파일 | 원래 | 저장 뒤 | git 에 나온 변경 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `Io/Unit12.cs` (200줄 · UTF-8 BOM) | CRLF | **CR 0 / LF 200** | 399줄 (실제로 고친 것은 1줄 + 머지 주석) |
|
||||||
|
| `Common/Util/한글설명.cs` (11줄 · CP949) | CRLF | **CR 0 / LF 11** | 21줄 |
|
||||||
|
|
||||||
|
### 무엇이 원인이었나
|
||||||
|
|
||||||
|
두 가지가 겹쳤다.
|
||||||
|
|
||||||
|
1. 편집기가 주는 글(`BuildLocalText`)은 줄마다 `\n` 이다. `GitService.ResolveConflictWithContent` 는
|
||||||
|
**인코딩만 맞추고 줄끝은 아예 보지 않고** 그 글을 그대로 썼다. 그래서 늘 LF 가 됐다.
|
||||||
|
2. 인코딩을 맞출 "원본" 으로 **워킹트리 파일**을 읽었다. 충돌 중의 워킹트리에는 git 이 LF 로 충돌 표시를 넣어 두므로
|
||||||
|
줄끝을 봤더라도 "혼합" 으로 읽혔을 것이다. 보통 저장(`TextFile.Write`)은 그 "혼합" 을 무조건 CRLF 로 썼다.
|
||||||
|
|
||||||
|
### 고친 것
|
||||||
|
|
||||||
|
| 자리 | 무엇 |
|
||||||
|
|---|---|
|
||||||
|
| `TextFile.Encode` (새 함수) | 글을 저장할 바이트로 만드는 규칙을 한 곳으로 모았다. "원본 유지" 가 무엇을 따를지를 **원본 바이트로 받는다.** 인코딩은 원본에서 판별, 줄끝은 원본에서 **가장 많은 것**, 원본에 줄끝이 없으면 CRLF. BOM 은 맨 앞에 한 번만 붙이고 글 첫머리의 U+FEFF 는 뗀다 |
|
||||||
|
| `TextFile.Write` | 디스크의 파일을 원본으로 넘겨 `Encode` 를 쓴다. "혼합" 은 이제 많은 쪽을 따른다(예전에는 무조건 CRLF) |
|
||||||
|
| `GitService.ResolveConflictWithContent` | 원본을 워킹트리가 아니라 **내 쪽(ours) blob** 으로 잡는다. 내 쪽이 없으면 상대 쪽, 그것도 없으면 공통 조상. 고른 저장 형식을 받는다 |
|
||||||
|
| `HomeViewModel` 세 자리 | 해결로 저장 · Save & Commit · 확인 창의 "저장하고 계속" 이 모두 고른 저장 형식을 넘긴다 |
|
||||||
|
|
||||||
|
로그 글도 따라 바뀌었다. `충돌 해결(직접 편집, ks_c_5601-1987)` 이 `충돌 해결(직접 편집, CP949 · CRLF)` 로 나온다
|
||||||
|
(6차 C-1 의 "로그가 CP949 를 ks_c_5601-1987 로 적는다" 가 이 자리였다).
|
||||||
|
|
||||||
|
### 확인한 것 (새로 만든 저장소, 3분할 + [해결로 저장])
|
||||||
|
|
||||||
|
| 파일 | 한 일 | 결과 |
|
||||||
|
|---|---|---|
|
||||||
|
| `Io/Unit12.cs` | Take Theirs 1 | CR 200 = LF 200 · BOM 한 번 · 내 쪽 대비 **+2 −1** (고른 줄 + 머지 주석) |
|
||||||
|
| `Motion/Unit0.cs` (3,363줄) | 충돌 6개 | CR 3,367 = LF 3,367 · 내 쪽 대비 **+8 −4** (5차 C-1 에서는 +3,367 −3,363) |
|
||||||
|
| `Common/Util/한글설명.cs` | Take Theirs 1 | CR 11 = LF 11 · CP949 그대로(UTF-8 로 안 읽힘) · '가접' 들어감 |
|
||||||
|
| `Io/LineEnding.cs` | 내 쪽 CRLF · 상대가 LF 로 바꾼 파일에서 Take Theirs | **내 쪽을 따라 CRLF** (CR 61 = LF 61) |
|
||||||
|
| `Io/Unit20.cs` | 저장 형식 줄바꿈을 **LF 로 고르고** 저장 | 고른 대로 LF (CR 0 · LF 182) |
|
||||||
|
|
||||||
|
화면 확인 **10건 통과**. `EncTest` 에 저장 바이트 규칙 22건을 넣었다(16 → 38).
|
||||||
|
|
||||||
|
### 검사 모음이 옛 실행 파일로 돌고 있었다
|
||||||
|
|
||||||
|
A-1 검사를 넣고 하네스를 돌리다 **세 벌이 빌드가 안 된다**는 것을 알았다. 검사 모음 스크립트가 빌드 출력을 버리고
|
||||||
|
`bin` 에 남아 있던 **옛 실행 파일**을 그대로 돌려서, 그동안 통과로 세어지고 있었다.
|
||||||
|
|
||||||
|
| 하네스 | 무엇이 깨졌나 | 언제부터 |
|
||||||
|
|---|---|---|
|
||||||
|
| `LangTest` (52건) | 토크나이저의 줄 넘김 상태를 `bool` 로 넘겼다. 5차 B-1 에서 `CarryOver` 로 바뀌었다. 고치자 **1건이 실제로 실패** - XAML 언어 이름을 옛 이름("XML / HTML")으로 기대하고 있었다 | 5차 B-1 (09-11) |
|
||||||
|
| `ReportTest` (31건) | 프로젝트에 `CarryOver.cs` · `MarkupTokenizer.cs` 가 빠져 있었다 | 5차 B-1 (09-11) |
|
||||||
|
| `TokenTest` (15건) | **`Program.cs` 가 없다.** 언제 왜 사라졌는지 모른다. 실행 파일은 09-06 것이었다 | 알 수 없음 |
|
||||||
|
|
||||||
|
- 5차 B-1 · B-2 · C-1 과 6차 A-2 기록의 "전체 N건 통과" 에는 **이 세 벌의 옛 결과가 섞여 있다.**
|
||||||
|
고치고 새로 빌드해 돌려 보니 LangTest 의 이름 기대값 1건 말고는 모두 통과했다 - 제품 코드가 틀린 것은 없었다.
|
||||||
|
- `LangTest` 는 부르는 모양과 이름 기대값만 새 형식으로 맞췄다. 검사 내용은 그대로다.
|
||||||
|
- `ReportTest` 는 빠진 파일 둘을 넣었다.
|
||||||
|
- `TokenTest` 는 되살릴 원본이 없어 **같은 범위(C# 줄 하나를 갈래로 쪼개기)로 새로 썼다**(22건). 예전 15건과 같은 검사는 아니다.
|
||||||
|
- 검사 모음은 이제 **모두 다시 빌드하고(`--no-incremental`), 이번에 새로 만든 실행 파일이 아니면 실패로 센다.**
|
||||||
|
|
||||||
|
그렇게 돌린 결과 **21벌 745건 통과** · 빌드 경고 0 · 오류 0.
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
| 날짜 | 항목 | 커밋 |
|
| 날짜 | 항목 | 커밋 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|
| 2026-09-14 | **6차 A-1** — 충돌 해결 저장이 내 쪽(ours) 파일의 줄끝·인코딩을 따른다(3,363줄 파일 +3,367/−3,363 → +8/−4). 검사 모음이 옛 실행 파일로 돌던 것을 찾아 세 벌을 고침 | 아래 |
|
||||||
| 2026-09-14 | **6차 A-2** — 병합 중 [해결로 저장] 을 따로 둠(쓰고 스테이징만). Save & Commit 은 남은 충돌이 있으면 쓰기 전에 막는다. 건너뛴 목록 불러오기가 목록을 비우던 것도 막음 | 아래 |
|
| 2026-09-14 | **6차 A-2** — 병합 중 [해결로 저장] 을 따로 둠(쓰고 스테이징만). Save & Commit 은 남은 충돌이 있으면 쓰기 전에 막는다. 건너뛴 목록 불러오기가 목록을 비우던 것도 막음 | 아래 |
|
||||||
| 2026-09-14 | **지시서 6차 B-5 정함** — 머지 주석은 소스에 넣고, 비교·병합에서는 그 줄을 무시한다. git 은 모르므로 주석 차이뿐인 충돌은 MergeHub 가 푼다 | 아래 |
|
| 2026-09-14 | **지시서 6차 B-5 정함** — 머지 주석은 소스에 넣고, 비교·병합에서는 그 줄을 무시한다. git 은 모르므로 주석 차이뿐인 충돌은 MergeHub 가 푼다 | 아래 |
|
||||||
| 2026-09-14 | **지시서 6차** — 5차 C-1 에서 걸린 23가지를 A(망가뜨리는 것 5) · B(헷갈리는 것 8) · C(사소 1) · D(다시 끝까지)로 묶음 | 아래 |
|
| 2026-09-14 | **지시서 6차** — 5차 C-1 에서 걸린 23가지를 A(망가뜨리는 것 5) · B(헷갈리는 것 8) · C(사소 1) · D(다시 끝까지)로 묶음 | 아래 |
|
||||||
|
|||||||
@ -93,7 +93,7 @@
|
|||||||
|
|
||||||
| 상태 | 항목 |
|
| 상태 | 항목 |
|
||||||
|---|---|
|
|---|---|
|
||||||
| 대기 | A-1 3분할로 푼 파일을 저장하면 CRLF 가 LF 로 바뀐다 |
|
| **완료** | A-1 3분할로 푼 파일을 저장하면 CRLF 가 LF 로 바뀐다 — 내 쪽(ours) 파일의 줄끝·인코딩을 따른다 |
|
||||||
| **완료** | A-2 Save & Commit 이 "실패" 라는데 파일은 이미 써지고 스테이징됐다 — [해결로 저장] 을 따로 둠 |
|
| **완료** | A-2 Save & Commit 이 "실패" 라는데 파일은 이미 써지고 스테이징됐다 — [해결로 저장] 을 따로 둠 |
|
||||||
| 대기 | A-3 충돌 파일을 고르면 상대(Theirs) 칸이 안 나온다 |
|
| 대기 | A-3 충돌 파일을 고르면 상대(Theirs) 칸이 안 나온다 |
|
||||||
| 대기 | A-4 상대가 지운 파일을 3분할이 다룰 줄 모른다 |
|
| 대기 | A-4 상대가 지운 파일을 3분할이 다룰 줄 모른다 |
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -915,21 +915,32 @@ namespace MergeHub.Services
|
|||||||
Report($"충돌 해결({resolution}): {normalized}");
|
Report($"충돌 해결({resolution}): {normalized}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResolveConflictWithContent(string path, string content)
|
public void ResolveConflictWithContent(string path, string content,
|
||||||
|
string? encodingName = null, string? newLineName = null)
|
||||||
{
|
{
|
||||||
var normalized = NormalizePath(path);
|
var normalized = NormalizePath(path);
|
||||||
var fullPath = ToFullPath(normalized);
|
var fullPath = ToFullPath(normalized);
|
||||||
var directory = Path.GetDirectoryName(fullPath);
|
var directory = Path.GetDirectoryName(fullPath);
|
||||||
if (!string.IsNullOrEmpty(directory)) Directory.CreateDirectory(directory);
|
if (!string.IsNullOrEmpty(directory)) Directory.CreateDirectory(directory);
|
||||||
|
|
||||||
// 편집 전 파일의 인코딩을 그대로 유지한다. (CP949 소스를 UTF-8 로 덮어쓰지 않도록)
|
// "원본" 은 워킹트리 파일이 아니라 <b>내 쪽(ours) blob</b> 이다(6차 A-1).
|
||||||
var encoding = File.Exists(fullPath)
|
// 충돌 중 워킹트리에는 git 이 LF 로 충돌 표시를 넣어 두어서, 그 파일을 보면 줄끝이 "혼합" 으로 읽힌다.
|
||||||
? DetectEncoding(File.ReadAllBytes(fullPath))
|
// 예전에는 인코딩만 워킹트리에서 보고 줄끝은 아예 안 봐서 CRLF 파일이 통째로 LF 가 됐다.
|
||||||
: new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
|
// 내 쪽이 없으면(내가 지운 파일) 상대 쪽, 그것도 없으면 공통 조상을 본다.
|
||||||
|
var conflict = Repo.Index.Conflicts[normalized];
|
||||||
|
var referenceBlob = conflict is null
|
||||||
|
? null
|
||||||
|
: LookupBlob(conflict.Ours) ?? LookupBlob(conflict.Theirs) ?? LookupBlob(conflict.Ancestor);
|
||||||
|
|
||||||
File.WriteAllText(fullPath, content, encoding);
|
var reference = referenceBlob is not null
|
||||||
|
? ReadBlobBytes(referenceBlob, normalized)
|
||||||
|
: File.Exists(fullPath) ? File.ReadAllBytes(fullPath) : null;
|
||||||
|
|
||||||
|
File.WriteAllBytes(fullPath, TextFile.Encode(content, encodingName, newLineName, reference));
|
||||||
Commands.Stage(Repo, normalized);
|
Commands.Stage(Repo, normalized);
|
||||||
Report($"충돌 해결(직접 편집, {encoding.WebName}): {normalized}");
|
|
||||||
|
var written = TextFile.Describe(fullPath);
|
||||||
|
Report($"충돌 해결(직접 편집, {written.Encoding} · {written.NewLine}): {normalized}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public string CommitMerge(string? message = null)
|
public string CommitMerge(string? message = null)
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using MergeHub.Models;
|
using MergeHub.Models;
|
||||||
|
|
||||||
@ -92,7 +92,12 @@ namespace MergeHub.Services
|
|||||||
TextFileInfo DescribeWorkingFile(string path);
|
TextFileInfo DescribeWorkingFile(string path);
|
||||||
|
|
||||||
/// <summary>편집기에서 직접 수정한 본문으로 해결.</summary>
|
/// <summary>편집기에서 직접 수정한 본문으로 해결.</summary>
|
||||||
void ResolveConflictWithContent(string path, string content);
|
/// <summary>
|
||||||
|
/// 충돌 파일을 이 글로 풀고 스테이징한다. 저장 형식이 "원본 유지"(또는 null)면 내 쪽(ours) 파일의
|
||||||
|
/// 인코딩과 줄끝을 따른다(6차 A-1).
|
||||||
|
/// </summary>
|
||||||
|
void ResolveConflictWithContent(string path, string content,
|
||||||
|
string? encodingName = null, string? newLineName = null);
|
||||||
|
|
||||||
/// <summary>충돌을 모두 해결한 뒤 병합 커밋 생성. 메시지 생략 시 기본 메시지 사용.</summary>
|
/// <summary>충돌을 모두 해결한 뒤 병합 커밋 생성. 메시지 생략 시 기본 메시지 사용.</summary>
|
||||||
string CommitMerge(string? message = null);
|
string CommitMerge(string? message = null);
|
||||||
|
|||||||
@ -76,16 +76,44 @@ namespace MergeHub.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static void Write(string path, string content, string? encodingName, string? newLineName)
|
public static void Write(string path, string content, string? encodingName, string? newLineName)
|
||||||
{
|
{
|
||||||
var encoding = ResolveEncoding(path, encodingName);
|
var reference = File.Exists(path) ? File.ReadAllBytes(path) : null;
|
||||||
var newLine = ResolveNewLine(path, newLineName);
|
File.WriteAllBytes(path, Encode(content, encodingName, newLineName, reference));
|
||||||
|
|
||||||
var text = content.Replace("\r\n", "\n");
|
|
||||||
if (newLine != "LF") text = text.Replace("\n", "\r\n");
|
|
||||||
|
|
||||||
File.WriteAllText(path, text, encoding);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Encoding ResolveEncoding(string path, string? name)
|
/// <summary>
|
||||||
|
/// 글을 저장할 바이트로 만든다. <b>"원본 유지" 가 무엇을 따를지</b>를 <paramref name="reference"/> 로 받는다.
|
||||||
|
///
|
||||||
|
/// 따로 뺀 까닭(6차 A-1) - 병합 충돌 중의 워킹트리 파일에는 git 이 LF 로 충돌 표시를 넣어 둔다.
|
||||||
|
/// 그 파일을 "원본" 으로 보면 줄끝이 "혼합" 이 되고, 충돌 해결 저장은 아예 줄끝을 안 봐서 전부 LF 로 썼다.
|
||||||
|
/// 3,363줄 CRLF 파일에서 12줄을 고쳤는데 git 에는 파일 전체가 바뀐 것으로 나왔다.
|
||||||
|
/// 원본이 무엇인지는 부르는 쪽이 제일 잘 안다 - 충돌이면 내 쪽(ours) blob, 보통이면 디스크의 파일.
|
||||||
|
///
|
||||||
|
/// 규칙
|
||||||
|
/// - 인코딩: 고른 값이 있으면 그것. "원본 유지" 면 원본에서 판별. 원본이 없으면 UTF-8(BOM 없음).
|
||||||
|
/// - 줄끝: 고른 값이 있으면 그것. "원본 유지" 면 원본에서 <b>가장 많은 것</b>. 원본에 줄끝이 없으면 CRLF.
|
||||||
|
/// - BOM: 인코딩이 BOM 을 가지면 맨 앞에 한 번만 붙인다. 글 첫머리의 U+FEFF 는 떼고 쓴다
|
||||||
|
/// (blob 을 그대로 풀면 BOM 이 글자로 딸려 와 두 번 붙는다).
|
||||||
|
/// </summary>
|
||||||
|
public static byte[] Encode(string content, string? encodingName, string? newLineName, byte[]? reference)
|
||||||
|
{
|
||||||
|
var encoding = PickEncoding(encodingName, reference);
|
||||||
|
var newLine = PickNewLine(newLineName, reference);
|
||||||
|
|
||||||
|
var text = (content ?? string.Empty).TrimStart('\uFEFF').Replace("\r\n", "\n");
|
||||||
|
if (newLine == "CRLF") text = text.Replace("\n", "\r\n");
|
||||||
|
else if (newLine == "CR") text = text.Replace("\n", "\r");
|
||||||
|
|
||||||
|
var body = encoding.GetBytes(text);
|
||||||
|
var preamble = encoding.GetPreamble();
|
||||||
|
if (preamble.Length == 0) return body;
|
||||||
|
|
||||||
|
var all = new byte[preamble.Length + body.Length];
|
||||||
|
Buffer.BlockCopy(preamble, 0, all, 0, preamble.Length);
|
||||||
|
Buffer.BlockCopy(body, 0, all, preamble.Length, body.Length);
|
||||||
|
return all;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Encoding PickEncoding(string? name, byte[]? reference)
|
||||||
{
|
{
|
||||||
switch (name)
|
switch (name)
|
||||||
{
|
{
|
||||||
@ -94,8 +122,8 @@ namespace MergeHub.Services
|
|||||||
case "CP949": return GetCp949();
|
case "CP949": return GetCp949();
|
||||||
}
|
}
|
||||||
|
|
||||||
return File.Exists(path)
|
return reference is { Length: > 0 }
|
||||||
? Detect(File.ReadAllBytes(path))
|
? Detect(reference)
|
||||||
: new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
|
: new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,10 +139,38 @@ namespace MergeHub.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string ResolveNewLine(string path, string? name)
|
private static string PickNewLine(string? name, byte[]? reference)
|
||||||
{
|
{
|
||||||
if (name == "CRLF" || name == "LF") return name;
|
if (name == "CRLF" || name == "LF") return name;
|
||||||
return File.Exists(path) ? Describe(path).NewLine : "CRLF";
|
if (reference is not { Length: > 0 }) return "CRLF";
|
||||||
|
|
||||||
|
return DominantNewLine(Detect(reference).GetString(reference));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 가장 많이 쓰인 줄끝. 줄끝이 하나도 없으면 CRLF(윈도우 사내 소스의 기본).
|
||||||
|
/// 같으면 CRLF · LF · CR 차례로 고른다.
|
||||||
|
///
|
||||||
|
/// "혼합" 을 그대로 두지 않는 까닭 - 저장은 한 가지로 해야 한다. 예전에는 혼합이면 무조건 CRLF 로 썼는데,
|
||||||
|
/// 거의 LF 인 파일에 CRLF 한 줄이 섞였을 때 파일 전체가 CRLF 로 바뀌었다.
|
||||||
|
/// </summary>
|
||||||
|
private static string DominantNewLine(string text)
|
||||||
|
{
|
||||||
|
int crlf = 0, lf = 0, cr = 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < text.Length; i++)
|
||||||
|
{
|
||||||
|
if (text[i] == '\r')
|
||||||
|
{
|
||||||
|
if (i + 1 < text.Length && text[i + 1] == '\n') { crlf++; i++; }
|
||||||
|
else cr++;
|
||||||
|
}
|
||||||
|
else if (text[i] == '\n') lf++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crlf == 0 && lf == 0 && cr == 0) return "CRLF";
|
||||||
|
if (crlf >= lf && crlf >= cr) return "CRLF";
|
||||||
|
return lf >= cr ? "LF" : "CR";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -613,7 +613,7 @@ namespace MergeHub.ViewModels
|
|||||||
if (isConflict)
|
if (isConflict)
|
||||||
{
|
{
|
||||||
// 충돌 해결 경로 - 인덱스의 충돌까지 함께 해제된다.
|
// 충돌 해결 경로 - 인덱스의 충돌까지 함께 해제된다.
|
||||||
_workspace.Git.ResolveConflictWithContent(path!, content);
|
_workspace.Git.ResolveConflictWithContent(path!, content, encoding, newLine);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -691,7 +691,7 @@ namespace MergeHub.ViewModels
|
|||||||
var isConflict = _workspace.Git.GetConflicts().Any(c => c.Path == path);
|
var isConflict = _workspace.Git.GetConflicts().Any(c => c.Path == path);
|
||||||
if (isConflict)
|
if (isConflict)
|
||||||
{
|
{
|
||||||
_workspace.Git.ResolveConflictWithContent(path!, content);
|
_workspace.Git.ResolveConflictWithContent(path!, content, encoding, newLine);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -2200,7 +2200,7 @@ namespace MergeHub.ViewModels
|
|||||||
if (conflictPath is not null && _workspace.IsMergeInProgress &&
|
if (conflictPath is not null && _workspace.IsMergeInProgress &&
|
||||||
_workspace.Git.GetConflicts().Any(c => c.Path == conflictPath))
|
_workspace.Git.GetConflicts().Any(c => c.Path == conflictPath))
|
||||||
{
|
{
|
||||||
_workspace.Git.ResolveConflictWithContent(conflictPath, content);
|
_workspace.Git.ResolveConflictWithContent(conflictPath, content, SaveEncoding, SaveNewLine);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user