Git이란 / 구조 / 명령어 정리, Git vs SVN

코찔찔이💻·2024년 4월 2일
0
post-thumbnail

1) Git?

Git 이란 분산형 관리 시스템 형태의 형상 관리 도구이다.

💡 형상 관리 도구란? 과거 작업 내역과 현재 작업 내역, 변경점을 확인할 수 있도록 만들어진 도구이다. **즉 버전 관리 도구라고도 한다.**

****소프트웨어 개발에 필요한 소스코드를 효과적으로 관리 할 수 있게 해주는 프레임 워크 중 하나이다.

1-1) Git vs SVN

대표적으로 SVN과 Git 이 존재하는데, SVN은 중앙 서버 저장소에서 소스 코드와 히스토리를 저장하는 형태이며, Git은 로컬 저장소와 서버 저장소를 분산해서 저장할 수 있다는 것이 차이점이다.

SVN(중앙집중식)

  • CVCS(Centralized Version Control System)
  • 개발자가 자신만의 commit history를 가질 수 없다.
  • commit한 내용에 실수가 있을 시 다른 개발자에게 바로 영향을 미치게 된다.
  • 저장소를 중앙 저장소 하나만 두는 형태이기 때문에, 데이터 소실 시 복구가 어렵다.

GIT(분산관리식)

  • DVCS(Distributed Version Control System)
  • 자신만의 commit history를 가지고 개발자 저장소(local)와 서버 저장소(remote)를 독립적으로 관리할 수 있다.
  • commit한 내용에 실수가 있더라도, 바로 서버에 영향을 끼치지 않는다.
  • 서버 통합 관리자는 각 개발자의 commit history를 원하는 순간에 가져올 수 있다.
  • 로컬 저장소가 존재하기 때문에, 네트워크에 접근할 필요가 없어서 빠르다.
  • commit하는 순간 저장소를 공유하는 모든 개발자가 소스코드를 볼 수 있는 SVN과 달리, 로컬 저장소에서 개발자는 마음껏 commit하고 원할 때, 원격 저장소로 push할 수 있다.

1-2 .git 폴더 구조 분석

.git/objects

  • git에서 활용하는 데이터들이 저장되는 곳
  • git의 모든 변경사항을 “압축”해서 파일들을 각 폴더 내부에 key-value 형식으로 저장한다.
  • 객체명은 실제 파일에 담긴 값들을 해시값 40자(2자-폴더명, 38자 파일명)식별자로 활용
  • 소스코드의 일부만 바꾸더라도 별개의 해시값으로 지정되기 때문에 식별에 용이하다.
  • 각각의 커밋별로 하나의 커밋 파일이 저장( hash, author, commiter, commit message)*
  • Git object 객체에는 4가지 타입이 존재한다.
    • blob : 텍스트, 이미지, 음악 등 다양한 형식의 파일이 저장 될 수 있다. 즉 , 파일의 내용(contents)를 담는다. git 저장의 기본 단위라고 볼 수 있다.

      //해시 파일에 압축된 내용을 프린트
      git cat-file -p [hash]
      
      //해시 파일의 타입을 확인
      git cat-file -t [hash]

      해당 blob의 내용을 확인하고 싶으면 위에 작성된 명령어를 입력하면 된다.

    • tree: 디렉토리의 파일명 & 내용명에 정보를 담는 곳이다.

    • commit : 고유한 id를 지니고 있으며 hash 정보를 통하여 저장된다.

      • tree : commit이 일어난 시점에 작업 디렉토리에 있는 파일의 이름 및 파일 정보
      • parent : 직전의 커밋의 정보가 저장
      • author : 해당 커밋의 권한을 지닌 유저 이름
      • committer : 해당 커밋을 작성한 유저 이름
    • tag :

      • 커밋을 참조하기 쉽도록 알기 쉬운 이름을 붙이는 것
      • cd 한번 붙인 태그는 고정된다.
      • 일반태그(LightWeight tag)와 주석태그(Annotated tag)로 나뉘어진다.

