지난 시간에는 Git을 활용하여 협업할 때, 벌어지는 문제 상황과 그 대처 방법에 대해 함께 알아봤습니다.

이번 시간에는 Git을 보다 더 자유롭게 사용할 수 있도록 Git에 대한 여러 팁들을 알려드리겠습니다.

🧙‍♀️ git reflog

앞서 git reset은 HEAD가 가리키던 브랜치가 가리키는 커밋을 바꾸는 커맨드라고 배웠습니다. 만약 과거의 커밋으로 reset 하면 그 커밋 이후로 했던 커밋들은 어떻게 될까요?

커밋 히스토리부터 보겠습니다.

git history


이 중에서 가장 처음에 한 3b94 커밋으로 reset을 해보겠습니다.

git reset --hard 3b94

실행을 하면, hard 옵션을 줬기 때문에 working directory 속 내용까지 싹 다 사라집니다.

정말 초기화 됐는지 확인하기 위해 calculator.py 파일을 출력해보겠습니다.

cat calculator.py


두 함수만 뜨는 것을 보니 처음으로 돌아간 게 맞습니다. 이 상태에서 커밋 히스토리를 보면 어떻게 될까요?

git history


제일 처음 커밋만 뜨네요. 그럼 이때까지 했던 모든 커밋들이 삭제된 걸까요? 정답은 아닙니다!

앞서 reset을 해도 그 이후의 커밋들이 삭제되는 건 아니라고 했던 말 기억하시나요? 이를 증명해보겠습니다.

reset 전 가장 최신 커밋의 아이디는 9ff9였습니다. 이 최신 커밋으로 다시 reset을 해보겠습니다. 그런 다음, 커밋 히스토리도 다시 한 번 볼게요.

git reset --hard 9ff9
git history


다시 예전 커밋들이 보입니다! calculator.py 파일도 다시 출력해보겠습니다.

cat calculator.py


다시 네 개의 함수가 잘 뜨네요.

이렇듯 git reset을 하면 이전 커밋들이 모두 삭제되진 않습니다. 다만, HEAD가 가리키던 브랜치가 새로운 커밋을 가리키게 될 뿐이죠.

그래도 최신 커밋으로 돌아가기 위해서는 최신 커밋의 아이디를 알아야 하는데요. 만약 커밋 히스토리를 미리 출력하지 않고 git reset을 하면 어떻게 해야 될까요?

다시 처음 커밋으로 reset하고 한 번 알아 봅시다. 위 과정을 다시 진행해주세요.

최신 커밋 아이디를 모를 때, 사용할 수 있는 커맨드는 git reflog입니다. reflog는 reference log의 약어로, HEAD가 지금까지 가리켜왔던 커밋들을 기록한 정보입니다.

git reflog


실행하면, 위와 같이 지금까지 HEAD가 가리켜온 커밋들이 화면에 출력됩니다. 이때, 각 한 줄은 HEAD가 가리키던 커밋이 바뀌었을 때 기록된 것입니다.

reset: moving to 9ff9라는 문구가 보이시나요? 이 문구는 해당 동작을 통해서 HEAD가 가리키게 된 커밋을 말하는데요. 그 커밋의 아이디는 바로 왼쪽에 나타나 있습니다. 이 아이디를 통해 다시 최신 커밋으로 돌아갈 수 있는 거죠.

git reset --hard 9ff9

혹은 위 문구 옆 HEAD@{1}을 적어줘도 됩니다.

git reset --hard HEAD@{1}

그럼 다시 최신 커밋으로 돌아갈 수 있습니다.

이렇듯 git reflog는 최신 커밋 아이디를 모를 때 사용할 수 있는 커맨드입니다. 실무에서도 자주 쓰이는 커맨드이므로 꼭 기억해주세요!

🧙‍♀️ 커밋 히스토리를 보는 다양한 방법

지금까지 커밋 히스토리를 보면서 git history를 사용했는데요. 사실 이 커맨드는 git log --pretty=oneline별칭이었죠?

이 커맨드 뒤에 --all이라는 커맨드를 붙여주면 현재 브랜치뿐만 아니라 전체 브랜치의 커밋 히스토리가 잘 보입니다.

