Day 62. Git 1 : Local git

ho_c·2022년 5월 15일
0

국비교육

목록 보기
57/71
post-thumbnail

어제 하루 종일 서류 작업을 하고 오늘은 세미 프로젝트 전 ‘협업’을 위해 Git을 배웠다.
깃허브가 있어서, 몇 시간씩 에러랑 싸우던 시절이 있었는데, 막상 배우고 나니 기초를 안다는 게 정말 중요하다는 것을 다시 깨달았다.


VCS

: Version Control System

말 그대로 “버전 관리 체계”를 뜻하며, 협업의 과정에서 프로그램의 버전을 관리하기 위해서 사용된다. 오늘 배울 깃 외에도 CVS, SVN 등 여러 종류가 있다.

다만 깃이 가진 차별성은 “분산 처리”가 가능하다는 것이다. 원래 VCS는 모든 버전을 중앙서버에서 통제하는 “중앙 통제시스템”이었다. 여기서 사용자는 VCS 서버에 프로젝트 스냅샷 (add-commit으로 저장한 세이브 포인트) 을 넣어놓고 꺼낸다.

이때, 중앙서버가 죽어버리면 모든 데이터가 날아간다. 반대로 깃은 중앙서버의 역할을 존재하지만, 실제 해당 프로젝트를 참여해 VCS를 사용하는 모든 이가 중앙서버가 되어 분산처리된다. 또한, 온-오프라인 환경에 대해 각 개인이 서버이기에 전혀 문제가 되지 않는다.

그럼 VCS로 뭘 할까?

개발을 진행하면, 코드 진행에 문제가 생기거나, 다시 코드를 짜고 싶을 때 이전에 저장해둔 스냅샷으로 돌아갈 수 있다. 즉, 과거의 특정 시점으로 갈 수도, 원래 시점으로 돌아오는 것이 가능하다. 이 부분이 DB와 다른 VCS의 기초 기능이다.

여담으로 깃 허브는 깃이랑 자신들의 서버를 연동시켜놓은 부가 서비스는 혼동하지 말자.


Local GIT

깃을 응용하는 프로그램은 Git Kraken(해외), Source Tree(국내)처럼 여러 가지인데, 이들은 깃 SCM의 원리 위에 그래픽을 얹은 것이다. 따라서 우리는 CMD를 통한 Git SCM을 사용하고자 한다.

1. Git 설치하기

설치는 최신 버전을 하자. 추가적으로 여러 기능이 따라오지만 그건 나중에 익숙해지면 하고, 기본값으로 설정하면 된다. 딱히 스크린샷을 찍어두지 않았기 때문에 특정 단계에서 설정만 살펴보자.

  • Let Git decide : 브랜치를 설정하는 과정

브랜치(가지)는 하나의 흐름(타임라인)에서 나아가는 새로운 분기점과 흐름이다. 그런 브런치 중, 처음 우리가 만들어가는 브랜치를 “master” 또는 “main”이라고 한다.

  • OpenSSH : Secure Shell, 보안처리 된 통신 프로그램으로 깃 서버에 뭘로 접속할건지 물어보는 것이다.

2. DOS

깃 SCM은 CMD를 사용한다. 윈도우 CMD가 맘에 들지 않는다면. 깃에서 제공하는 Git bash를 사용해도 괜찮다. (나는 Git bash가 더 좋다.)

CMD는 DOS라는 운영체제로 우리가 사용할 명령하는 다음과 같다. 이를 이용해서 Git으로 관리할 폴더로 넘어가는데, 해당 파일의 주소창에서 CMD 치면 그 자리에서 실행되니 별로 상관 없다.

드라이브 이동 [ d: ]
폴더(디렉토리) 이동 [ cd ] Change Directory
이전 폴더 이동 [ cd .. ]
파일 정보 출력 [ dir ] 

명령어

< 첫 커밋 >

git init

폴더로 이동해서 CMD에 git init을 입력하면, 해당 폴더를 깃으로 관리하기 위한 초기화 작업과 세팅이 준비된다. 딱히 변화가 없지만 폴더 내부의 숨긴 폴더를 보면, .git 이라는 이름을 가진 폴더가 생긴다.

이 폴더가 깃의 핵심으로, 이걸 지우면 해당 폴더에 적용된 깃의 관리기능이 사라지니 주의해야 한다.


git status

해당 폴더에 대한 정보를 알려준다. 첫 설정 이후엔 깃 생성 이전에 만들어진 파일이 목록에 뜬다. 이 파일들은 untracking file(미추적 파일)로 깃이 관리하지 않는 파일들을 의미한다.

이후 커밋이 일어난 뒤에는 새로 생성된 파일 또는 추적파일의 변경 사항들이 반영된다.


Working Tree

현재 작업을 수행하는 폴더, 그 자체를 “워킹 트리”라고 한다.
우리가 깃으로 워킹 트리 안에서 행하는 모든 작업을 보관하려면 이를 Local Repository, 곧 .git에 보관해야 한다.

