일주일동안 나는 옷장을 관리하는 Closet API를 설계하였고, 팀원은 회원을 관리하는 User API를 설계하였다. 우리는 각각 다른 브랜치 feature/closet과 feature/user 에서 작업하였고, 상위 브랜치인 dev에 merge하여 작업을 이어나갔다.
우선 내가 설계한 API를 PR을 올려서 Rebase & Merge 후 팀원의 API를 PR을 올려 같은 방식으로 Merge를 시도했다. 하지만, 내 PR은 정상 작동했지만, 팀원의 PR은 Rebase & Merge가 작동하지 않았다.
첫 번째 원인은 .gitignore을 사용하지 않았다. 각각의 컴퓨터에는 그에 맞는 다양한 환경변수들과 요소들을 저장한 파일들이 있다. 예를 들면 .idea, .gradle, .git, .DS_Store 등이 있다. 이러한 파일들은 모든 사람마다 각각 다 다른 내용이기 때문에 이 파일들을 포함해서 Push하게 되면 나중에 다른 사람과 협업할 때 내용 불일치로 충돌이 발생할 수 있다. 따라서 .gitignore을 생성하고
# IntelliJ IDEA
.idea/
*.iml
# OS
.DS_Store
# Gradle
.gradle/
build/
# Logs
*.log
와 같은 내용을 삽입한 뒤 본인의 레포지토리에 Push 하면 된다. 이렇게 되면 깃허브는 더 이상 .gitignore에 명시된 파일을 커밋 대상으로 지정하지 않는다.
하지만, 이미 깃허브에 파일을 올린 상태에서 뒤늦게 .gitignore을 추가했을 수도 있다. .gitignore의 적용 범위는 깃허브에 Push된 이후부터 적용되므로 이미 레포지토리에 올려진 파일에는 적용되지 않는다. 따라서 Git 추적에서 제거해야 한다.
git rm -r --cached .idea
git rm -r --cached build
git rm -r --cached .gradle
등등, 수동으로 추적에서 제거하면 된다. 이때 깃허브의 레포지토리에서만 삭제되고, 본인의 원본 로컬 파일은 삭제되지 않고 그대로 있으니 안심해도 된다.
두 번째 요인은 build.gradle 문제였다.
나는 Closet API를 구현했기 때문에 기본적인 dependency만 추가했지만, 회원가입을 다루는 API는 JWT 등 더 많은 dependency를 추가하여 build.gradle 파일이 다르게 되었다. 그렇다고 이 파일을 .gitignore에 추가할 순 없다. build.gradle이 없으면 다른 사람이 클론해서 바로 실행해볼 수 없기 때문이다.
여기서 느낀 점은, 미리 build.gradle, 즉, 자바 버전, 스프링 부트 버전은 물론이고 어떤 dependency를 부여할 것인지 팀끼리 미리 논의하고 합의하는것이 중요하다고 느꼈다.
이런 돌이킬 수 없는 요인들이 합쳐져서 Rebase & Merge가 불가능해졌다.
결국 Rebase & Merge를 포기하고 단순 Merge Commit 방식으로 PR을 올렸다.