git log --pretty=oneline --all 

물론 이렇게도 가능합니다.

git history --all


위 결과를 자세히 보면, premium 브랜치와 master 브랜치가 둘 다 있는 것을 확인할 수 있습니다. 그런데 이렇게 보면 두 브랜치의 커밋 히스토리를 구분하기가 어렵습니다.

이 문제를 해결하려면 --graph라는 옵션을 주면 됩니다. 이 옵션은 각 브랜치와의 관계가 잘 드러나도록 커밋 히스토리를 그래프 형태로 출력해줍니다.

git history --all --graph


실행을 하면, 화려한 선들이 출력됩니다. 지금 여기서 별표(*) 하나가 커밋 하나를 뜻합니다. 그리고 여러 들은 브랜치를 의미하죠. 선이 갈라졌다는 것은 코드 관리 흐름이 갈라졌다는 것을 뜻하겠죠? graph 옵션을 사용하니 커밋과 브랜치의 관계가 입체적으로 잘 보입니다.

graph 옵션을 주기 전에는 revert 커밋의 순서가 섞여 브랜치를 구분하기 어려웠는데요. 위 결과에서는 premium 브랜치는 위에 master 브랜치는 아래에 위치하여, 두 커밋이 잘 구분됩니다. 참고로 두 선이 합쳐지는 곳에 커밋 메시지를 보면 전부 merge 커밋이란 걸 알 수 있습니다.

앞으로 커밋과 브랜치의 흐름을 정확하게 파악하고 싶을 때는 graph 옵션을 활용해보세요!

🧙‍♀️ GUI 환경에서 Git 사용하기

우리는 지금까지 Git을 CLI 환경에서 작업했는데요. 그런데 우리에게 익숙한 GUI(Graphic User Interface) 환경에서도 Git을 사용할 수 있습니다. 특정 프로그램들을 통해서 말이죠.

다양한 프로그램들이 있지만 그 중에서 가장 널리 쓰이는 Sourcetree에 대해 배워보겠습니다.

❗ Sourcetree 설치하기

  1. Sourcetree 페이지로 접속해서 Download for Windows를 클릭해주세요.

  1. 약관에 동의한 뒤, 프로그램을 다운로드 합니다.
  2. Sourcetree 설치 파일을 클릭합니다.
  3. 설치 전에 계정 등록을 하라는 문구가 뜹니다. 계정 하나를 생성합니다.
  4. 설치를 완료하면 아래와 같은 창이 뜹니다.

    여기서부터는 새로운 로컬 레포지토리를 만들 수 있고 원래 있던 로컬 레포지토리를 import할 수도 있습니다. 지금까지 작업해온 MathTool을 import 해보겠습니다.
  5. 좌측의 Local을 누르고 그 옆에 Add를 눌러 MathTool의 경로를 잡아줍니다. 그럼 다음과 같은 창이 뜹니다.

상단의 아이콘에서 커밋, pull, push 등의 작업을 할 수 있습니다. 그래프가 있는 가운데 창은 커밋 히스토리를 그래픽적으로 보여주는 영역이고 그 아래에는 커밋 히스토리 중에서 파란색으로 활성화된 커밋에 대한 정보를 보여주는 영역이 있습니다. 이 영역은 해당 커밋 당시 생성되거나 수정된 파일 목록을 보여줍니다. 그 아래 영역은 커밋 히스토리 중에서 파란색으로 활성화된 커밋에 대해 '커밋을 한 사람, 커밋 메시지, 커밋 일시' 등의 정보를 보여줍니다. 마지막으로 오른쪽 영역은 구체적인 수정 내역을 보여줍니다.

❗ Sourcetree 기능 살펴보기

