Git 에서 'error: Your local changes would be overwritten by merge' 오류 해결 방법

GitBeginner
지금 연습하기

소개

Git 은 개발자가 코드를 관리하고 효과적으로 협업하는 데 도움이 되는 강력한 버전 관리 시스템입니다. 하지만 Git 을 처음 사용하는 경우 특히 혼란스러운 오류 메시지를 접할 수 있습니다. 흔히 발생하는 오류 중 하나는 "Your local changes would be overwritten by merge"입니다. 이 오류는 Git 이 커밋되지 않은 로컬 수정 사항을 덮어쓸 수 있으므로 안전하게 변경 사항을 병합할 수 없을 때 발생합니다.

이 Lab 에서는 이 오류의 원인, 해결 방법, 그리고 향후 Git 워크플로우에서 이 오류가 발생하지 않도록 방지하는 전략을 구현하는 방법을 배우게 됩니다.

Git 워크플로우 이해

병합 충돌을 해결하기 전에, 기본적인 Git 워크플로우를 이해하고 오류를 시연하기 위한 환경을 설정해 보겠습니다.

Git 이란 무엇인가

Git 은 여러 개발자가 서로의 작업에 간섭하지 않고 동일한 코드베이스에서 작업할 수 있도록 하는 분산 버전 관리 시스템입니다. Git 은 파일 변경 사항을 시간별로 추적하여 필요한 경우 이전 버전으로 되돌릴 수 있도록 합니다.

기본적인 Git 워크플로우

일반적인 Git 워크플로우는 다음 단계를 포함합니다.

  1. 작업 디렉토리에서 파일 수정
  2. git add로 변경 사항 스테이징 (staging)
  3. git commit으로 변경 사항 커밋 (commit)
  4. git push로 변경 사항을 원격 저장소로 푸시 (push)
  5. git pull로 변경 사항을 원격 저장소에서 풀 (pull)

시작해 봅시다

먼저, 프로젝트 디렉토리로 이동합니다.

cd /home/labex/project/git-merge-demo

저장소의 상태를 확인해 보겠습니다.

git status

다음과 유사한 출력을 볼 수 있습니다.

On branch main
nothing to commit, working tree clean

이제 어떤 브랜치가 있는지 확인해 보겠습니다.

git branch

다음과 같은 출력을 볼 수 있습니다.

  development
* main

별표 (*) 는 현재 main 브랜치에 있다는 것을 나타냅니다. 저장소의 파일을 살펴보겠습니다.

ls -la

다음과 같은 출력을 볼 수 있습니다.

total 20
drwxr-xr-x 3 labex labex 4096 ... .
drwxr-xr-x 3 labex labex 4096 ... ..
drwxr-xr-x 8 labex labex 4096 ... .git
-rw-r--r-- 1 labex labex   24 ... README.md
-rw-r--r-- 1 labex labex   27 ... script.js
-rw-r--r-- 1 labex labex   25 ... styles.css

이 파일들의 내용을 살펴보겠습니다.

cat README.md
cat script.js
cat styles.css

훌륭합니다! 이제 저장소의 구조를 이해했습니다. 다음 단계에서는 "local changes would be overwritten by merge" 오류를 생성하는 시나리오를 만들 것입니다.

병합 충돌 시나리오 생성

이 단계에서는 "Your local changes would be overwritten by merge" 오류로 이어지는 시나리오를 만들 것입니다. 이는 이 오류가 발생하는 이유를 이해하는 데 도움이 될 것입니다.

development 브랜치에서 변경 사항 만들기

먼저, development 브랜치로 전환하고 몇 가지 변경 사항을 만들어 보겠습니다.

git checkout development

다음과 같은 출력을 볼 수 있습니다.

Switched to branch 'development'

이제 script.js 파일을 수정해 보겠습니다.

echo "console.log('Hello from development branch!');" > script.js

이 변경 사항을 커밋해 보겠습니다.

git add script.js
git commit -m "Update script.js on development branch"

다음과 같은 출력을 볼 수 있습니다.

[development xxxxxxx] Update script.js on development branch
 1 file changed, 1 insertion(+), 1 deletion(-)

main 브랜치에서 커밋되지 않은 변경 사항 만들기

이제 다시 main 브랜치로 전환해 보겠습니다.

git checkout main