따라서 일반적인 깃의 구조도는 다음과 같다.

Working Tree → Stage → Local Repository

예를 들어 A / B / C 라는 각 작업 내역을 git으로 관리하기 위해선 원하는 로컬 레포지토리 이전에 ‘staging area’로 올려줘야 하며, 이를 staging 이라고 한다.

staging area가 궁금하다면 이 포스팅을 참조하자.

추가로 스테이지에 올리는 작업은 부분적으로 또는 전체를 한번에도 가능하다.


git add <file명> or *

앞서 설명한, 우리가 관리할 작업 깃의 입장에선 추적할 대상을 스테이지로 올려놓는 명령이다.

git rm —cached <file명> : 추적 취소.

git commit –m “커밋명”

스테이지에 올려진 작업을 로컬 레포에 저장하는 기능이다. 이때 커밋의 이름을 입력해야 한다. 안 하면 엄청 뭐라한다.

git config --global

본인이 깃을 써본 적이 없다면, 깃에도 사용자인 우리의 정보를 남겨줘야 한다. 이때 사용하는 것이 git config를 통해 이메일이랑 이름을 입력하면 된다.

$ git config --global user.name OOO
$ git config --global user.email abcdefg@example.com

이때 --global를 사용하게 되면, 해당 컴퓨터 전체 적용되는 사용자를 입력한 것이다. 파일 별로 다른 사용자 정보를 두고 싶으면 --global 옵션을 빼주는 것이 좋다.

이렇게 커밋 이후, 정보입력이 끝났다면 우린 첫 번째 스냅샷을 찍은 것이다.


git log

이 명령어는 저장된 스냅샷들의 고유값과 내역이 나온다. 우리가 특정 시점으로 돌아가고 싶다면 내역을 출력해서 이동하면 된다.

  • git log –3 : 최신 3개만 보여준다.
  • git reflog : 모든 브랜치의 로그를 볼 수 있다. (시점에 상관없다)

HEAD -> master

명령은 아니고, 상태를 의미한다. 여기서 HEAD는 현재 사용자인 우리가 바라보고 있는, 또는 현재 위치한 타임라인-커밋 포인트를 의미한다.

따라서 HEAD -> master 는 “헤드가 마스터 브랜치를 보고 있다”라는 뜻이다.

따라서 마스터는 문맥에 따라 그 의미가 달라진다..

  • 가장 근본이 되는 브랜치.
  • 마스터 브랜치의 가장 최신 시점.

git checkout 고유값 앞 5자리 or 브랜치 명

깃의 핵심은 우리가 원하는 커밋만 해뒀다면, 언제든 원하는 커밋 시점으로 돌릴 수 있다는 것이다. 이 기능을 이용하기 위해선 git checkout을 사용하면 된다.

그리고 어디로 이동할지에 대해선, log를 통해서 나온 커밋의 고유값 5자리만 쳐주면 된다. 물론 master에서 과거로 체크아웃을 하면, 그 시점에서 미래의 기록들은 나오지 않는다. 그래서 가장 최신으로 돌아가고 싶으면 git checkout master를 해주면 된다.

근데 한 가지 숨겨진 사실은 checkout은 우리가 지정한 커밋 시점으로 HEAD를 돌리는 것이 아니다.

일단 마스터에서는 다음과 같이 커밋 포인트들이 늘어난다.

여기서 가장 최신인 커밋 포인트는 C이고, 이곳이 master이다. 동시에 A→B→C로 이어지는 브랜치 역시 master이다. 아무튼 이제 A로 체크아웃을 한다면 다음과 같이 생각한다.

하지만 사실은 다음과 같다.