Sourcetree는 누구나 그래픽 요소(아이콘, 설명 등)만 보고도 바로 사용할 수 있을 정도로 직관적인 UI(User Interface)를 가지고 있습니다. 그 중 몇 가지 기능을 살펴보겠습니다.

  1. 커밋 하기
    어떤 파일을 생성하거나 수정하고 나서 Sourcetree에 커밋 메시지를 입력하고 커밋할 수 있습니다.
  2. pull 하기
    리모트 레포지토리의 내용을 로컬 레포지토리로 가져와서 merge할 수 있습니다.
  3. push 하기
    로컬 레포지토리의 내용을 리모트 레포지토리로 보낼 수 있습니다.
  4. fetch 하기
    리모트 레포지토리의 내용을 로컬 레포지토리로 가져올 수 있습니다. merge는 하지 않습니다.
  5. 브랜치 생성하기
    새로운 브랜치를 생성할 수 있습니다.
  6. 브랜치 merge 하기
    현재 브랜치에서 다른 브랜치를 merge할 수 있습니다.
  7. 커밋 메시지를 기준으로 커밋 검색 하기
    커밋 메시지에 관한 키워드 검색으로 특정 커밋을 찾을 수 있습니다.
  8. 브랜치 변경하기(checkout)
    다른 브랜치로 이동할 수 있습니다.
  9. 리모트 레포지토리의 브랜치 살펴보기
    리모트 레포지토리에 있는 브랜치들도 살펴볼 수 있습니다.

위에 소개한 내용들은 지금까지 배웠던 기능들입니다. 이런 GUI 프로그램을 사용하면 터미널에 Git 커맨드를 치지 않아도 Git을 사용할 수 있습니다. 다시 말해, 커맨드를 몰라도 된다는 것이죠.

뿐만 아니라 터미널에서 봤던 것보다 더 깔끔하고 직관적인 모습으로 커밋 히스토리를 볼 수 있다는 장점도 있습니다.

하지만 아직 Git 커맨드를 사용하는 방법도 제대로 익히지 못했는데 바로 이런 프로그램을 사용하는 것은 좋지 않습니다. 커맨드부터 하나씩 배워야 나중에 이런 프로그램을 사용하다가 문제가 생기더라도 대처가 가능하기 때문이죠. Sourcetree는 실무에서도 많이 쓰이기 때문에 CLI 환경에서의 Git에 적응이 되면 계속해서 사용해보시길 바랍니다.

🧙‍♀️ git rebase

새로운 커맨드를 배우기 전에 상황 설정부터 하겠습니다. premium 브랜치에서 실험용 브랜치를 하나 더 만들건데요. 앞으로 premium 버전에 복잡한 함수를 추가할 때, 이 실험용 브랜치에서 실험을 한 후에 premium 브랜치에 추가하려고 합니다. 간단한 함수들은 premium 브랜치에 바로 추가할 거구요.

우선, 실험용 브랜치를 생성해보겠습니다.

git branch test

그런 다음, Sublime Text로 이동해서 간단한 함수 하나를 추가하겠습니다. 현재 위치는 premium 브랜치이어야 합니다.

calculator.py 파일에 나머지를 구하는 get_Remainder 함수를 추가했습니다.

터미널에서 git add와 커밋을 진행해주세요.

git add .
git commit -m "Add get_Remainder function"

test 브랜치에는 두 수의 중간 값을 구해주는 get_Median 함수를 추가하겠습니다. test 브랜치로 이동한 후, Sublime Text에서 새 함수를 추가해주세요.

git checkout test


마찬가지로 git add와 커밋까지 진행하겠습니다.

git add .
git commit -m "Add get_Median function"

여기까지 진행했는데 회사로부터 get_Median 함수를 premium 브랜치에 추가해달라는 요청을 받았습니다. 그럼 premium 브랜치에서 test 브랜치를 merge하면 될 것 같네요.

git checkout premium
git merge test


CONFLICT가 뜨네요! 같은 부분을 서로 다르게 수정했기 때문이죠? Sublime Text로 이동해서 원하는대로 내용을 수정해주겠습니다. 함수 두 개를 다 남기면 되겠습니다.

그런 다음, git add와 커밋을 진행해주세요.

git add .
git commit

커밋 메시지는 에디터에 뜨는 그대로 사용하겠습니다.

여기까지 진행한 후, 커밋 히스토리를 확인해볼게요. 그래프를 통해 더 직관적으로 봅시다.

git history --all --graph