.git/refs

  • git에서 관리하는 branch들의 정보가 담겨있다.
  • local → heads , remote → remotes 안에서 관리된다.

.git/logs

  • HEAD. 각각의 브랜치 별로 작업 목록이 로그로 기록

.git/hooks

  • 기본적인 hook들이 정의되어 있다.
  • hook? 특정 상황에 특정 스크립트를 실행
  • .sample 확장자를 지우면 해당 hook이 실행된다.

.git/index

  • stage에 올라간 파일. 즉, git add 명령어를 통해 index 파일이 수정

.git/FETCH_HEAD

  • git fetch 이후, 해당 브랜치의 변경사항을 FETCH_HEAD 파일에 기록
  • 패치 작업 이후, 가져온 브랜치의 최신 커밋을 참조할 때 유용

2)Git을 사용하기 위한 필수 개념

local (Working Directory)

사용자 컴퓨터 내부의 폴더. 저장소로 인식되는 폴더는 .git 이라는 숨김 폴더를 가지고 있다. 로컬 저장소는 네트워크 통신이 필요하지 않다.

remote

원격 서버에 존재하는 저장소, 즉 소스 코드를 저장하고 공유할 수 있는 원격 저장소를 제공하는 대표적인 서비스로 Github, GitLab, Bitbucket 등이 있다.

upstream , downstream

fork → upstream : 오리지널 레퍼지토리 origin : fork한 레퍼지토리 downstream : orgin

clone → upstream : fork한 레퍼지토리 (origin) downstream : local

Github vs Gitlab

Github

- 공개적으로 사용 가능한 무료 서비스, 유료 서비스를 포함한 깃 저장소 호스팅을 지원하는 웹 서비스

Gitlab

- 개인 또는 조직이 Git repository의 내부 관리를 상용할 수 있다. 즉, 각 조직에서 서버를 설치하여 git 저장소를 운영할 수 있다.

**차이**

- 모두 git repository를 중심으로 개발 업무를 진행하는데 있어서 큰 차이는 없다.
- 소스코드 관리 이슈 트래킹, 모니터링 등 gitlab 하나로 많은 편의를 제공하고 있어서 github보다는 실무적으로 더 많이 사용되고 있다.

git 영역

코드가 Commit 될 때, 3가지 영역을 거친다.

1) Working Directory → 사용자가 코드를 작업하고 관리하는 프로젝트 디렉토리

2) Staging Area → git add를 통해서 수정된 코드를 올리는 영역. 바로 Repository에 올라가지 않고, Staging Area에 소스코드가 올라간다.

3) Repository → Staging Area에 올라간 코드들 중 git commit를 통해 최종 수정본을 저장소에 제출

git Status(파일 상태)

File의 관점에서는 4가지 상태가 존재한다.

  • untracked : Git에 add 되지 않은 상태, 즉 git으로 버전 관리가 되어 있지 않은 상태

  • unmodified : Git에 add 되었지만, 수정되지 않은 상태(new file과 동일).

  • modified : 이미 git으로 추적하고 있고, 파일이 수정되어 있는 상태(stage에 올라가 있지 않음)

  • staged : 파일이 수정 완료되어 commit할 준비가 되어 있는 상태, 즉 Staging Area에 반영된 상태

git HEAD

HEAD란? 현재 체크아웃된 브랜치의 이름을 가리키는 용어이다.

즉, 현재 내가 어떤 작업 공간에 머물고 있는지를 나타낸다. HEAD는 default로 master를 바라본다.

HEAD → koi.mcw_0.2 : 현재 koi.mcw_0.2 라는 브랜치의 커밋이 로컬 저장소의 최종 커밋, 즉 현재 작업 공간은 koi.mcw_0.2 브랜치임을 뜻한다.

git Branch

software 개발 시, 동일한 소스 코드 위에서 신규 개발, 버그 수정 등의 업무 협업을 할 시, 여러 개발자들이 동시에 다양한 작업을 할 수 있도록 하는 기능이다. 즉, 브랜치를 통해 하나의 프로젝트를 여러 버전으로 관리할 수 있다.

