문제상황설명
절차지향적으로 요구사항에 만족하는 구현을 한 뒤, 객체지향적으로 클래스와 기능을 나누려고 하였다.
그러기위해 절차지향적인 구현을 V1
이라는 브랜치를 파서 구현을 완료하고 main
브랜치에 병합을 하고V2
라는 브랜치를 다시 파서 V2
브랜치에서 객체지향적으로 분리하려고 계획했었다.
하지만 기능명세에 명세된 단위로 커밋을 남겼어야 했는데 V1
에서 모든 기능의 구현을 완료한 뒤 "요구사항을 만족하는 구현 완료"라는 커밋메시지로 한 번에 커밋을 했고main
브랜치로 V1
을 병합까지 해버린 상태이다.
문제를 해결하면서 고려해야할 사항은
- 이미 병합된 상태로
push
되어버린main
브랜치는 어떻게 해야하는가 - "요구사항을 만족하는 구현 완료"라고 커밋한 하나의 큰 커밋 단위를 어떻게 작게 나누어야하는가
해결해보기
이미 push된 커밋을 되돌리기git revert
git revert
는 원격 저장소에 push된 커밋을 로컬 저장소로 되돌린다
현재 나는 merge
된 commit
을 되돌리려고 하고있기때문에 이 때는 반드시 -m 옵션을 사용하여 어느 부모를 기준으로 merge
를 되돌릴지 명시해야합니다.-m 1
: 현재 브랜치의 커밋을 기준으로 되돌린다-m 2
: 병합된 브랜치(V1
)의 기준으로 커밋을 되돌린다
일반적으로 병합 이전의 현재 브랜치 상태로 되돌릴때 사용하기때문에 -m 1
옵션을 사용해주면 된다.
-m 1
옵션을 넣고 명령어를 실행하니 아래와 같은 에러가 발생했다.
error: Your local changes to the following files would be overwritten by merge:
src/main/java/racingcar/RacingCar.java
Please commit your changes or stash them before you merge.
Aborting
fatal: revert failed
로컬에 수정된 파일이 있기때문에 되돌리기를 수행할 수 없는 에러 메시지인데, revert
를 하기전에는 반드시 로컬에 수정된 내용이 있어서는 안되는 것 같다.
나의 경우에는 V1
브랜치에서 추가로 예외 상황을 구현하고 있었기때문에 이런 문제가 발생한듯하다.
이 문제를 해결하려면 stash
를 사용하여 현재 로컬 변경사항을 임시로 저장하고 git revert
를 실행한 뒤 임시 저장한 내용을 다시 불러오는 것이다.
이제 아래 명령어를 순서대로 실행해준다git stash
git revert -m 1 <hash log>
되돌리기를 완료했으면 push
를 통해서 원격 저장소에 revert
된 내용을 반영해주어야 한다
여기까지 완료했으면 현재 상태를 잠시 확인해보자
revert
를 통해 merge
이전의 상태로 돌아온 것 같지만 정확히 말하자면 merge
이전의 상태의 커밋을 새로 만든 것이다.
A -> B -> A` 같은느낌?
이제 git stash pop
명령어를 통해 임시저장해둔 변경 내용을 가져오자
그러면 merge
push
한 후의 구현했던 예외처리 로직을 가져오게 된다
commit단위를 쪼개기
이제 원격 저장소에 잘못 푸쉬를 되돌리는 전처리 과정을 마쳤고
이 문제의 본질이었던 commit을 쪼개야한다.
코드라인수는 120라인 정도 되었는데 클래스를 쪼개두지 않고 main()
메서드에 모두 구현해놓아서 코드를 읽어가며 commit단위를 쪼개는게 쉬운일이 아니었다..
1시간정도는 사용한 것 같았다
먼저 "요구사항을 만족하는 구현완료"의 커밋 메시지를 날렸던 커밋의 브랜치로 switch
해주어야한다
그리고 해당 커밋을 reset
해야하는데 필자는 revert
명령어로 이미 merge
되기 전의 상태이기때문에 "요구사항을 만족하는 구현완료"라는 메시지를 갖은 커밋이 바로 직전의 커밋이었기때문에 git reset HEAD~1
명령어를 사용하여 직전의 커밋을 스테이징 해제하였다
스테이징 해제 상태가되면 코드를 구현했던 그 상태로 돌아온 것이다git add -p
명령어를 사용하여서 커밋하고자하는 단위 즉, 구현한 기능 단위대로 add
하여 스테이징으로 올리고 커밋메시지를 적어 커밋을 날려주면된다.
git add -p
를 사용하면 작성한 모든 코드가 보여지게 되는데 이 코드를 vim으로 일일이 코드를 읽어가며 구현한 기능의 단위를 남기고 커밋을 날리고의 반복이다
git add -p
명령어를 실행하면 아래와 같은 질문을 받을 것이다(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,s,e,?]?
y
: 해당 변경사항을 통째로 스테이징n
: 해당 변경 사항을 스테이징 하지 않고 다음 Chunk로 넘어감s
: 더 작은 단위로 변경사항을 나누어 보여줌q
: 중단하고 나머지는 스테이징 하지 않음e
: Chunk를 직접 편집할 수 있는 모드로 전환
필자의 경우에는 모든 기능의 구현을 통째로 커밋했기때문에e
옵션으로 커밋단위를 하나씩 만들어가며 작업했다
e
옵션을 통해 작업할 때 주의할 사항이 몇 가지 있었다
error: patch failed: src/main/java/racingcar/RacingCar.java:10
error: src/main/java/racingcar/RacingCar.java: patch does not apply
error: 'git apply --cached' failed
Your edited hunk does not apply. Edit again (saying "no" discards!) [y/n]?
커밋 단위를 수정하던 중에 위의 에러 메시지를 받게 되었는데 이미 커밋된 내용을 수정하면 위와 같은 메시지를 받게 될 것이다
이 문제는 원래 파일의 내용과 일치하지 않기때문에 발생하는 문제로 merge시에 충돌이 발생하는 것과 비슷한 개념인 것 같다
n
을 입력하면 편집 내용을 취소하고 해당 chunk를 건너뛰게 됩니다
따라서 y
를 입력해 다시 수정해야합니다
+ */
System.out.println("경주할 자동차 이름을 입력하세요");
String inputCarNames = Console.readLine();
+ validateInputCarNames(inputCarNames);
+
이런식으로 vim편집기에서 +가 표시된 라인은 원래 파일에서 추가된 부분으로 해당 라인을 지워서 스테이징 하거나 남겨두어서 스테이징 처리 해주어야합니다
-가 표시되었을 경우 삭제된 라인으로 이 라인을 스테이징 하려면 그대로 두고 스테이징하지 않으려면 삭제해야합니다
아무것도 표시되지 않은 줄은 원본파일의 라인이기때문에 편집하지 않고 그대로 두어야합니다
이 작업을 반복하면 모든 커밋단위를 쪼갤수 있고 이제 다시 V1브랜치를 main브랜치로 병합하면된다!
다 끝났다 생각하고 병합을 하니 또 충돌이 발생해버려서 확인해보니main
브랜치에서 구현한 파일이 삭제되어있어서 충돌이 발생했다
다행히 파일 자체가 있고 없고의 충돌이었기때문에 V1
브랜치의 구현한 파일을 main
브랜치로 유지하는 방식으로 충돌도 깔끔하게 해결하였다
부록
vim편집기를 통해 많은 양의 텍스트를 수정해본게 이번이 처음이었는데 덕분에 vim편집기를 다루는 법을 조금 배울 수 있었다
- 페이지 넘기기: page down
- 페이지 위로: page up
wq
: 저장후 종료q!
: 저장하지 않고 종료dd
: 커서 라인삭제Ndd
: N개의 라인 삭제10, 20d
: 10~20의 라인삭제u
: 되돌리기ctrl + r
: 되돌리기를 취소- 라인삭제 명령어 같은 경우에는 INSERT모드가 아닌 명령 모드상태에서 입력해야한다 (ESC누르면 명령모드)*
'Git' 카테고리의 다른 글
[Git] gitignore와 관리해야할 파일 (1) | 2024.11.08 |
---|---|
[Git] Commit Message Conventions (3) | 2024.10.30 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!