Git 이해하기 Part 1

김민준·2022년 2월 11일
2

Git

목록 보기
1/2

Git이란?

깃(Git)은 컴퓨터 파일의 변경사항을 추적하고 여러 명의 사용자들 간에 해당 파일들의 작업을 조율하기 위한 분산 버전 관리 시스템이다. 또는 이러한 명령어를 가리킨다.
소프트웨어 개발에서 소스 코드 관리에 주로 사용되지만 어떠한 집합의 파일의 변경사항을 지속적으로 추적하기 위해 사용될 수 있다. 기하학적 불변 이론을 바탕으로 설계됐고, 분산 버전 관리 시스템으로서 빠른 수행 속도에 중점을 두고 있는 것이 특징이며 데이터 무결성, 분산, 비선형 워크플로를 지원한다.
-위키백과

소프트웨어 구성관리(SCM, Software Configuration Management)

소프트웨어 공학에서 소프트웨어 구성 관리(software configuration management, SCM, S/W CM)는 더 범위가 큰 구성 관리의 학문간 분야의 일부인, 소프트웨어의 변경사항을 추적하고 통제하는 작업이다.
SCM 행위에는 버전 관리, 베이스라인 확립이 포함된다. 무언가 잘못되는 경우 SCM은 변경사항과 변경한 사람을 특정할 수 있다. 구성이 잘 된 경우 SCM은 수많은 호스트에 걸쳐 이를 복제(replicate)하는 방법을 결정한다.
-위키백과

우리는 바로 "Git"을 통해 소프트웨어 구성관리를 하고 있다고 생각하면 될 것 같습니다!!!

버전 관리 시스템(VCS, Version Control System)

파일 변화를 시간에 따라 기록했다가 나중에 특정 시점의 버전으로 꺼내올 수 있는 시스템

버전 관리 시스템에는 CVCS vs DVCS가 존재

CVCS(중앙집중식 VCS, Cenral Version Control System)

장점

  • 운영/관리가 직관적
  • 관리자가 모든 작업에 대해 실시간 체크 가능

단점

  • 커밋시 바로 중앙 히스토리에 반영
  • 자신만의 작업 히스토리는 존재하지 않음
  • 규모가 커질수록 매우 느려짐. why?
    • 버전 관리 관련 연산을 "중앙서버"에서 모두 처리
    • 델타(Delta) 방식으로 데이터를 관리

🤔 델타 방식

  • 프로젝트 내의 각 파일의 변경사항을 시간순으로 계속 쌓아가며 파일들의 집합을 관리하는 방식
  • 파일의 생성부터 변경사항들을 계속 따라가야 하고,
    버전을 가져올 때 변경사항들을 계산하여 가져와야 해서,
    커밋이 많아질수록 속도가 느려짐
    • 버전 5를 가져오려면 파일의 생성을 기준으로, 모든 델타들을 계산하여 가져와야하기 때문에 커밋이 쌓일수록 느려질 수 밖에 없음

DVCS(분산형 VCS, Distribution Version Control System)

장점

  • 코드의 분산관리로 인해 중앙서버 데이터가 유실되어도 복구 가능
  • 자신만의 작업공간이 별도로 있기 때문에,
    네트워크가 연결되어있지 않아도 커밋 등 버전 관리가 가능
  • 규모가 커지더라도 속도가 빠름
    • 버전 관리를 위한 대부분의 연산이 "로컬"에서 이루어짐
    • 스냅샷(Snapshot) + 델타 방식으로 데이터를 관리

🤔 스냅샷

  • 파일을 하나씩 별도로 보며 차이점(즉, 델타)만 따로 관리하지 않고, 프로젝트 전체를 스냅샷 형태로 관리
  • 매 순간마다 프로젝트 전체를 사진으로 찍어서 관리하는 것과 같은 형태
  • 버전이 변경되면 변경된 버전의 스냅샷을 하나 만들어 놓고 그 스냅샷을 가리키는 레퍼런스를 저장
  • 효율을 위해, 변경되지 않은 파일은 새로 저장을 하는 것이 아니라 이미 저장되어 있는 파일에 링크만 걸어줌

  • 매 버전마다 스냅샷을 만들고 저장하면 많은 용량을 차지하고 느려지지 않을까? => No!!!
    • 마지막 커밋의 스냅샷만 통째로 저장하고 나머지 커밋에 대해서는 스냅샷과 스냅샷이 차이를 기록한 "델타"만을 저장하기 때문임
      (스냅샷 + 델타로 데이터 관리)

  • 버전별로 전체 스냅샷을 모두 저장하지 않아도 마지막 스냅샷을 기준으로 특정 시점의 스냅샷을 만들 수 있어, 저장소의 크기도 자연스럽게 줄어듦