분기된 브랜치에서 수정을 한 후 커밋하면, master 브랜치에는 어떠한 영향을 끼치지 않는다. 따라서 반영하고 싶은 브랜치가 있다면 master 브랜치와 병합하고, 반영하고 싶지 않은 작업이 있는 브랜치는 삭제하면 된다.

//현재 체크아웃된 branch 확인 or branch list 확인
git branch

//branch 생성
git branch 브랜치명

//해당 브랜치로 이동
git checkout branch 이름

//master 브랜치로 이동
git checkout master

//branch 삭제 -> master 브랜치로 체크아웃 후 가능
git branch -d branch 이름

git fork vs git clone

fork

  • 다른 사람의 Github repository에서 어떤 부분을 수정하거나 추가 기능을 넣고 싶을 때, 해당 repository를 내 github repository로 그대로 복제
  • 수정 사항을 original repository에 변경 사항을 적용하고 싶으면 해당 저장소에 pull request를 해야 한다.
  • 원본(original)의 변경 사항을 추적할 수 있다. 그리고 해당 변경 사항을 나의 저장소로 반영할 수 있다.(fetch / rebase)

clone

  • 특정 repository를 자신의 local directory 에 복사하여 새로운 저장소를 만든다.
  • 원본 레퍼지토리의 로그를 볼 수 없다.
  • 권한이 없으면 해당 저장소(origin)으로 push하지 못한다.
    • ex) project를 생성한 후, 각 개발자가 clone하여 local 저장소에서 개발 작업 및 commit을 한다.
      이 때, 한 개발자가 remote 저장소에 push를 하게 되면, 다른 사람들은 origin에 코드를 적용할 권한이 없어지게 된다. 해당 변경 사항을 로컬에 병합한 이후 push할 수 있다.

git fetch vs git pull

협업 시, 다른 팀원이 원격 저장소에 먼저 변경 사항을 커밋하고 push 했을 경우 사용

fetch

  • 로컬 저장소와 원격 저장소의 변경 사항이 다를 때, 비교 대조하고 git merge 명령어와 함께 최신 데이터 반영, 충돌 문제 등을 해결(수동으로 병합을 진행해야 한다.)
  • 가져온 내용을 병합하지 않기 때문에, 로컬 저장소에 영향을 주지 않는다.

pull

  • git remote를 통해 연결된 원격 저장소의 최신 내용을 로컬 저장소로 가져 오면서 병합(자동으로 병합을 진행된다.)
  • 로컬 저장소에 변경 사항이 그대로 반영된다.

요약

  • 원격 저장소에서 변경 사항이 생기면, push 전에 fetch + merge 또는 pull 사용해야 한다.
  • fetch는 변경 사항을 비교 대조해볼 수 있으나 merge를 수동으로 해야 한다.
  • pull은 변경 사항을 자세히 알 수 없으나 한번에 merge를 진행할 수 있다.

git push

프로젝트 내에 추가되거나 수정된 소스코드를 공유하고 싶을 때, upstream 저장소로 push할 수 있다.

//git push 기본 명령어
git push <리모트 저장소 이름> <push할 브랜치 이름>

//git push 시, push할 remote 저장소의 upstream branch 설정
git push --set-upstream origin master 

//원격 저장소의 브랜치와 로컬 저장소의 브랜치를 자동으로 연결
//git push or git pull 명령어 만으로 브랜치 간 연결이 가능해 진다.
git push -u <리모트 저장소 이름> <push할 브랜치 이름>

해당 명령어는 Clone 한 리모트 저장소에 쓰기 권한이 있고, Clone 하고 난 이후 아무도 Upstream 저장소에 Push 하지 않았을 때만 사용할 수 있다.

즉, 다른 사용자가 먼저 push를 했을 경우에는 곧바로 push할 수 없고, remote에 올라가 있는 데이터를 로컬로 merge한 이후에, 새롭게 push할 수 있다.

origin vs master vs origin/master

origin : remote 저장소 이름. git clone을 통해 원격 저장소를 복사하면 자동으로 origin이라는 이름의 원격 저장소가 등록된다.