premium 브랜치와 test 브랜치가 잘 merge 되었네요.

그런데 방금처럼 git merge를 하지 않고 다른 커맨드를 사용할 수 있습니다. 바로 git rebase입니다. 이 커맨드를 사용하기 위해 premium 브랜치를 merge 직전의 커밋으로 되돌리겠습니다. reset을 하면 되겠죠?

git reset --hard a968

reset이 잘 되었으니 새로운 커맨드를 사용해보겠습니다. 참고로 rebase는 베이스를 다시 지정한다는 뜻을 가지고 있습니다. 다시 말해, 커밋을 재배치한다는 것이죠. 좀 더 구체적으로 설명 드리자면, 이 전체 커맨드는 현재 위치한 premium 브랜치의 베이스를 test 브랜치로 재지정한다는 뜻입니다. 아직 무슨 말인지 잘 모르겠죠? 직접 해보면서 알아봅시다.

git rebase test

rebase의 인자로는 대상 브랜치 이름을 적어주면 됩니다.

실행을 하면, merge 때와 마찬가지로 CONFLICT가 뜹니다. 해결 방법은 merge CONFLICT와 동일합니다. git add를 하는 것까지도 동일한데 커밋은 하지 않습니다. 대신, 다음과 같은 커맨드를 입력하죠.

git rebase --continue

이 커맨드의 의미는 CONFLICT가 발생해서 제대로 진행되지 못한 리베이스를 계속 진행하라는 뜻입니다. 커맨드 실행 후, 다시 커밋 히스토리를 보겠습니다.

git history --all --graph


그런데 뭔가가 좀 다릅니다. 브랜치가 갈라지지 않았습니다! 그래서 마치 Add get_Median function 커밋이 원래 premium 브랜치에서 진행한 것처럼 보입니다.

다시 말해, merge 커밋이 새로 생성되지 않고 test 브랜치의 커밋을 premium 브랜치의 커밋이 거쳐온 것처럼 보인다는 것이죠. 갈라져 있던 코드 흐름이 하나로 이어져 커밋 히스토리의 구조 자체가 바뀌었습니다.

이는 rebase의 뜻 그대로 test 브랜치가 가리키는 커밋을 premium 브랜치가 자신의 새로운 베이스로 만든 것입니다.

정리하자면, merge와 달리 rebase는 새로운 커밋을 만들지 않고 rebase로 만들어진 커밋 히스토리는 merge로 만들어진 커밋 히스토리보다 좀 더 깔끔합니다. 분기를 나누지 않기 때문이죠. 물론 결과물은 동일합니다.

그럼 둘 중 어떤 커맨드를 사용해야 될까요? 만약 두 브랜치를 합쳤다는 정보가 커밋 히스토리에 꼭 남아야 한다면 merge를, 커밋 히스토리를 깔끔하게 유지하는 게 더 중요하다면 rebase를 사용하면 됩니다.

🧙‍♀️ 작업 내용 임시 저장하기

이번에는 premium 브랜치에서 절댓값을 구하는 함수 get_Abs를 추가해보겠습니다.

Sublime Text에서 위와 같이 작업을 하고 있던 도중, 회사에서 긴급 공지가 내려왔습니다. 무료 버전의 라이센스 정보를 당장 수정해달라는 내용인데요. 진행 중인 작업이 있지만 긴급 공지인만큼 빨리 처리를 해야할 것 같습니다.

작업 중인 내용을 저장하고 요청을 처리하기 위해 master 브랜치로 이동합니다.

git checkout master


에러가 뜨네요! 자세히 읽어보니 지금 브랜치를 이동하면 방금까지 진행했던 작업이 사라진다는 내용이네요.

상황을 정리해보면, master 브랜치로 이동하는 순간 premium 브랜치에 있던 HEAD가 master 브랜치를 통해 새로운 커밋을 가리키게 됩니다. 그럼 working directory의 내용도 커밋의 내용대로 바뀌면서 방금 작업했던 내용이 사라질 수 있기 때문에 에러가 뜨는 것이죠.