Git의 중요 5대 개념

  1. 파일상태
  2. 작업공간
  3. 커밋
  4. 브랜치
  5. HEAD

git의 대부분의 기능은 위 5가지 개념을 활용하는 과정

git init: Git 시작을 위한 초기화

  • CLI에 git init 명령어 입력시, .git 폴더가 생성됨
  • git은 코드 변화에 대한 히스토리 및 상태를 .git 폴더에서 관리
    • .git 폴더 삭제시, 관리하던 모든 이력이 삭제됨
      • 따라서, 작업했던 프로젝트 파일이 있더라도 git 관리가 불가능
    • 커밋, 로그, 데이터 등을 git 내부적으로
      Refs, Blob, Tree 시스템을 통해 관리

git add: Working Directory to Staging Area

Working Directory

Untrackted

  • 아직 git에 의해 한번도 관리되지 않은 상태
  • 즉, git add 명령어로 아직 한번도 Staging Area에 진입하지 않은 상태

Tracked

  • git add 명령어를 통해 Staging Area에 진입하여
    git에 의한 관리가 시작된 상태

Modified

  • "Tracked" 상태의 파일이 수정된 상태

Staging Area

  • Git Index라고도 함
  • 워킹 디렉토리의 변경사항을 바로 로컬 저장소에 기록(커밋)하는 것이 아니라, 여기에 먼저 기록하는 과정을 거침
    • 다음 커밋의 스냅샷을 위한 밑바탕
    • 작업 과정에서의 중간 산출물을 적절하게 선택하여
      커밋을 할 수 있음
  • 병합 충돌(merge conflict)가 일어났을 때, 임시 상태의 데이터를 관리
    • Staging Area가 없다면 메모리 상에서 이를 관리해야 함

git commit: Staging Area to Local Repository

commit

  • 의미있는 변화에 대한 히스토리
  • Staging Area에 Index된 코드의 변화를 커밋을 통해 히스토리화
  • root commit을 제외한 커밋들은 parent commit을 가짐
  • 현재 커밋의 이전 커밋이 parent commit
  • 부모 커밋에 변화가 발생하면, 부모 커밋의 자식 커밋도 변화
    • 이러한 현상은 연쇄적으로 발생하기 때문에, 특정 커밋에 변화가 발생하면 이후의 모든 커밋에 변화가 발생
    • 따라서, 특정 커밋을 변화하고자 시키고자 하는 경우에는 주의가 필요(특히, 협업시 주의 요망)
  • 변화된 값과 커밋 정보를 기반으로 SHA-1 알고리즘 해싱을 하여 commit id를 생성

커밋 정보(log)에는 어떠한 정보들이 있을까?

  • 작성자, 작성일자
  • 커밋 메세지
  • 커밋 ID(hash)
  • 변경이력
  • parent commit
  • Etc.

commit은 매우 중요하다!!!

  • 프로젝트가 커지면 커밋의 수도 매우 늘어나므로, 프로젝트의 관리를 수월하게 하기 위해서는 commit을 "잘" 해야함
    • 커밋 메세지는 항상 자세히 기재
    • 커밋 단위에 신경쓰기
      • 작업의 중간물을 저장하는 차원에서 커밋X
      • 여러 기능을 묶어서 커밋X
      • 정상 동작을 보장하는 경우에만 커밋O
    • [참고]: 규칙적인 Commit 메세지로 개발팀 협업하기

commit id

  • git 무결성을 위한 체크썸
  • 160bit로 구성: 40자리 * 16진수(4bit)
  • SHA-1 알고리즘으로 만들어진 hash 값을 사용하기 때문에 중복값이 없어 commit의 순서를 기억할 수 있고, 이로 인해 온/오프라인 어떤 환경에서도 commit이 가능
  • 일반적으로 8~10자로도 프로젝트 내에서 고유성을 유지하기에 충분하기 때문에, git에서는 기본값으로 7자리의 짧은 형태를 사용