위 사진처럼 실제 체크아웃이 가리키는 것은 A의 커밋 포인트를 복사하여 새로운 브랜치인 A`로 HEAD를 돌려놓는 것이다.


git reset

체크아웃이 복사된 브랜치로 간다면, 리셋은 현재에서 완전히 뒤로 돌아가서 앞이 사라진다.
뒤에 —hard 옵션을 사용하면 다 사라진다. 물론 실제 데이터는 완벽하게 지워지지 않았다.


git restore

추적 중인 파일의 변화를 대처하는 방법은 2가지이다.

  • commit : 수정 사항 반영
  • git restore : 스테이지에 올리지 않고 원상 복구한다.

삭제하기

삭제하는 명령도 따로 있지만, 가장 간단한 방법은 과거로 돌아가는 것이다. 일단, 스냅샷만 찍어놓았다면, 해당 시점은 항상 저장이 되어 있다.
그래서 파일을 실수로 지우거나, 쓸모없어서 지운 파일이 다시 필요해진다면 과거로 돌아가면 된다.

그러나, 그 후에 개발이 엄청나게 진행되었다면 과거부터 현재까지 따라잡는 건 비효율이다. 이 문제를 해결하는 방법은 “과거에서 빼서 미래로 넣는 것이다”

  • 과거로 돌아가서 파일을 복구한다.
  • 그걸 폴도 외부로 빼낸다.
  • 다시 미래(master)로 돌아와 밖에 있는 파일을 폴더에 넣는다.

빈번한 실수

수정한 걸 커밋하고, 또 사라진 파일을 복구할 때 빈번히 일어나는 실수는 “데이터 복구 후 master로 안 돌아온다는 것이다.”

어벤져스 엔드게임을 보면, 과거로 돌아가서 스톤을 가져오는 장면이 있다.

여기서 과거로 온 헐크가 이제 타임 스톤을 달라고 하지만 거절당한다. 이유는 과거에서 미래로 가져가는 순간, 그 타임라인에서 이어지는 미래는 헐크가 온 미래와 다른 미래를 만들기 때문이다. 이른바 “타임 패러독스” 때문이다.

물론 완벽히 일치 하는 비유는 될 수 없다. 왜냐면 타임 스톤은 미래로 가면 사라지지만, 우리가 복구할 데이터는 그 시점에서 사라지지 않기 때문이다.

무튼 여기서 우리가 데이터를 빼내고 마스터로 체크아웃 하지 않고 커밋을 해버리면 새로운 브랜치가 이어진다.

요약 : 데이터 복구를 위한 커밋 포인트에서 또 커밋을 하면, 새로운 브랜치가 만들어진다.


git branch

현재 HEAD인 브랜치와 사용중인 브랜치의 목록을 출력한다.

체크아웃으로 이동하려면 커밋 포인트의 주소값을 알고 있어야 한다. 그리고 주소값으로만 이동하는 브랜치는 ‘임시 브랜치’의 성향을 가지고 있다. 말 그대로 정식 루트는 아니라는 것이다.

그리고 임시 브랜치는 마스터 브랜치와 해당 시점까지 동일한 타임라인을 가지고 있다. 일종의 평행 세계라고 생각하는게 좋다. 그래서 주로 실험적인 코드를 짤 때, 브랜치를 새로 빼서 진행한다. 그 결과가 좋으면 Merge로 병합하여, 새로운 미래를 만들고, 별로면 그냥 가지를 쳐버린다.


Merge

머지는 다른 브랜치의 커밋 내역을 끌어와서 병합하는 것이다.
물론 다른 브랜치의 커밋 내용을 밖에다가 빼놓고 다시 넣는 것도 가능하지만, 데이터가 많은데 그걸 수작업으로 할 필요는 없을 것이다.

아무튼 merge로 병합을 하는데, 먼저 쉽고 편하게 이동하도록 징식 브랜치를 만든다.

git branch 브랜치명

앞서 임시 브랜치는 주소 값으로 이동한다. 그러나 임시 브랜치를 정식으로 해서 완전 새로운 루트로 치고 싶다면, 이름을 붙여 정식 브랜치로 등록하는게 좋다.

git branch —d “브랜치명” : 브랜치 삭제

git merge 병합할 브랜치명

머지 시, 두 가지 동작이 동시에 일어난다.

  • 병합할 브랜치의 로그와 기록들이 현재 브랜치로 병합된다.
  • 병합과 동시에 새로운 미래(커밋)가 만들어 진다.
    머지의 기준은 현재 HEAD가 보고 있는 브랜치에서 병합할 대상을 끌어오는 것으로 대상은 원하는대로 맘껏 할 수 있다.
git log --pretty=format:"%h %s" --graph : 머지 시에만 그래프처럼 로그를 보여준다.

Conflict (충돌)

이 문제는 머지를 할 때, 커밋 포인트끼리 충돌이 일어나 머지가 진행되지 않는 것이다. 일단 개인이 혼자 깃을 쓸 때는 딱히 일어나지 않는데, 팀플 시에 주로 발생한다.

일종의 버전 문제로, 같은 역사를 공유하는 두 개의 커밋 포인트의 버전이 일치하면 머지가 되지 않는다. 즉, 머지는 한쪽이 버전이 높아야 한다.

그림으로 설명하면 다음과 같다.

위 경우는 같은 타임라인을 가지고 있더라도, 버전이 한쪽이 더 높기 때문에 병합과 커밋이 가능하다.

반대로 위 경우는 타임라인은 공유하지만, 내용이 달라도 함께 버전을 높였다. 그 결과 깃 입장에선 어떤 것이 더 최신이고, 중심적인 커밋 포인트인지 인식할 수 없다. 따라서 ‘충돌’을 일으킨다.

충돌이 나면, 내용이 혼합이 되며 각각 어느 커밋 포인트에 기반한 것인지 기록되어 있다. 즉, 깃이 사용자한테 어떤 것을 선택할 것인지 수정하고 다시 커밋을 해달라는 것이다.

따라서 사용자는 충돌 내용을 잘 분석하여, 원하는 방향으로 새로 커밋을 해주면 된다.
(충돌이 나면 커밋이 되지 않는다.)

profile
기록을 쌓아갑니다.

0개의 댓글