main 브랜치에 있는지 확인해 보겠습니다.

git branch

다음과 같은 출력을 볼 수 있습니다.

  development
* main

이제 main 브랜치에서 동일한 파일 (script.js) 을 수정하지만, 이번에는 변경 사항을 커밋하지 않겠습니다.

echo "console.log('Hello from main branch!');" > script.js

병합 충돌 오류 트리거

이제 작업 디렉토리에 커밋되지 않은 변경 사항이 있으므로 development 브랜치를 main 브랜치에 병합해 보겠습니다.

git merge development

다음과 유사한 오류 메시지를 볼 수 있습니다.

error: Your local changes to the following files would be overwritten by merge:
        script.js
Please commit your changes or stash them before you merge.
Aborting

축하합니다! "Your local changes would be overwritten by merge" 오류를 생성하는 시나리오를 성공적으로 만들었습니다.

이 오류는 다음과 같은 이유로 발생합니다.

  1. development 브랜치에서 script.js를 수정하고 변경 사항을 커밋했습니다.
  2. 또한 main 브랜치에서 script.js를 수정했지만 변경 사항을 커밋하지 않았습니다.
  3. 병합을 시도할 때 Git 은 커밋되지 않은 변경 사항이 병합 작업에 의해 덮어쓰여질 것임을 감지했습니다.

다음 단계에서는 이 오류를 해결하는 방법을 배우겠습니다.

Git Stash 를 사용하여 병합 충돌 해결하기

"Your local changes would be overwritten by merge" 오류를 해결하는 가장 일반적이고 유용한 방법 중 하나는 git stash를 사용하는 것입니다. git stash 명령은 커밋되지 않은 변경 사항을 임시로 저장하여 나중에 적용할 수 있도록 합니다.

Git Stash 란 무엇인가

git stash는 커밋되지 않은 변경 사항 (스테이징된 변경 사항과 스테이징되지 않은 변경 사항 모두) 을 가져와 나중에 사용할 수 있도록 저장한 다음 작업 복사본에서 변경 사항을 되돌리는 Git 명령입니다.

Git Stash 를 사용하여 오류 해결하기

git stash를 사용하여 커밋되지 않은 변경 사항을 저장해 보겠습니다.

git stash

다음과 유사한 출력을 볼 수 있습니다.

Saved working directory and index state WIP on main: xxxxxxx Initial commit

이 메시지는 변경 사항이 저장되었음을 확인합니다. 이제 작업 디렉토리가 깨끗한지 확인해 보겠습니다.

git status

다음과 같은 출력을 볼 수 있습니다.

On branch main
nothing to commit, working tree clean

이제 script.js의 내용을 확인해 보겠습니다.

cat script.js

원래 내용을 볼 수 있습니다.

console.log('Hello, Git!');

development 브랜치 병합

이제 작업 디렉토리가 깨끗하므로 development 브랜치를 안전하게 병합할 수 있습니다.

git merge development

다음과 같은 출력을 볼 수 있습니다.

Updating xxxxxxx..xxxxxxx
Fast-forward
 script.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

script.js의 내용을 다시 확인해 보겠습니다.

cat script.js

이제 다음을 볼 수 있습니다.

console.log('Hello from development branch!');

Stashed 변경 사항 검색

이제 development 브랜치를 성공적으로 병합했으므로 stashed 변경 사항을 검색해 보겠습니다.

git stash list

다음과 같은 출력을 볼 수 있습니다.

stash@{0}: WIP on main: xxxxxxx Initial commit

이는 하나의 stash 가 저장되었음을 보여줍니다. 이를 적용해 보겠습니다.

git stash apply

충돌 메시지가 표시될 수 있습니다.

Auto-merging script.js
CONFLICT (content): Merge conflict in script.js

이는 Git 이 병합된 파일 위에 stashed 변경 사항을 적용하려고 하기 때문에 정상입니다. script.js의 내용을 확인해 보겠습니다.

cat script.js

다음과 같은 내용을 볼 수 있습니다.

<<<<<<< Updated upstream
console.log('Hello from development branch!');
=======
console.log('Hello from main branch!');
>>>>>>> Stashed changes

이는 수동으로 해결해야 하는 병합 충돌입니다. nano 를 사용하여 파일을 엽니다.

nano script.js