master : 가장 중심이 되는 기본 브랜치

origin/master : remote의 중심이 되는 브랜치

git checkout

git checkout은 크게 두 가지 기능이 있다.

-Branch 또는 코드를 특정 커밋 시점으로 되돌릴 때 (switch 기능)

-내용 되돌리기 (restore 기능)

이때 커밋으로 시점을 되돌릴 시 , head는 detach 즉, 브랜치를 참조하지 않은 상태가 된다.

detach 상태인 head에서 커밋을 계속 생성해도, 참조하는 브랜치가 없어서 commit되지 않은 내용이라고 인식하여 삭제된다. 커밋 생성 후 내용을 유지하려면, 새로 브랜치를 생성해서 참조하던지, 기존의 브랜치를 참조하도록 하던지 선택해야 한다.

//특정 커밋으로 되돌리기
git checkout [커밋 해시값]

//특정 브랜치 생성 후 해당 브랜치로 이동
git checkout -b 새로운 브랜치 이름

//특정 커밋으로 되돌린 뒤, 특정 브랜치를 해당 커밋으로 참조하도록 하기
//브랜치를 새로 생성하거나, master 브랜치를 해당 커밋 시점에 참조하도록 하면 된다.
git checkout -B [브랜치 이름] [커밋 해시값]

//모든 변경사항을 취소
git checkout .

git merge

  • 다른 Branch의 버전을 현재 Branch로 가져와서 병합 시키는 작업을 의미한다.
  • fetch를 통해 변경 사항을 비교 대조 한 후, merge로 원격 저장소의 변경 사항을 로컬 저장소에 반영한다.
  • 새로운 브랜치에서 개발을 완료하고 merge 하기 위해서는 master 브랜치에 checkout되어 있어야 한다.
// 병합하기 위해 master 브랜치 checkout
git checkout master

// 병합할 branch 설정
git merge 브랜치 이름

머지가 완료되었다면 다음 메시지를 확인할 수 있다.

Merge made by the 'recursive' strategy.
 example.txt | 1 +
 1 file changed, 1 insertion(+)

병합이 완료되었다면 작업했던 브랜치를 삭제한다.


//병합되지 않은 브랜치를 삭제하려면 -d -> -D로 쓴다.
git branch -d 브랜치 이름

merge 방식

1. Fast - forward 방식

분기된 브랜치(develop)는 master가 가지고 있는 모든 내용을 포함하고 있으므로, master 보다 더 최신버전이라고 할 수 있다. master에서 추가로 커밋이 이루어지지 않고 병합하게 된다면, master에는 최신화된 브랜치(develop)의 내용이 추가로 붙게 된다.

2. 3-way-merge(Recursive merge)

develop에서 기능 개발 후, 커밋을 한 뒤에 master에서 추가적인 커밋이 있었다고 가정했을 때, 분기된 branch는 master보다 최신 버전이라고 보기 어렵다. 이때 master와 develop이 서로 다른 내용을 가지고 있으므로, 내용을 합친 뒤(Fast -forward) 새로운 커밋 메시지를 만들어(Recursive) 병합한다.

즉, base(A)와 base에서 뻗어나간 브랜치가 참조하는 커밋(B,C)을 비교하여 병합 후 새로운 커밋을 생성하는 방식이다.

merge option

/* merge option */
// -ff : 두 브랜치가 fast -forward 관계일 경우, 
//-ff 명령어 사용 시, merge commit을 생성하지 않고 브랜치의 참조만 변경한다. 
//git merge의 default option
git checkout master
git merge -ff 분기 브랜치
/* merge option */
//--no-ff : fast-foward 관계여도, 강제로  merge commit 을 생성하고 병합
git checkout master
git merge --no-ff 분기 브랜치

Merge 종류

Github에서 제공하는 Merge 방식에는 Merge, Squash and Merge, Rebase and Merge로 총 3가지가 있다.

1) Merge

git checkout master
git merge <분기 브랜치명>

하나의 브랜치와 다른 브랜치의 변경 이력 전체를 합치는 방식

