동기
(작성일: 2024.06.13)
`Github`에서 `main` 브랜치에서 팀원과 코드를 병합하던 중
최종 단계인 `main` 브랜치 이전 단계의 `develop` 브랜치의 필요성을 느꼈다.
코드를 병합하던 `main` 브랜치의 이름을 `develop` 브랜치로 변경하고
새롭게 `main` 브랜치를 만들어 개발 완료한 코드를 `develop` 브랜치에서 병합하여
최종적으로 `main` 브랜치에 `push`하는 방식으로 변경했다.
명령어
git checkout main
git pull origin main
git checkout -b develop
git push -u origin develop
# 모든 파일 삭제
git rm -rf .
# 모든 로컬 변경사항 및 파일을 버림
git reset --hard
git clean -fdx
# 현재 main 브랜치에서 모든 커밋을 삭제하고 완전히 새로운 커밋을 생성
git checkout --orphan new-main
# 초기 커밋 만들기
git commit -am "[Init] 초기 설정"
# 기존의 main 브랜치를 삭제하고, 새로운 브랜치를 main으로 이름 변경
git branch -D main
git branch -m new-main main
# 원격 main 브랜치에 강제 푸시 (주의: 이 작업은 원격 브랜치의 이력을 변경)
git push -f origin main
우선 `local`에 있는 `main``브랜치를 최신 버전으로 업데이트하기 위해
원격 브랜치로부터 `pull`한다.
git checkout feature/payment
그리고 현재까지 구현이 끝난 버전이 `AWS`에 배포되어 있는데 최종 코드가 결제 기능까지 구현되어 있다.
그 코드는 최종적으로 기존의 `main` 브랜치에 `pull request`를 할 때
`feature/payment` 브랜치로부터 한 것이기 때문에 `feature/payment`로 브랜치를 변경한다.
git rebase main
그리고 `feature/payment` 브랜치를 `main` 브랜치에 `rebase`한다.
이 때, 충돌이 발생하는데 수동으로 해결해야 한다.
git add <충돌난 파일>
git rebase --continue
git push -f origin feature/payment
모든 충돌이 해결되고 리베이스가 완료되면,
`feature/payment` 브랜치의 커밋들이 `main` 브랜치의 최신 커밋 다음에 위치한다.
목표
하고자 하는 작업을 다시 정리하면,
기존의 `main` 브랜치는 코드를 병합하는 브랜치이자 최종 배포하는 코드를 올려놓는 브랜치였다.
이 `main` 브랜치를 `develop` 브랜치로 이름을 변경하고 새로운 `main`브랜치를 만든 후,
구현이 완료되어 배포한 버전을 최종 `push`하는 용도로 변경하려는 것이다.
문제 발생
새로운 `main` 브랜치를 어떤 파일도, 커밋 내역도 없는 깨끗한 브랜치로 만들고
기존의 `main` 브랜치는 현재 개발을 진행 중인 내역이 포함되어 있기에
개발이 완료된 내역들만 새롭게 만들어진 `main` 브랜치에 `push`하려고 했다.
그러다 보니 새롭게 생긴 `main` 브랜치는 기존의 개발 중이던 브랜치들과 `history`가 다르기 때문에
새로운 `main` 브랜치에 코드를 `pull request`할 때 아래의 에러가 발생했다.
There isn’t anything to compare.
main and feature/payment are entirely different commit histories.
어찌보면 당연한 것이, 새롭게 만들어진 `main` 브랜치는 당연히 `commit` 내역이 브랜치 생성 후,
원격 브랜치에 처음 `push`할 때 `commit`한 내역밖에 없기 때문에
기존에 개발을 할 때 사용하던 브랜치와 `commit history`가 다를 수 밖에 없는 것이다.
git merge develop --allow-unrelated-histories
그래서 위와 같은 방식으로 `feature/payment` 브랜치에 있는 상태에서
새롭게 만들어진 `main` 브랜치로 강제 병합하는 방법도 있고,
`patch`를 만들어서 병합 시 `commit history`가 다른 문제를 해결하는 방식이 있다.
현재 상황에서 강제 병합을 해도 큰 문제는 분명히 없지만
그래도 찜찜하고, 백업을 했지만 혹시 모를 문제를 방지하기 위해 사용하지는 않았다.
그래서 결과적으로 `rebase`를 하는 방식을 사용해서
`commit history`를 맞추는 방식으로 브랜치 변경 작업을 진행했다.
rm -fr ".git/rebase-merge"
만약 `rebase` 과정에 에러가 발생한다면,
위 명령어를 통해 `rebase` 디렉토리를 삭제하고 다시 시도하면 된다.
그래서 순차적으로 진행한다면,
아마도 기존의 `main`브랜치에서 `develop` 브랜치를 만드는 방식으로 이름을 변경하고
기존의 `main` 브랜치는 파일과 커밋 내역을 삭제해 초기화하는 과정까지는 문제가 발생하지 않을 것이다.
- `main` (파일, 커밋 내역 x)
- `develop` (기존의 main 브랜치와 같은 버전)
- `feature/payment` (개발 완료된 코드 o)
그러면 이 상태를 가진 브랜치 3개가 존재하게 된다.
그리고 이 `feature/payment` 브랜치의 코드를 `main` 브랜치로 `pull request`를 해야 하는 상황에서
`commit history`가 불일치하는 문제가 발생하게 되는 것이다.
이 때 `feature/payment` 브랜치인 상태에서 `main` 브랜치와 `rebase`를 하면,
두 브랜치가 같은 `commit history`를 갖게 된다.
그러면 비로소 `feature/payment` 브랜치에서 새로운 `main` 브랜치로 `pull request`를 할 수 있다.
`develop` 브랜치도 당연히 `feature/payment`와 마찬가지로 추후 개발이 완료되면
새로운 `main` 브랜치로 `pull request`를 해야하기 때문에,
`rebase`를 하여 `commit history`를 맞춰주는 것으로 작업을 마무리했다.
`rebase`를 하는 과정에서 `conflict`가 많이 발생한다.
그러면 새롭게 `incoming`하는 코드를 `accept`하여 `merge conflict`를 일일히 해소한 후
`pull request`를 하면 된다.
느낀점
사실 이전에 프로젝트를 진행할 때는 처음부터
`main - develop - 기능 별 각 브랜치`
이 틀을 만들고 개발을 했기 때문에 위와 같은 작업을 할 필요가 없었다.
하지만 이번에 이전에 진행했던 프로젝트의 `refactoring`을 진행하면서
위 구조 설계를 생략하고 바로 `main` 브랜치에서 코드를 병합하는 방식으로 개발을 진행했다.
그 결과, 매우 불편했고 그리고 구조 개선의 필요성을 느껴 `main` 브랜치를 변경하는 작업을 진행했다.
이렇게 다시 구조를 바꾸고 나니, 개발을 완료하여 코드를 `develop` 브랜치에서 병합하고
테스트를 끝낸 후, 배포까지 진행할 때 `develop` 브랜치에서 `main` 브랜치로 `pull request`를 하여
최종적으로 코드를 반영하고, 배포한 코드의 `release`까지 편하고 체계적으로 할 수 있게 되었다.
그리고 `git` 명령어에서 `merge`와 `rebase` 등을 많이 사용했지만
명확한 차이를 기억하고, 이해하여 사용한 것은 아니었다.
하지만 이번 브랜치 정리 작업을 직접 진행하면서 확실히 알게 되었다.
한 마디로, 처음에 개발을 할 때 병합하는 용도의 브랜치까지 만들고 개발을 하는 것이
역시 편하다는 것을 다시 한 번 깨닫게 되었다. 😤
'Git & Github' 카테고리의 다른 글
[Github] 가비아 도메인 + Github Pages 호스팅 (0) | 2025.05.15 |
---|---|
[Github] Github README.md 꾸미기 (0) | 2025.05.14 |