두 변경 사항을 모두 유지하거나 하나를 선택하도록 파일을 편집합니다.

// Keep both changes
console.log("Hello from development branch!");
console.log("Hello from main branch!");

Ctrl+O를 누르고 Enter를 눌러 파일을 저장하고, Ctrl+X를 눌러 nano 를 종료합니다.

이제 해결된 충돌을 스테이징하고 커밋해 보겠습니다.

git add script.js
git commit -m "Merge development branch and resolve conflict"

축하합니다! git stash를 사용하여 "Your local changes would be overwritten by merge" 오류를 성공적으로 해결했습니다.

병합 오류를 해결하는 다른 방법

이전 단계에서는 "Your local changes would be overwritten by merge" 오류를 해결하기 위해 git stash를 사용했습니다. 이 단계에서는 이 상황을 처리하는 다른 접근 방식을 살펴보겠습니다.

방법 1: 병합 전에 변경 사항 커밋하기

"Your local changes would be overwritten by merge" 오류를 방지하는 가장 간단한 방법 중 하나는 병합 작업을 수행하기 전에 변경 사항을 커밋하는 것입니다.

이를 시연하기 위해 다른 시나리오를 만들어 보겠습니다. 먼저 styles.css 파일을 수정해 보겠습니다.

echo "body { background-color: #f0f0f0; }" > styles.css

이제 변경 사항을 stashing 하는 대신 커밋해 보겠습니다.

git add styles.css
git commit -m "Update styles.css on main branch"

다음과 같은 출력을 볼 수 있습니다.

[main xxxxxxx] Update styles.css on main branch
 1 file changed, 1 insertion(+), 1 deletion(-)

이제 development 브랜치로 전환하여 동일한 파일을 변경하고 커밋해 보겠습니다.

git checkout development
echo "body { background-color: #e0e0e0; }" > styles.css
git add styles.css
git commit -m "Update styles.css on development branch"

이제 다시 main 브랜치로 전환해 보겠습니다.

git checkout main

이제 병합을 시도하면 변경 사항을 커밋했으므로 "local changes would be overwritten" 오류가 발생하지 않습니다. 그러나 병합 충돌이 발생할 수 있습니다.

git merge development

다음과 같은 출력을 볼 수 있습니다.

Auto-merging styles.css
CONFLICT (content): Merge conflict in styles.css
Automatic merge failed; fix conflicts and then commit the result.

이는 두 브랜치 모두 파일의 동일한 부분에 대한 변경 사항을 커밋했을 때 발생하는 다른 종류의 충돌입니다. 이 충돌을 해결해 보겠습니다.

cat styles.css

다음과 같은 출력을 볼 수 있습니다.