이런 상황에 대응하기 위해 꼭 알아야 할 커맨드가 있습니다. 바로 git stash입니다. stash는 안전한 곳에 '보관하다, 넣어두다'라는 뜻이 있습니다. 이 커맨드를 사용하면 working directory에서 작업하던 내용을 Git이 따로 보관하게 됩니다. 그리고 이때, 보관하는 장소stack이라고 하는데요. stack은 데이터를 저장하는 구조입니다.

이런 식으로 stack은 가장 나중에 들어온 데이터를 가장 먼저 꺼내는 구조입니다. git stash를 하면 가장 먼저 들어온 데이터가 가장 아래에 저장됩니다. 그럼 꺼낼 때도 가장 마지막에 꺼내지겠죠?

이제 이 커맨드를 실행해봅시다.

git stash


내용을 읽어보니, 작업한 내용을 stack에 잘 저장했다고 하네요. 정말 저장이 잘 되었는지 확인하려면 stash 뒤에 list를 붙이면 됩니다. list는 '조회하다, 나열하다'라는 뜻을 가지고 있습니다.

git stash list


실행해보면, 작업했던 내용이 stack에 잘 들어가 있는 것을 확인할 수 있습니다.

이 상태에서 다시 Sublime Text로 돌아와보면,

get_Abs 함수를 추가하기 전 모습으로 돌아왔습니다.

이처럼 git stash 커맨드를 사용하면, 최근 커밋 이후로 작업했던 내용은 모두 stack에 옮겨지고 working directory 내부는 다시 최근 커밋의 상태로 초기화됩니다. 그럼 작업한 내용이 사라질 걱정은 하지 않아도 되는 것이죠.

git stash를 했기 때문에 이제 master 브랜치로 이동이 가능합니다.

git checkout master

그런 다음, Sublime Text로 이동하겠습니다. 요청 받은 내용은 master 브랜치의 License 파일을 수정하는 것이었죠? 요청대로 내용을 수정해보겠습니다.

'Free'로만 적혀 있던 내용을 'Free for 1 year'로 수정했습니다. 내용을 수정했으니, 커밋을 해야겠죠?

git add .
git commit -m "Add free License duration info"

커밋까지 마쳤으면, 다시 premium 브랜치로 돌아가 원래 하던 작업을 이어 해봅시다.

git checkout premium

이제 stack에 저장했던 내용을 불러오겠습니다. stash 커맨드 뒤에 apply를 붙여주세요. apply는 '적용하다'라는 뜻이죠? 이 말은 즉, stack에 있는 내용을 다시 working directory로 가져와서 적용한다는 뜻입니다.

git stash apply

그리고 다시 Sublime Text로 와 보면,

작업했던 내용이 그대로 복구된 것을 확인할 수 있습니다. 나머지 내용을 적어준 뒤, 커밋을 진행해주겠습니다.

git add .
git commit -m "Add get_Abs function"

이렇듯 어떤 브랜치에서 하던 작업을 아직 커밋하지 않았는데 다른 브랜치로 가야하는 상황에서는 git stash 커맨드를 사용하여 작업 중이던 내용을 잠깐 저장하면 됩니다. 실무에서는 이와 같은 상황이 종종 벌어집니다. 그때마다 stack에 잠시 작업을 저장하면 쓸데없는 커밋을 늘리는 걸 방지할 수 있습니다.


이번 시간에는 Git을 보다 더 자유자재로 활용할 수 있는 여러 팁들에 대해 배웠습니다. reflog, all 옵션과 graph 옵션, GUI 환경에서 Git 사용할 수 있도록 돕는 프로그램, rebase, stash까지. 지금까지 많은 커맨드들을 배웠지만 또 새로운 커맨드들이 등장하는 것을 보면 Git에는 참 다양한 커맨드들이 있는 것 같네요.

다음 시간에는 이번 시간에 이어 Git에 관한 꿀팁을 더 알려드리려 합니다. 이제 얼마 남지 않았으니 조금만 더 힘내주세요!

* 이 자료는 CODEIT의 'Git으로 배우는 버전 관리' 강의를 기반으로 작성되었습니다.
profile
There's Only One Thing To Do: Learn All We Can

0개의 댓글