글을 작성하게 된 계기
git rebase 명령을 사용하던 중, 원격 파일 과 로컬의 untracked 파일이 충돌 하며 rebase가 실패했습니다. 이를 해결하는 과정에서 알게 된 내용을 정리하기 위해 글을 작성하게 되었습니다.
1. 문제 상황
git fetch 로 원격 브랜치를 가져온 후, rebase를 진행하던 중 다음과 같은 에러가 발생했습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# fetch
$ git fetch origin dev
From https://github.com/click-io/server
* branch dev -> FETCH_HEAD
# rebase 후 에러 발생
$ git rebase origin/dev dev
error: The following untracked working tree files would be overwritten by checkout:
admin-app/README.md
config/schema/schema.sql
modules/storage/rdb/src/main/kotlin/project/io/rdb/core/article/entity/ArticleEmojiJpaEntity.kt
modules/storage/rdb/src/main/kotlin/project/io/rdb/core/customer/entity/CustomerSupportCategory.kt
modules/storage/rdb/src/main/kotlin/project/io/rdb/core/customer/entity/CustomerSupportJpaEntity.kt
modules/storage/rdb/src/main/kotlin/project/io/rdb/core/customer/infra/CustomerSupportJpaEntityWriteRepository.kt
modules/storage/rdb/src/main/kotlin/project/io/rdb/core/customer/repository/CustomerSupportEntityWriteRepository.kt
modules/storage/rdb/src/main/kotlin/project/io/rdb/core/user/entity/Grade.kt
modules/storage/rdb/src/main/kotlin/project/io/rdb/core/user/entity/Role.kt
modules/storage/rdb/src/main/kotlin/project/io/rdb/core/user/entity/UserProfileImageJpaEntity.kt
Please move or remove them before you switch branches.
에러 메시지를 읽어보면 rebase 중 원격 파일과 untracked 파일 간의 충돌 때문에 문제가 발생한 것을 알 수 있습니다. rebase는 다른 브랜치의 커밋을 적용하는 과정에서 현재 작업 디렉토리를 업데이트 합니다. 이 과정에서 원격에 있는 파일이 로컬의 untracked 파일과 동일한 이름으로 존재 해 이를 덮어쓰지 못하고 에러를 발생시킨 것입니다. 즉, rebase 과정에서 어떤 파일을 적용할지 판단할 수 없어서죠.
error: The following untracked working tree files would be overwritten by checkout
2. 해결 방법
rebase를 할 때, 원격 파일과 로컬의 untracked 파일 중 어떤 것을 선택할지 모르기 때문에 에러가 발생 했습니다. 따라서 먼저 stash 명령어로 untracked 파일을 묻어둔 후, 원격 파일을 우선 처리 했습니다. untracked 파일은 stage 상태가 아니기 때문 에, 원격 파일을 rebase 한 후, pop으로 처리하더라도 충돌이 발생하지 않는다고 판단 했기 때문입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# untracked 파일 stash
$ git stash --include-untracked
Saved working directory and index state WIP on dev: 49c47a6 [CIO-16] ArticleEmoji 클릭 API를 개발한다. (#32)
# rebase로 원격 파일 처리
$ git rebase origin/dev
Successfully rebased and updated refs/heads/dev.
# untracked 파일 pop
$ git stash pop
Already up to date.
admin-app/README.md already exists, no checkout
config/schema/schema.sql already exists, no checkout
modules/storage/rdb/src/main/kotlin/project/io/rdb/core/article/entity/ArticleEmojiJpaEntity.kt already exists, no checkout
......
modules/storage/rdb/src/main/kotlin/project/io/rdb/core/user/entity/UserProfileImageJpaEntity.kt already exists, no checkout
error: could not restore untracked files from stash
On branch dev
Untracked files:
(use "git add <file>..." to include in what will be committed)
admin-app/build.gradle.kts
buildSrc/
click-io-app/
......
scheduling-app/
nothing added to commit but untracked files present (use "git add" to track)
The stash entry is kept in case you need it again.
3. 다른 방법은 없었을까?
크게 untracked 파일을 백업 후 삭제 하는 방식과 untracked 파일을 stage 상태로 만든 후 rebase 하는 방식 두 가지를 떠올릴 수 있습니다.
강제 rebase를 할 수도 있지만, 이는 위험하기 때문에 권장하지 않습니다.
3-1. untracked 파일 백업 후 삭제
먼저 untracked 파일을 백업한 후, 삭제하는 방법을 떠올릴 수 있습니다. 로컬에 있는 파일이 원격과 중복되기 때문에 발생한 문제로, 로컬 파일을 제거하는 것이죠.
1
2
3
4
5
6
7
8
9
10
11
12
13
# untracked 파일 확인
$ git status --untracked-files
# backup 디렉토리 생성 후, untracked 파일 백업
$ mkdir ../backup
$ cp -r <untracked 파일 또는 폴더> ../backup
# untracked 파일 삭제
$ git clean -fd
# rebase 후 untracked 파일 복원
$ git rebase origin/dev
$ cp -r ../backup/* .
3-2. untracked 파일을 stage 상태로 만든 후 rebase
untracked 파일도 중요한 경우, 임시로 git에 추가 해 rebase 할 수 있습니다. 이 경우, rebase 과정에서 원격 파일과 untracked 파일 중, 어떤 것을 선택할지 선택해 문제를 해결할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
# untracked 파일 stage로 추가
$ git add .
$ git commit -m "Temporary commit"
# rebase
$ git rebase origin/dev
CONFLICT (content): Merge conflict in .....
# 충돌 해결 후 rebase 계속 진행
$ git add <filename>
$ git rebase --continue
4. 정리
rebase 과정 중, 원격에 있는 파일과 untracked 파일이 충돌해서 rebase가 실패하는 경우를 살펴보았습니다. rebase는 stage에만 영향을 받는 것으로 알고 있었는데, git이 어떤 것을 선택할지 모르면 untracked 파일에 대해서도 충돌이 발생합니다. 따라서 git이 어떤 것을 선택할지, 명확히 알 수 있도록 합시다.