<<<<<<< HEAD
body { background-color: #f0f0f0; }
=======
body { background-color: #e0e0e0; }
>>>>>>> development

파일을 편집하여 충돌을 해결해 보겠습니다.

nano styles.css

내용을 다음과 같이 변경합니다.

body {
  background-color: #f5f5f5;
}

파일을 저장하고 해결된 충돌을 커밋합니다.

git add styles.css
git commit -m "Resolve merge conflict in styles.css"

방법 2: Git Checkout 을 사용하여 로컬 변경 사항 폐기하기

또 다른 방법은 더 이상 필요하지 않은 경우 로컬 변경 사항을 단순히 폐기하는 것입니다.

## Create a change to README.md
echo "## Updated README" > README.md

## Check the status
git status

다음과 같은 출력을 볼 수 있습니다.

On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")

이러한 변경 사항이 필요하지 않다고 결정한 경우 폐기할 수 있습니다.

git checkout -- README.md

상태를 다시 확인해 보겠습니다.

git status

다음과 같은 출력을 볼 수 있습니다.

On branch main
nothing to commit, working tree clean

그리고 README.md 의 내용은 원래 상태로 복원되었습니다.

cat README.md

이러한 대체 방법은 특정 상황과 요구 사항에 따라 "Your local changes would be overwritten by merge" 오류를 처리할 수 있는 다양한 옵션을 제공합니다.

병합 충돌을 방지하기 위한 모범 사례

이제 "Your local changes would be overwritten by merge" 오류를 해결하는 방법을 알았으므로, 이 문제가 처음부터 발생하지 않도록 하기 위한 몇 가지 모범 사례에 대해 논의해 보겠습니다.

1. 변경 사항을 자주 커밋하기

작고 빈번한 커밋을 수행하면 병합 충돌의 가능성을 줄이는 데 도움이 됩니다.

## Make a small change
echo "// Add a comment" >> script.js

## Commit the change
git add script.js
git commit -m "Add a comment to script.js"

2. Push 전에 Pull 하기

변경 사항을 푸시하기 전에 항상 원격 저장소에서 변경 사항을 pull 하십시오.

## In a real scenario, you would do:
## git pull origin main
## Since we're working locally, let's simulate this by checking out development and back
git checkout development
git checkout main

3. Feature Branch 사용하기

각 기능 또는 버그 수정에 대해 새 브랜치를 만듭니다.

## Create a new feature branch
git checkout -b feature-navbar

## Make some changes
echo "/* Navigation bar styles */" >> styles.css

## Commit the changes
git add styles.css
git commit -m "Add navigation bar styles"

main 브랜치로 돌아가 보겠습니다.

git checkout main

4. Main 브랜치와 정기적으로 병합 또는 리베이스하기

feature 브랜치를 main 브랜치와 최신 상태로 유지합니다.

## Switch to the feature branch
git checkout feature-navbar

## In a real scenario, you would merge or rebase with main:
## git merge main
## or
## git rebase main

## For our demonstration, let's simulate this
echo "/* More styles */" >> styles.css
git add styles.css
git commit -m "Add more styles"

## Go back to main
git checkout main

5. Git Status 를 자주 사용하기

병합 또는 pull 과 같은 작업을 수행하기 전에 항상 저장소의 상태를 확인하십시오.

git status

다음과 같은 출력을 볼 수 있습니다.

On branch main
nothing to commit, working tree clean

6. 팀과 소통하기

이것을 실습 환경에서 시연할 수는 없지만, 소통은 충돌을 피하는 데 중요합니다. 팀이 어떤 파일을 작업하고 있는지 확인하여 동일한 파일에 대한 동시 변경을 방지하십시오.

7. 복잡한 병합에 GUI 도구 사용하기

복잡한 병합 충돌의 경우 GUI 도구 사용을 고려하십시오.

## List available GUI merge tools (in a real environment)
## git mergetool --tool-help

## In our case, let's just display what merge tools are typically available
echo "Common merge tools: meld, kdiff3, vimdiff, vscode"

이러한 모범 사례를 따르면 Git 워크플로우에서 병합 충돌 및 "Your local changes would be overwritten by merge" 오류의 발생을 크게 줄일 수 있습니다.

요약

이 실습에서는 Git 에서 "Your local changes would be overwritten by merge" 오류를 해결하는 방법을 배웠습니다. 이는 작업 디렉토리에 커밋되지 않은 수정 사항이 있는 상태에서 변경 사항을 병합하거나 pull 하려고 할 때 발생하는 일반적인 문제입니다.

이 실습에서 다룬 주요 내용은 다음과 같습니다.

  1. 서로 다른 브랜치에서 동일한 파일을 변경하여 "Your local changes would be overwritten by merge" 오류를 트리거하는 시나리오를 만들었습니다.

  2. 이 오류를 해결하는 여러 가지 방법을 배웠습니다.

    • git stash를 사용하여 변경 사항을 임시로 저장
    • 병합 전에 변경 사항을 커밋
    • git checkout을 사용하여 원치 않는 로컬 변경 사항을 폐기
  3. 병합 충돌을 방지하기 위한 모범 사례를 살펴보았습니다.

    • 빈번하고 작은 커밋을 수행
    • 푸시 전에 pull
    • feature branch 사용
    • main 브랜치와 정기적으로 병합 또는 리베이스
    • git status를 자주 사용
    • 팀과 소통
    • 복잡한 병합에 GUI 도구 사용

이러한 개념과 기술을 이해함으로써 Git 워크플로우를 보다 효율적으로 관리하고 병합 충돌로 이어지는 일반적인 함정을 피할 수 있습니다.

Git 은 버전 관리 및 협업을 위한 강력한 도구이지만, 충돌을 방지하려면 변경 사항을 신중하게 관리해야 합니다. 이 실습에서 배운 기술은 다른 사람들과 효과적으로 협업하면서 코드베이스의 무결성을 유지하는 데 도움이 될 것입니다.