ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 버전 관리 시스템(Version Control System) Git
    Programming🧑‍💻/Git & Github 2022. 12. 28. 22:56

    버전 관리 시스템이란?

    • 버전관리 시스템은 소스코드, 파일, 폴더 등의 변경사항을 추적하고 이를 기록으로 남겨 버전관리를 용이하게 해주는 시스템이다. 
    • 스냅샷들을 통해 변경사항을 남겨두고 이를 버전관리에 이용한다. 
    • 각 스냅샷들에는 변경사항과 함께 변경한 사람, 메시지 등의 메타정보가 포함되어 변경사항에 대한 파악을 돕는다. 
    • 단독으로 이용해도 변경사항을 추적하거나 개발을 병렬적으로 진행하는 등 여러가지 이점이 있다. 
    • 하지만 협업을 할 때 큰 효과를 발휘한다. 
    • 다른 사람이 어떤 사항을 변경하였는지 인지할 수 있어 동시개발에서 오는 충돌문제를 해결할 수 있다. 
      • 누가 이 모듈을 작성하였는가?
      • 특정 파일 또는 특정 라인을 '누가' '언제' '왜' 바꾸었는가?
      • 어디까지 단위테스트가 진행되었는가? 등등

     

    Git

    다양한 버전관리 시스템들이 존재하지만 그 중에서도 Git 이 대표적으로 사용된다.

    하지만 git 커맨드를 외우고 이를 사용하기만 한다면 문제가 발생할 때 원인을 모른채 리프레쉬 할 수 밖에 없다. 

    git을 제대로 사용하기 위해서는 git의 데이터 모델에 대한 이해가 필요하다. 

     

    https://missing.csail.mit.edu/2020/version-control/

    Git의 데이터 모델

    • 용어정리
      • blob : 파일을 의미한다.
      • tree : 디렉토리(폴더)를 의미한다. tree는 다른 폴더나 파일을 담을 수 있다.
        • 따라서 트리는 map으로써 데이터를 저장하는데 다른 tree나 bolb의 이름에 tree 또는 bolb을 맵핑하고 있다.
    // file(blob)은 bytes(데이터)의 묶음
    
    type blob = array<byte>
    
    // a directory(tree)는 파일또는다른트리의 이름과 파일또는다른트리를 맵핑하는 map
    
    type tree = map<string, tree | blob>
    
    
    // parents : 참조할 대상인 되는 부모커밋들의 목록
    // author, message : 같은 수정한 사람과 목적등을 알리는 메타데이터
    // snapshot : 참조와 저장으로 구성되는 스냅샷 
    // 위의 항목들로 commit이 구성된다. 
    
    type commit = struct {
        parents: array<commit>
        author: string
        message: string
        snapshot: tree
    }

     

    스냅샷(Snap Shots)

    스냅샷은 git에 의해 변경사항이 추적되는 최상위 트리(폴더)를 의미한다. 

    즉 하나의 구분되는 프로젝트 버전을 의미한다. 

    위의 그림을 통해 용어들을 정리해보면

    • root 트리(스냅샷) : git에 의해 추적되는 위 프로젝트의 최상위 트리로 블랍하나와 다른 트리하나를 구성요소로 가지고 있다. 
    • foo 트리 (폴더) : 최상위 트리에서 나온 하위 트리 
    • bar.txt 블랍 (파일) : foo 트리에 속하는 하나의 파일이며 내용으로 "hello world"를 가지고 있다. 
    • baz.txt 블랍 (파일) : root 트리에 속하는 하나의 파일이며 내용으로 "git is wonderful"를 가지고 있다. 

     

    git의 데이터 모델 (방향성 비순환 그래프)

    • 시간스탬프 선형 모델
      • 일반적으로 버전관리모델을 구성한다고 할 때 생각해볼 수 있는 수단은 시간순서에 따라 선형적으로 폴더들을 나열하는 것이다. 
      • 위의 그림을 예로 들면 bar.txt 내용에 변화가 생기면 ver2로 해서 전체 내용을 새로 저장하는 것이다. 
      • 하지만 이러한 모델을 사용하면 전체 내용 중 아주 일부만 변경이 생겨도 전체 내용을 저장하여 새로운 버전을 구성하기 때문에 변경되지 않는 부분도 새롭게 저장함으로써 저장공간을 낭비하게 된다. 
    • 방향성 비순환 그래프
      • git은 이러한 문제를 해결하기 위해서 방향성 비순환 그래프 모델을 사용한다. 
      • 스냅샷은 최상위 폴더로 프로젝트 전체를 저장하는 트리를 의미한다. 
      • 각 스냅샷은 이전 스냅샷인 "부모 집합"을 참조하면서 변경되지 않은 부분을 '또' 저장함으로써 공간을 낭비하는 점을 해결한다.
      • 예를 들어 bar.txt 내용에 변화 생기면 새로운 스냅샷은 변경이 생긴 bar.txt에 대해서만 저장하고 나머지 변경이 없는 부분은 선행하는 부모들이 저장하고 있는 데이터를 참조하는 형식으로 트리를 구성한다. 
      • 즉 새로운 스냅샷은 프로젝트 전체 내용을 구성하고 있는 것은 맞지만 변경이 생긴 부분만 실제로 저장하고 있다. 

     

    커밋(commit)

    위와 같이 변경되는 부분만 저장하며 나머지 부분은 참조하여 구성된 새로운 스냅샷을  커밋(commit)이라 한다.

     

     

    스냅샷들의 연결 과정

    • o 는 각 커밋(commit) 또는 스냅샷을 나타낸다. 
    • 화살표들은 각 커밋이 참조하고 있는 부모들의 방향을 나타낸다. 
    • 프로젝트를 진행하던 중 기존 프로그램에서 발생하는 버그를 수정하면서 새로운 기능을 추가하고자 한다. 
    • 이때 같은 프로젝트 내에서 둘을 같이 작업하게 되면 작업간의 충돌이 발생하며 원할한 작업이 어려울 수 있다. 
    • 이를 해결하기 위해 두가지 커밋을 구성한다.(가지를 친다.) 
    • 위쪽 가지에서 뻗어나가는 커밋(스냅샷)은 버그를 수정하면서 변경되는 부분의 데이터들만 가지고 나머지 부분은 부모들을 참조한다. 
    • 아래쪽 가지에서 뻗어나가는 커밋(스냅샷)은 새로운 기능을 추가함에 따라 변경되는 부분의 데이터들만을 가지고 나머지 부분은 역시 선행하는 부모들을 참조하고 있다. 

    • 위와 같이 개발을 병렬적으로 진행함으로써 작업들의 충돌로 인한 이슈를 피할 수 있게 된다. 
    • 병렬적으로 개발이 진행되다가 새로운 기능에 대한 작업이 완료되었으면 병합(merge)를 하게 된다. 
    • 새로운 스냅샷은 버그수정 가지와 신기능 가지의 커밋을 참조함으로써 병합을 진행한다. 
    • 물론 병합으로 인한 충돌 문제는 항상 고려해야 한다. 

     

    Git WorkFlow

    Staging area의 필요

    • 커밋은 부모가 되는 커밋들과 비교하여 변경된 부분만을 저장하고 나머지 부분을 참조하여 새로운 스냅샷을 구성한다. 
    • 만약에 A기능과 B기능에 대해 작업을 하였는데 A에 대해서는 완료되었으나 B는 아직 고쳐야할 부분이 남아있다. 
    • 이때 Staging area 없이 working directory와 부모가 되는 커밋을 비교하면 A,B 변경된 부분이 모두 새로운 커밋에 반영된다.
    • 새로운 작업 내용들중 반영하고 싶은 내용만 commit에 넣을 수 있도록 Staging area를 만들었다.
    • Staging area에 있는 파일들만을 부모가 되는 커밋들과 비교하게 함으로써 원하는 변경사항만 커밋에 반영할 수 있게 한다. 
    • working directory에서는 A와 B 모두에 변경이 생겼지만 A만 staging area에 올려두고 커밋을 만들면 부모가 되는 커밋과 비교하는 과정에서 A의 변경사항만을 새로운 커밋에 저장하고 나머지 부분들은 부모 커밋들을 참조한다. 
    • 즉 Staging area를 통해 원하는 변경사항만 커밋에 반영할 수 있게 되었다. 

     

    Flow

    출처 : 드림코딩 깃, 깃허브 제대로 배우기 (기본 마스터편, 실무에서 꿀리지 말자)

    • 처음 깃 저장소를 init하면 working directory에 있는 파일들은 추적되지 않는 상태(untracked)로 되어 있다. 
    • 이 추적되지 않는 파일들을 커밋하기 위해 staging area에 add 하면 이제 해당 파일들은 추적되는 상태(tracked)로 바뀐다. 
    • 추적되는 상태가 된 파일들은 이후 변경사항들이 생기면 git이 변경사항을 인지하고 commit 여부를 묻는다. 
    • 추적되는 파일들은 git이 현재 Head 커밋과 비교하여 변경된 부분을 캐치한다. 
    • staging area에 올라온 파일들은 아직 커밋되지 않았어도 추적되는 상태이기 때문에 staging area에 올라온 파일과 working directory에 있는 파일을 비교하여 변경된 부분을 캐치한다. 
    • 아직 staging area에 있는 파일이 working directory에서 변경이 일어났으면 다시 해당 파일을 add해서 변경된 부분을 staging area에 반영해 주어야지 그렇지 않고 커밋을 하게 되면 working directory에 변경이 일어난 사항이 제외된 기존에 staging area에 올라와 있던 파일이 커밋이 된다. 

     

    Git Command

    • 기존에 있던 프로젝트 폴더를 사용하거나 새로운 프로젝트를 위한 프로젝트 폴더를 만든다. 
    mkdir 프로젝트폴더
    • git init : git이 해당 프로젝트 폴더를 추적할 수 있도록 프로젝트 폴더내에 git repository를 생성한다. 
    • 새로 만든 .git 폴더에 참조 또는 객체의 형태로 프로젝트의 데이터들이 저장되어 버전을 관리할 수 있게 된다. 
    git init
    • ls를 이용해 확인해보면 폴더내에 .git 폴더가 보이지 않지만 ls -a를 이용해 숨겨진 폴더까지 확인하면 .git 폴더를 확인할 수 있다. 
    ls -a
    • git help  : git 커맨드의 매뉴얼을 출력한다. 
    git help 커맨드
    • git status : 현재 git 저장소의 상태를 볼 수 있다. 
    git status
    • git add : staging area에 커밋할 파일들을 올려둔다. 
    git add 파일이름
    • git commit : staging area에 있는 파일들을 바탕으로 새로운 커밋(스냅샷)을 구성한다. 
      • 커밋을 하면 커밋에 대한 메시지를 적을 수 있는 텍스트에디터가 나오고 이곳에 커밋에 대한 메타 데이터를 작성한다.  
      • 처음에 i를 눌러서 편집모드로 들어가기 내용작성후 esc -> :x
      • vi로 인한 문제시 vi weekrep 후 vi 종료시키기 :x
    git commit
    •  git log : 현재 repository에 등록되어 있는 커밋들에 대한 정보를 출력한다. 
    git log
    • git log --all --graph --decorate : 현재 등록되어 있는 커밋들을 그래프의 형태로 출력한다. 
     git log --all --graph --decorate
    • git diff 파일이름 : 현재 working directory에 있는 변경된 파일을 staging area에 해당 파일의 변경전 파일이 있다면 있다면 그 파일과 없다면 head(제일 최근 커밋)와 비교되어 변경된 사항이 무엇인지 즉 새로운 커밋에 새로 저장되는 내용이 무엇이 될지 출력해준다. (무엇과 비교해도 결과는 같지만 대상이 다르다)
    git diff 파일이름
    • git diff 커밋이름 파일이름 : 현재 파일을 특정 스냅샷과 비교하여 차이를 보여준다.  (스냅샷 이름 : 해시코드 앞 8자리)
    git diff 커밋이름 파일이름
    • git checkout 커밋이름 파일이름 : 지정한 커밋의 파일을 working directory에 가져온다. 
    git checkout 커밋이름 파일이름

     

    ★HEAD : 현재 타고 있는 줄기의 가장 끝 부분 커밋

     

    • git checkout  커밋이름 : 지정한 커밋으로 Head를 옮긴다. 
    git checkout 커밋이름
    • git branch : 현재 갈라진 줄기들의 이름을 보여준다. (별표시가 되어있는 줄기가 현재 HEAD의 위치)
    git branch
    • git branch 새로운줄기이름 : 현재 있는 커밋에서 새로운 줄기를 생성한다. 
    git branch 새로운줄기이름
    • git checkout 줄기이름 : 지정한 줄기로 Head를 옮긴다. 
    git branch 줄기이름

     

    ★ branch 이름은 해당 줄기의 마지막 커밋 또한 지칭한다. 

    • git merge 병합할커밋(줄기)이름 : 현재 Head가 있는 줄기에 지정한 커밋(줄기)을 병합시킨다. 
    git merge 병합할커밋(줄기)이름
    • git merge --abort : 병합 중단하기
    git merge --abort
    • git mergetool : 병합과정에서 발생하는 충돌이슈를 해결을 위한 툴 제공
    git mergetool
    • git rebase 리베이스할가지이름 : 현재가지의 분기점(베이스)을 다른 가지의 끝부분으로 변경한다. 
    git rebase 리베이스할가지이름
    git checkout experiment
    git rebase master

    출처 : https://git-scm.com/book/ko/v2/Git-%EB%B8%8C%EB%9E%9C%EC%B9%98-Rebase-%ED%95%98%EA%B8%B0

     

     

    • git remote : 원격저장소 리스트 출력
    git remote
    • git remote add 원격저장소이름 url : 원격저장소 추가
    git remote add <name> <url>
    • git push 원격저장소 올릴로컬가지:저장되는원격가지 : 원격저장소에 파일들을 저장
    git push <remote> <local branch>:<remote branch>
    • git branch --set-upstream-to=원격저장소이름/원격저장소가지 : 위치한 로컬가지를 지정한 원격저장소의 가지가 동기화 하도독 설정한다. 
    git branch --set-upstream-to=<remote>/<remote branch>
    •  git fetch : 원격저장소로부터 커밋을 가져온다. 
    git fetch
    •  git pull : fetch + merge
    git pull
    •  git clone 원격저장소url 저장할폴더 : 원격저장소를 가져와서 로컬에 저장한다. 
    git clone 원격저장소url 폴더이름

     

    • git commit --amend : 커밋내용을 편집한다. 
    • .gitignore : 해당파일에 git이 추적하지 않을 파일 목록들을 등록하면 git이 해당 파일은 추적하지 않음

    ★ 출처

     

    Version Control (Git)

    Version Control (Git) Version control systems (VCSs) are tools used to track changes to source code (or other collections of files and folders). As the name implies, these tools help maintain a history of changes; furthermore, they facilitate collaboration

    missing.csail.mit.edu

     


    'Programming🧑‍💻 > Git & Github' 카테고리의 다른 글

    차근 차근 살펴보는 Git  (0) 2024.04.28

    댓글

Designed by Tistory.