병합하기 전, master 브랜치에 checkout이 되어 있어야 한다.

2) Squash and Merge

git merge --squash <분기 브랜치명>

master에서 병합 시, develop의 커밋 이력을 삭제하고, 해당 브랜치에서 작업했던 커밋 내역들을 새로운 커밋을 생성하여 해당 커밋에 모두 담기게 하는 병합 방식이다.

  • -squash 옵션을 사용하면 커밋까지 생성하지 않는다.상대 브랜치의 작업 내용이 추가되어 파일 상태만 변경된다.
  • staged 상태로 되어있기 때문에, commit을 진행하면 된다.
  • --squash  옵션으로 merge를 진행하면 분기 브랜치의 최신 commit이 merging commit을 참조하지 않아서 merging 정보가 표시되지 않는다. 따라서 master 브랜치 관점에서는 병합에 대한 이력이 남지 않게 되는 것이다.
  • develop의 커밋 이력은 remote에 동일한 이름의 브랜치가 없을 경우, 삭제된다.

3) git rebase & merge

rebase란 ?
현재 브랜치의 Base를 재설정하고 합치는 것.

각각의 브랜치는 base를 가지고 있다. 해당 base로부터 코드를 수정하고 commit한다.

각각의 개발자가 merge를 하게 되면, git history가 서로 엉키게 된다. 이러한 분기 branch들의 history를 깔끔하게 재정렬 해주는 것이 rebase 기능이다.

develop 브랜치에서 이루어진 커밋 내역들을 master 브랜치에 rebase 하여 커밋 내용을 재배치하고 추가 커밋 메시지 없이 병합된다. 이때, Base가 바뀐 커밋들이 이동하는 것이 아닌, rebase될 브랜치에 복사되는 것이다.

(rebase 전 후를 살펴보면 commit message는 동일한데, commit id가 바뀐 것을 확인할 수 있다)

주의할 점은, rebase는 rebase 대상이 될 분기 브랜치에, merge는 기존의 중심 브랜치에 체크아웃된 상태에서 진행되어야 한다.

git rebase [base 브랜치명](master)

git checkout [브랜치명](master)

git merge [분기 브랜치명]

git restore

git의 파일 조작(특정 커밋으로 되돌리기, Unstaging 시키기) 의 기능을 지원하는 명령어

//특정 파일 HEAD Commit으로 복구하기
git restore [파일이름]

//특정 파일을 특정 Commit을 복구하기
//커밋 해시값에는 'HEAD'가 들어갈 수도 있다. 
git restore --source [커밋 해시값] [파일 이름]

//Staging Area에 올라간 파일 다시 Unstaging 시키기(git add 이전 상태)
git restore --staged [파일이름]

git reset vs git revert

git reset

git restore은 파일 단위의 제어를 명령했다면, git reset은 전체 파일을 제어하기 위한 명령어

전체 파일들이 특정 커밋으로 돌아가기 위해 사용된다.

//취소 하고 싶은 commit : aea80d9 
//현재 작업 위치인 HEAD의 포인터를 이전의 커밋으로 변경 
git reset --hard/--soft/--mixed 86cd811

—soft 옵션은 작업 디렉토리와 인덱스를 보존, 즉 파일이 스테이징된 상태를 유지한다.(커밋된 코드가 리셋 이후에도 사라지지 않는다.)

커밋만 변경한다.

—mixed 옵션은 변경 이력을 모두 삭제하지만 변경 내용(소스코드)는 유지한다. 이때 파일은 unstaged 상태이기 때문에 , add 명령어로 stage에 올리고 커밋해야 한다.

  • 옵션을 비워두면, —mixed 옵션이 적용된다.

커밋, 인덱스를 변경한다.

—hard 옵션은 현재 HEAD에서 추가된 변경사항을 모두 되돌려준다. 이때, git 저장소에서 관리하지 않는 파일(Untracked files)를 추가한 경우에는 reset 이후에도 그대로 유지된다. 해당 파일들 까지 삭제하고 싶은 경우에는 git clean을 따로 실행한다.

  • 주의 : 변경 이력을 모두 제거하기 때문에, 사용에 주의가 필요하고, 협업 시에는 상대방의 커밋내역을 지울 수 있기 때문에 사용을 권장하지 않는다.

