1. git push 전에 git pull을 해야하는 경우가 많다
이번엔 git push를 하면서 자주 만나는 상황을 알아보겠다.
premium 브랜치의 license 파일에 기업용 가격에 대한 내용을 추가하고, premium 브랜치에 커밋까지 완료했다.
깃허브의 premium 브랜치 license 파일에는 교육용 가격에 대한 정보를 추가하고 커밋메세지를 남겨 주었다.
그러면 현재는 로컬 레포지토리와 리모트 레포지토리의 최신 커밋 내용이 각각 다르다. 로컬 레포지토리에는 기업용 가격에 대한 정보가, 리모트 레포지토리에는 교육용 가격에 대한 정보가 추가되어있다. 이렇게 한 프로그램을 각각 다른 개발자가 다른 방식으로 개발하는 일은 매우 흔하다.
이 상태에서 로컬 레포지토리에서 리모트 레포지토리에 git push를 하면 push가 되지 않는다.
로컬 레포지토리를 수정하는 중에 리모트 레포지토리에 변화가 생겼다면, 바로 git push가 되지 않는다.
이때는 일단 git pull을 해야한다. 그런데 이번에도 뭔가 에러가 뜬다. 중간에 보니 낯익은 에러 메시지가 뜬다?!
git pull을 하면 리모트 레포지토리의 최신 커밋들을 로컬 레포지토리로 가져와 그것을 그대로 merge 한다. 그러므로 conflict가 발생할 수 있다. 이는 예전에 conflict를 해결한 방법대로 하면 된다.
conflict가 발생한 license 파일을 보면 예전에 봤던 표시가 뜨고 있다. 내가 원하는 내용대로 수정하면 된다.
나는 기업용, 교육용 가격 정보가 모두 필요하므로 필요없는 부분만 제거해 주고 그대로 저장했다.
그런 후 커밋, git push 까지 완료!
깃허브에서 확인해보면 리모트 레포지토리에도 잘 반영되어 있다.
사실 git pull은 리모트 레포지토리 브랜치를 가져와서 현재 브랜치에 merge 하는 커맨드이다. 따라서 merge conflict가 뜨기도 한다.
여러 개발자가 협업하는 과정에서 주로 겪는 상황이다. 다른 개발자가 리모트 레포지토리를 가져가서 수정 후 git push 했다면, 나는 바로 git push 하지 못하고 git pull 한 후에 git push를 해줘야 한다. 이 과정에서 conflict가 발생한다면 해결한 후 다시 커밋을 하고 git push를 해주면 된다.
2. git pull말고 git fetch도 있다
브랜치를 가져온다는 건, 브랜치가 가리키고 있는 커밋 이전에 이루어진 모든 커밋들을 가져온다는 뜻이다. 이때 git fetch 커맨드는 merge 하지 않고 가져오기 단계까지만 해 준다. 보통 리모트 레포지토리에 있는 브랜치의 내용을 일단 가져와서 살펴본 후에 머지하고 싶을 때 사용한다.
예를 들어 신입 개발자가 calculator.py 파일을 잘못된 방향으로 바꿨다고 생각해보자. 아래와 같이 수정했다고 가정해보았다.
say hello 함수는 계산기에는 전혀 어울리지 않는 함수이다. 만약 git bash에서 git pull을 한다면? 자동으로 say hello 함수가 merge될 것이다.
git fetch를 사용하면 origin에 있던 premium 브랜치의 커밋이 로컬 레포지토리로 들어오게 된다.
이제 로컬 레포지토리와 리모트 레포지토리의 premium 브랜치 간의 차이를 비교해보겠다. git diff 를 사용하면 두 커밋 간의 차이 뿐만 아니라 두 브랜치 간의 차이도 볼 수 있다.
로컬 레포지토리의 premium 브랜치와 리모트 레포지토리의 premium 브랜치를 비교했을 떄, 리모트 레포지토리에 계산기에 어울리지 않는 say_hello 함수가 추가되어 있는것을 확인할 수 있다.
여기서 해결 방법은 두 가지가 있다.
- 잘못된 코드를 추가한 개발자에게 함수를 지우고 다시 리모트 레포지토리에 올려달라고 하기
- 내가 잘못된 부분을 알아서 해결하고 다시 git push하기
이 상태에서 리모트 레포지토리의 premium 브랜치를 merge하겠다.
그리고 calculator.py 파일에서 say_hello 함수를 삭제한 후 커밋하겠다.
그런 다음 git push 하면 리모트 레포지토리에도 say_hello 함수가 삭제되어 있을 것이다.
정리해보면 git fetch는!!
- 리모트 레포지토리에서 가져온 브랜치의 내용을 머지하기 전에 점검해야할 필요가 있을 때 사용
- 리모트 레포지토리에 있는 브랜치의 내용과 내가 작성한 코드를 비교해서 잘못된 부분이 없는지 검토해야할 때 사용
git pull = git fetch + merge 라고 생각할 수 있다.
git pull은 리모트 레포지토리의 브랜치를 검토할 필요없이 바로 합치고 싶을 때,
git fetch는 리모트 레포지토리의 브랜치를 검토해야할 때 쓰면 된다.
3. 이 코드는 누가 작성했을까?
깃을 쓰다보면 하나의 파일이 어떻게 수정되어 왔는지 확인이 필요할 때가 있다.
이럴땐 git blame 커맨드를 이용하면 된다.
git blame calculator.py 라고 입력하면 calculator.py 파일의 어떤 부분이 어떤 커밋에 의해 생겼는지 확인할 수 있다.
제일 왼쪽편은 커밋 아이디, 아이디 오른편엔 작성자가 표시된다.
혹은 git show [커밋아이디]를 작성하면 누가 언제 해당 커밋을 작성했는지 확인할 수 있다.
누가 했는지 다 뜨니까 코드 작성하고 커밋은 항상 신중하게...............
4. 이미 Remote Repository에 올라간 커밋을 취소해야 한다면?
무료 버전에 어떤 수의 제곱을 해주는 square 함수를 추가해보겠다.
커밋 완료 후 git push까지 실행해준다. 그런데! 무료 버전에서 square 함수를 빼자는 소식을 들었다면??
square 함수를 지우고 다시 커밋, git push를 해주면 된다.
그렇지만 git revert [커밋 아이디] 커맨드를 이용하면 최신 커밋에서 한 작업을 되돌리고 다시 커밋해주는 작업을 한번에 할 수 있다.
git revert 커맨드를 입력해 주면 커밋 메세지를 남기는 창이 뜬다. 나는 그대로 저장하겠다.
그리고 calculator.py 파일을 살펴보면 square 함수가 사라져 있고 커밋 히스토리에 방금 한 커밋이 잘 뜬다.
방금 나는 calculator.py 파일에서 square 함수를 직접 지우지 않고, git revert 커맨드를 사용해 square를 추가한 작업을 되돌리는 커밋을 새로 했다.
git push하고 커밋 히스토리를 살펴보면 로컬 레포지토리의 main 브랜치와 리모트 레포지토리의 main 브랜치가 같은 커밋을 가리키고 있다.
이 때 git reset으로 square 함수를 추가하기 전 커밋으로 돌아가면 되지 않냐고 생각할 수도 있지만, 로컬 레포지토리만 두고 작업할 땐 가능할 지 몰라도 리모트 레포지토리가 있다면 불가능하다. 이전 커밋으로 git reset 후 git push 하려고 하면, 리모트 레포지토리에 더 최신 커밋(square 함수를 추가한 커밋)이 있기 때문에 git push가 되지 않는다.
git revert를 하면 이전 커밋의 작업을 되돌리고 새로운 커밋이 생성되므로 git push를 하는데 문제가 없다.
이게 바로 reset 대신 revert를 사용하는 이유이다.
5. 여러 커밋 취소하기
과거의 여러 커밋을 한번에 범위지정해서 revert 하는 것도 가능하다.
git revert [시작 커밋아이디]..[마지막 커밋아이디] 를 입력하면 시작 다음 커밋 아이디 부터 마지막 커밋 아이디 사이의 모든 커밋들의 작업이 초기화된다.
예를 들어 git revert cf4a..422a 라고 입력하면, 422a 86c3 커밋의 작업들이 초기화된다.
6. 정리노트
- git fetch : 로컬 레포지토리에서 현재 HEAD가 가리키는 브랜치의 업스트림(upstream) 브랜치로부터 최신 커밋들을 가져옴(가져오기만 한다는 점에서, 가져와서 머지까지 하는 git pull과는 차이가 있음)
- git blame : 특정 파일의 내용 한줄한줄이 어떤 커밋에 의해 생긴 것인지 출력
- git revert : 특정 커밋에서 이루어진 작업을 되돌리는(취소하는) 커밋을 새로 생성
'1. 프로그래밍 > 1-1. Git' 카테고리의 다른 글
7. Git 자유자재로 활용하기 (2) (0) | 2021.09.07 |
---|---|
7. Git 자유자재로 활용하기 (0) | 2021.09.06 |
5. 브랜치 사용하기 (2) - [ git reset / checkout / merge ] (0) | 2021.09.05 |
5. 브랜치 사용하기 - [ branch / merge ] (0) | 2021.09.05 |
4. 커밋 다루기 - [ commit history / 커밋 메세지 / HEAD / git reset ] (0) | 2021.08.31 |