git push/fetch, pull: Local Repository <=> Remote Repository

push

  • 로컬 저장소에 커밋된 내용(HEAD가 가리키는 커밋)을 원격 저장소로 보내는 명령어

fetch

  • 원격 저장소의 최신 내용을 로컬 저장소로 가져오지만, 병합하지는 않는 명령어

pull

  • 원격 저장소의 최신 내용을 로컬 저장소로 가져오면서 병합까지 하는 명령어(fetch + merge)

Git의 BRANCH와 HEAD

BRANCH

  • 독립적인 작업공간을 생성하는 개념
  • 여러 브랜치를 생성하여 하나의 프로젝트를 여러 갈래로 나누어서 독립적으로 관리할 수 있음
  • 여러 개발자들이 동시에 다양한 작업을 할 수 있게 만들어 주는 기능
  • 브랜치는 항상 생성된 해당 브랜치의 가장 마지막 커밋을 가리킴
  • 특정 커밋을 가리키는 특수한 포인터
  • HEAD에 따라 워킹 디렉토리의 파일도 변경됨
  • git checkout 명령어를 통해 HEAD 포인터를 변경하여 작업 공간을 전환함
    • 다른 브랜치로 옮겨 로컬 브랜치를 변경할 수 있음
    • 해당 브랜치에서 최신 커밋이 아닌 과거의 커밋을 가리킬 수 있음
  • 새로운 커밋이 생성된 경우 새로운 커밋을 가리킴
  • HEAD의 변경은 git 내부에서 log로 관리
  • 일반적으로 브랜치를 가리키지만, 다른 커밋을 가리키게 할 수 있음(Detached HEAD)
    • 과거 시점의 코드를 확인하고자 할 때
    • 과거 시점에서 브랜치를 생성해야 할 때

git merge: 3-way vs Fast-forward

3-way merge

  • 새로운 브랜치 생성 이후, 메인 브랜치에서 커밋이 발생하여 Fast-forward merge가 불가능한 상황에 진행

  • base commit: 브랜치가 생성되는 기점이 되는 commit
  • base commit(274aacc)과 각 브랜치의 commit(0f039ae, E7ac282)을 비교하여 병합
    • 3가지 commit을 비교하여 auto-merge 시도 이후,
      해결되지 않는 부분에 대해서는 conflict가 발생
  • 3-way merge의 예시
CaseM branchBaseA BranchMerge
case1swiftswiftapp>app
case2androidiOSiOS>android
case3appleapple>
case4trialanderror>"conflict!"
  • 3-way merge의 경우, merge의 결과인 merge commit(92a84bb)이 생성됨

Fast-forward merge

  • 메인 브랜치에서 분기한 이후, 메인 브랜치에서는 변경 사항이 없는 경우 진행되는 머지

  • 구조적으로 conflict는 발생하지 않음
  • 3-way와 달리 merge의 결과인 merge commit이 생기지는 않으며, 단지 메인 브랜치의 포인터가 분기한 브랜치의 최신 커밋으로 이동
    • merge에 대한 히스토리가 남지 않기 때문에 이러한 형태의 병합을 선호하지 않는 경우도 있다고 함

git rebase

rebase: 다시 베이스를 만든다!

  • 말 그대로 base commit을 변경함
  • rebase시, base commit이 변경되어 그 이후의 커밋들이 모두 변경되므로 협업시 주의가 필요
  • rebase를 한 이후에는 자동으로 merge됨

  • rebase가 불필요한 경우에는 할 필요 없음
    • 아래의 경우는 바로 merge(Fast-forward)하면 됨

🤔 끝내기 전, 짤막한 팁!!!

  1. 유닉스 시스템에서 파일명 앞에 .을 붙이면 "숨김파일 처리"가 됩니다.
  2. Blob이란? Binary large object를 의미합니다. 큰 객체를 바이너리 형태로 저장한다는 의미로, 주로 멀티미디어 데이터가 이에 해당됩니다.
  3. github의 private repository의 경우, 일반적으로 commit 작업 이력이 잔디에 표시되지 않습니다... 따라서, 필요한 경우 별도의 설정이 필요합니다.
    [참고]: private 저장소의 작업 내역 github 잔디에 표시하기
profile
trial and error

0개의 댓글