커밋,디렉토리,인덱스를 변경한다.

hard 옵션으로 인해 지워진 commit을 되돌리려면 git reflog 명령어를 사용한다.

//삭제하기 이전까지의 모든 git 내역 출력
git reflog

//--hard 옵션으로 지운 커밋을 같은 명령어로 복구
git reset --hard [되돌리고 싶은 커밋 해시값]

HEAD^는 헤드의 직전 위치를 의미, 최신 커밋의 부모 커밋을 뜻한다.

//취소 하고 싶은 commit : aea80d9 
//현재 작업 위치인 HEAD의 포인터를 이전의 커밋으로 변경 
git reset --soft/--mixed/--hard HEAD^

git revert

하나의 커밋에서의 변경사항을 제거하기 위한 새로운 커밋을 만드는 명령어이다. git reset을 사용하면 현재 커밋과 대상 커밋 사이의 모든 커밋이 제거되는 반면에, 하나의 커밋만 제거하기 위해서는 git revert를 사용한다.

//특정 커밋의 변경사항 제거하기
git revert [커밋 해시값]

//바로 커밋으로 올리지 않고, stage area에 머무르도록 하기
git revert --no-commit [커밋 해시값]
//이후
git commit -m "커밋 메시지"

//여러개 커밋을 되돌리기
git revert [커밋 해시값] [커밋 해시값] ...

revert는 기본적으로 가장 최근의 커밋을 되돌릴 수 있도록 되어있다. 최신 커밋보다 더 이전의 커밋에 대해 revert를 하게 되면, 이후에 새로 생성된 커밋들의 내용과 충돌이 감지될 수 있다.

Solution : 최신 버전들을 모두 역순으로 revert 해서 원하는 지점의 커밋까지 revert 되어야 한다.

git stash

워킹 디렉토리에서 수정한 파일들을 임시저장한다.

  • 변경 사항을 임시로 저장 (이때 파일은 Modified이면서 Tracked 상태이거나, Staging Area에 등록된 파일이어야 한다)
  • 복원 시점에서는 stage 상태까지 복원 시키지 않는다.
  • pop 이후 다른 변경 사항과 충돌이 나는 경우는 merge 충돌과 마찬가지로 충돌을 해결해야 한다.
// 임시 저장할 내용 stash 등록
git stash 

// stash 내역 확인
git stash list

// stash에서 내용 꺼내오기
git stash apply

// stash에서 내용 꺼내오고, 목록에서 삭제
git stash pop

// 임시 커밋 내용에 메시지 부여하기
git stash -m '임시저장1'

.gitignore

Git의 root 디렉토리에 저장되어, Git Repository나 Staging Area에 추가되지 말아야 하는 폴더나 파일을 정의하는 파일. Staging Area에 올라가지 않기 때문에, tracking 되지 않는다.


참고

fork vs clone

https://velog.io/@imacoolgirlyo/Git-fork와-clone-의-차이점-5sjuhwfzgp

github vs gitlab

https://anothel.tistory.com/159

https://ko.wikipedia.org/wiki/깃랩

.git 폴더 구조 분석

https://tecoble.techcourse.co.kr/post/2021-07-08-dot-git/

git에서 만나는 이슈 정리/명령어 정리

https://parksb.github.io/article/28.html

pull vs fetch

https://devlog-wjdrbs96.tistory.com/236

origin, upstream, downstream

https://alkhwa-113.tistory.com/entry/upstream-vs-origin

git object 내부 파해치기

https://storycompiler.tistory.com/7

git restore

https://kotlinworld.com/281

git merge방식

https://mangchhe.github.io/git/2021/09/04/GitMerge/

sourcetree 에서의 git rebase

https://wbluke.tistory.com/26

git reset
https://git-scm.com/book/ko/v2/Git-도구-Reset-명확히-알고-가기

profile
버티면 다 되는거야.

0개의 댓글