버전 관리 시스템(Vesrion Control System, VCS)?
파일을 여러번 수정하고 각 수정마다 복사, 백업, 저장을 해본 경험이 있을 것이다. 우리는 이미부터 버전 관리를 해오고 있었다. 이처럼 버전 관리는 동일한 파일에 대해 여러 버전을 정의하고 관리하는 것을 의미한다.
이런 버전 관리를 통해 소스코드를 백업(Backup)해서 만약의 사태를 대비하고, 이전 상태로 쉽게 돌아갈 수 있고( Recovery), 여러 명이 동시에 작업을 할수 있어 다른 사람과의 협업(Collaboration)을 할 수 있게 된다.
버전 관리? 변경 관리? 형상관리?
변경관리는 소스 코드의 변경사항을 관리하는 것이고 버전관리는 이러한 변경사항을 버전이라는 개념을 통해 관리한다는 점에서 그 차이가 있으며 형상관리는 소프트웨어 프로젝트와 관련된 모든 변경사항을 관리한다는 점에서 형상관리 안에 버전 관리가 포함되어 있다고 볼 수 있다.
변경관리 ⊆ 버전관리 ⊆ 형상관리
- 버전 관리(VC; Version Control, RC; Revision Control)
- 소스 관리(SC; Source Control), 소스 코드 관리(SCC; Source Code Control)
- 형상 관리(CM; Configuration Management)
: 시스템이나 프로젝트의 구성 요소를 식별, 관리, 추적하고 보고하는 과정 - 소프트웨어 구성 관리(SCM; Software Configuration Management)
: 소프트웨어 개발 과정에서 변경 사항을 관리하고 통제하는 활동을 의미 - 그러나 변경관리, 버전관리, 형상관리는 명확하게 구분되지 않고 대체로 비슷한 의미로 쓰인다.
버전 관리 시스템은 파일 변경 사항을 시간에 따라 기록하고, 필요할 때 특정 버전을 다시 호출할 수 있는 시스템을 일컫는다.
- 시스템을 통해 파일의 이름을 바꾸지 않고도 버전관리 가능, 내용의 변경 사항은 컴퓨터가 관리하도록 한다.
이런 버전 관리 시스템 ( Version Control System, VCS)을 사용하면 동일한 정보에 대해 여러 버전을 관리하게 되며, 버전을 통해 시간에 따른 변경 사항 및 변경자를 확인할 수 있고, 각 파일을 이전 상태로 되돌릴 수 있고, 프로젝트를 통째로 이전 상태로 되돌릴 수 있고, 시간에 따라 수정 내용을 비교해 볼 수 있고, 누가 문제를 일으켰는지도 추적할 수 있고, 누가 언제 만들어낸 이슈인지도 알 수 있다. VCS를 사용하면 파일을 잃어버리거나 잘못 고쳤을 때도 쉽게 복구할 수 있다. 이런 모든 장점을 큰 노력 없이 이용할 수 있다.
버전 관리 시스템의 종류
예시 1 과 같이 많은 사람은 버전을 관리하기 위해 디렉토리로 파일을 복사하는 방법을 사용한다. 하지만 작업하던 디렉토리를 지워버리거나, 실수로 파일을 잘못 고칠 수도 있고, 잘못 복사할 수도 있는 등 실수의 여지가 크기 때문에 버전의 관리가 잘못되기 쉽다.
로컬 버전 관리 시스템(Local Version Control System, LVCS)
이를 해결하기 위해 로컬 버전 관리 시스템이 고안되었다. 서버 없이 로컬 내에 간단한 데이터베이스를 사용해서 파일의 변경 정보(버전)를 관리한다. 구현이 쉽고 단순하여 개인적인 프로젝트에는 적합하지만 협업에는 쓰기 힘들다. (파일이 통째로 날아가 버린다면 복구할 방법이 없다.)
- 대표적인 로컬 버전 관리 시스템으로는 RCS(Revision Control System)가 있다.
- RCS는 Patch Set(파일에서 변경되는 부분)을 관리한다.
- RCS는 파일에서 변경되는 부분(Patch)만 기억하므로 용량 문제를 해결한다.
- Patch Set은 특별한 혁식의 파일로 저장한다.
- Patch Set을 적용하여 모든 파일을 특정 시점으로 되돌릴 수 있다.
로컬 버전 관리 시스템은 로컬에서 관리 되기 때문에 협업을 해야하는 상황에서는 버전관리가 하기 쉽지 않다는 단점이 있다. 이럴 때 생기는 문제를 해결하기 위해 중앙 집중식 버전 관리 시스템(Centralized Version Control System, CVCS)가 개발되었다.
중앙 집중식 버전 관리 시스템(Centralized Version Control System, CVCS)
중앙 집중식 버전 관리 시스템(Centralized Version Control System, CVCS)은 파일을 관리하는 서버가 별도로 있고 사용자(클라이언트)들은 특정 버전의 스냅샷(snapshot)을 로컬에 받아 사용 (Checkout)한다.
모든 클라이언트의 로컬 데이터베이스를 관리하는 것이 아니라 모든 클라이언트들이 단 하나의 데이터베이스만을 바라보므로 동기화 문제가 없고 간단한 협업이 가능하며 관리자는 누가 무엇을 하고 있는지 알 수 있어 관리하기 편하다는 장점이 있다.
- 대표적인 중앙 집중식 버전 관리 시스템으로는 SVN(SubVersion), CVS(Concurrent Versions System)이 있다.
하지만 중앙 집중식 버전 관리 시스템에도 단점이 있다. 대표적으로 중앙 서버에 문제가 발생한다면 문제 발생 시간 동안 협업 및 버전 관리가 이루어 지지 않는다는 것이다. 만약 문제가 커져 중앙 서버의 데이터에 문제가 생기면 복구하기가 힘들다는 문제가 있다.(로컬 VCS 시스템도 이와 비슷한 결점이 있다.)
- 또한 모든 버전 관련 동작은 서버에서 처리 되어 서버의 부하가 크며 오프라인 상태에서는 버전 관리 시스템을 사용할 수 없다는 문제가 있다.
이를 해결하기 위해 등장한 것이 분산식 버전 관리 시스템(Distributed Version Control System, DVCS)이다.
분산식 버전 관리 시스템(Distributed Version Control System, DVCS)
중앙 집중식 버전 관리 시스템(CVCS)에서 서버에서 모두 파일 및 파일 변경 이력등 을 독점하여 문제가 발생했기 때문에
분산 버전 관리 시스템에서 클라이언트는 단순히 파일의 마지막 스냅샷(snapshot)을 받아 사용(Checkout) 하지 않고 클라이언트들은 모두 저장소, 히스토리를 전부 복제한 서버의 백업본을 가진다.
그렇기에 분산식 버전 관리 시스템에서는 서버가 죽거나 오프라인 상태에서도 버전 관리를 할 수 있다. 대부분의 버전 관리가 로컬에서 이루어지므로 속도도 빠르고 수정시에도 로컬에서 이루어 지기 때문에 충돌의 염려 없이 수정할 수 있으며, 최종적으로 서버에 올릴 때만 신경을 쓰면 된다.
- 다만 중앙 집중식 버전 관리 시스템에 비해 복잡하고, 동기화 문제가 있다는 단점이 있다.
분산식 버전 관리 시스템에는 Git, Mecurial, Bazaar 등이 있고 가장 널리 사용되는 것이 Git이다.
깃(Git)이란?
깃(Git)은 버전 관리 시스템( Vesrion Control System, VCS )에 속하는 분산형 버전 관리 시스템의 한 종류이다.
그렇다면 깃(Git)을 왜 사용할까?
깃을 사용함으로서 얻는 장점은 매우 많기 때문에 사용된다. 다른 개발자들과 협업을 진행하다 보면 잦은 업데이트가 발생한다. 깃을 사용하면 굳이 번거로운 과정 없이도 다른 개발자들과 소스코드를 주고 받을 필요 없이 같은 파일을 여러명이 동시에 작업하는 병렬 작업이 가능하다.
- 여러 브랜치를(Branch) 형성해 작업한 뒤, 마지막에 합치는 방식(Merge)
- 또한 쉽게 이전 버전으로 이동할 수 있으며 다시 원래의 버전으로 돌아오는 것 또한 자유롭다.
깃은 분산 버전 관리 시스템으로 중앙 서버가 필요 없다. 즉, 인터넷이 연결 되어 있지 않은 상황에서도 작업이 가능하며, 도중에 저장소에 이상이 생겨도 쉽게 복구할 수 있다.
깃(Git)의 기본 용어
1. Repository (저장소) : Git으로 관리되는 파일이나 폴더들이 포함된 프로젝트의 '소스 저장소'를 의미한다. 저장소를 통해서 작업자가 진행, 변경했던 사항들에 대해 알 수 있다.
- Local Repository : 개인 컴퓨터에 저장된 로컬 버전의 프로젝트 저장소를 의미(개인 전용 저장소)
- Remote Repository : 원격 서버에 저장되는 프로젝트 저장소를 의미(공유 저장소)
2. Working Tree(Working Directory) : 작업자의 현재 시점
- 파일의 수정, 저장등의 작업을 하는 디렉토리
3. Staging Area (Index) : 저장소에 커밋( Commit )하기 전에 커밋을 준비하는 위치
- Working Directory에서 작업한 파일을 Local Repository에 전달하기위해 파일을 분류하기 위한 공간이다.
- 예를 들어 Working Directory에서 5개의 파일을 수정하고 2개의 파일만 버전으로 생성하려고 한다면 2개의 파일만 Staging Area로 넘기면 된다.
4. Commit : 현재 변경된 작업 과정들에 대한 점검을 마친 뒤, 확정하고 저장소에 저장하는 작업
- 각각의 커밋 단계는 의미 있는 단계로 커밋 로그를 남긴다.
5. Checkout : 특정 시점이나 branch의 소스 코드로 이동하는 것을 의미한다.
- 과거 여러 시점의 소스 코드로 이동할 수 있다.
- 이전 버전 작업을 불러오는 것.
6. Branch : Repository(저장소)에서 독립적으로 어떤 작업을 하기 위한 현재 상태를 복사하여 공간을 생성하여 작업을 진행한다(가지 또는 분기점).
- Branch에서 작업을 완료하고 Merge를 수행한다.
7. Merge : 다른 Branch와 현재 Branch의 내용을 합치는 작업, 즉 병합을 말한다.
- Branch와는 다소 반대되는 개념이다.
- 병합 과정 중 두 branch에서 하나의 동일한 파일에서 서로 다른게 수정한 경우 충돌이 발생하며, 병합이 일시정지 된다.
- 충돌 부분에 대해 직접 수정하거나 Merge Tool 등을 활용하여 충돌을 해결한 뒤 병합을 계속 진행한다.
8. SnapShot : 특정 시점에서 파일, 폴더 또는 워크 스페이스의 상태를 의미한다.
- 스냅샷을 통해 특정 시점에 어떤 파일에 어떤 내용이 기록되어 있었는지, 폴더 구조는 어떠했는지, 어떤 파일이 존재했는지 등 저장소의 모든 정보를 확인할 수 있다.
- Git에서는 새로운 버전을 기록하기 위한 명령인 커밋(commit)을 실행하면 스냅샷이 저장된다
1. 개발자는 작업 디렉토리에 있는 파일을 수정
2. 수정된 파일을 모아 정리하여 만든 Snapshot을 Staging 디렉토리에 추가하고 저장
3. GIT 디렉토리에 저장 (Staging 디렉토리에 저장된 파일을 앞으로 영구 불변의 상태를 유지하는 Snapshot 으로서 git 디렉토리에 저장하는 것)
9. Clone : 원격 저장소로부터 소스코드를 로컬 저장소로 복제하는 것을 의미한다.
10. HEAD : 커밋을 가리키는 묵시적 참조 포인터, 최종적인 커밋 작업의 위치를 가리킨다.
- 새로운 커밋은 이전 부모 커밋을 기반으로 커밋을 생성, HEAD는 부모 커밋을 가리킨다.
- 처음 커밋에는 HEAD의 포인터는 없다, 최소한 한 번 이상 커밋을 해야만 HEAD가 존재
- 커밋될 때마다 이동, 마지막 커밋 위치를 가리킨다. 커밋이 변화한 최종 시점을 의미
깃(Git)의 구성 및 동작방식
1. Working Directory, 말 그대로 로컬 저장소에 접근할 수 있으며, 실제로 파일을 생성하고 수정하는 공간안에서 작업을 진행합니다.(.git 폴더가 있는 폴더)
깃은 Working Directory에 있는 파일들을 ‘추적됨’(tracked)'과 ‘추적되지 않음’(untracked)상태로 구분한다. 파일을 관리하려면 깃에 추적하라고 통지해야 하며 통지하지 않은 파일은 깃에서 따로 추적하지 않는다.
- Working Directory에 파일을 추가하거나 수정했다고 해서 깃이 자동으로 관리하지 않으며 새로 생성된 파일은 모두 ‘추적되지 않음(untracked)’ 상태이다.
- 추적되지 않는 상태의 파일들은 별도로 git add 명령어를 실행하여 추적(tracked) 상태로 변경해야 한다.
2. 작업이 완료되면 파일이 추가되거나 수정 및 삭제가 발생한 파일들을 git add 명령어를 실행하여 ‘추적됨’(tracked)'의 파일들을 스테이지 영역에 추가한다.
스테이지 영역에 등록된 파일들은 또 다시 stage 상태와 unstage 상태로 구분한다. 깃에 변화 이력을 기록하려면 파일들의 최종 상태가 stage 상태여야 하며 unstage 상태라면 파일에 변화가 있다는 것을 의미한다.
- 스테이지 영역에 있는 파일과 Working Directory안에 있는 파일 내용에 차이가 있을 때는 unstage 상태가 된다.
- 파일이 수정되어 임시적으로 스테이지 목록에서 제외된 것으로 다시 git add 명령어를 사용하면 스테이지에 다시 추가할 수 있다.
파일에 변화가 있다는 것은 워킹 디렉터리에서 파일이 수정 되었다는 것을 의미한다. 파일이 수정되면 워킹 디렉터리와 스테이지 간 내용이 일치하지 않기 때문에 스테이지는 수정한 파일과 원본 파일을 구분하기 위해 수정함(modified) 상태와 수정하지 않음(unmodified) 상태로 구분 한다.
- 스테이지에 등록된 파일은 깃이 추적 관리하므로 변경 내역은 영구적으로 기록된다.
- tracked 상태인 파일이 수정되면 스테이지는 파일 상태를 modified 상태로 변경합니다.
- 수정된 파일은 스테이지에서 잠시 제외(unstage)된다.
- 깃은 수정 여부만 체크해 주기 때문에 modified 상태로 변경된 파일은 스테이지로 재등록(add)해야한다.
- unmodified 상태는 tracked 상태이면서 스테이지에 등록한 후 어떤 수정도 하지 않은 원본 상태를 의미한다.
3. 스테이지 영역 안에 존재하는 모든 staged된 파일은 명령어 커밋(commit)을 통해 스냅샷(snapshot)으로 만들어진다.
Git에서는 새로운 버전을 기록하기 위한 명령인 커밋(commit)을 실행하면 스냅샷(snapshot)방식을 통해 파일 변화를 깃 저장소에 영구적으로 기록한다.
- HEAD와 스테이지 영역 간 차이를 비교하여 새로운 객체를 생성한다..
- 우리가 커밋을 하면 Git은 기본적으로 스냅샷을 저장한다
- 스냅샷은 특정 시점에서 파일, 폴더 또는 워크스페이스의 상태를 의미한다.
- 스냅샷을 통해 특정 시점에 어떤 파일에 어떤 내용이 기록되어 있었는지, 폴더 구조는 어떠했는지, 어떤 파일이 존재했는지 등 저장소의 모든 정보를 확인할 수 있다.
- .git 폴더 내부에 구현되며 staged 내용은 .git/index, Snapshot 내용은 .git/HEAD파일 에 저장된다.
스냅샷 방식은 각 버전에서 파일의 최종 상태를 직접 저장한다.
- 예를 들어, 버전 4에서 파일 A, B, C가 있고, 버전 5에서 파일 B와 C만 변경되었다면, 버전 5의 스냅샷은 파일 A는 버전 4의 파일 A를 그대로 참조하고, 파일 B와 C는 각각의 최신 버전이 저장된다.
- 따라서 Git은 단순히 해당 버전의 파일을 직접 참조하면 되기 때문에, 크기가 크고 커밋이 많은 프로젝트에서도 빠르게 작업을 할 수 있습니다.
그럼 깃은 커밋을 할 때마다 변경된 파일에 대해 용량이 기하급수적으로 증가하지 않을까? 라는 생각을 할 수 있다.
히스토리는 개념적으로 스냅샷의 연속이자 델타의 연속이기도 하다.
깃은 기본적으로 성능과 편리성을 위해 스냅샷으로 히스토리 데이터를 다루지만 적절한 시점에 GC(Garbage Collection)가 실행, 압축 및 델타화를 하여 최적화 하여 문제를 해결한다.
- 커밋을 하면 그 시점의 스냅샷이 저장되는 것이고 그 커밋과 부모의 커밋을 비교(diff)하면 델타를 얻을 수 있다.
- 커밋은 영구적으로 저장하는 것이기 때문에 언제든지 Checkout해서 그 시점의 스냅샷을 얻을 수 있고 비교해서(diff) 델타를 얻을 수도 있다.
마지막 버전의 스냅샷만을 통쨰로 저장하고 이전 버전들은 델타(diff 파일)를 저장한다. 이렇게 하면 버전별로 전체 스냅샷을 모두 저장하지 않아도 마지막 스냅샷을 기준으로 특정 시점의 스냅샷을 만들 수 있기 때문에 저장소의 크기도 자연히 줄어든다.
- 그림에서 rev6를 요구하면 rev6의 파일을 그대로 반환하고 rev4를 요구하면 rev6 파일에 rev5, rev4의 델타를 적용해서 반환한다.
- 마지막 버전의 파일이 스냅샷인 이유는 우리가 질의하는 파일은 대부분 마지막 버전의 파일이기 때문이다.
커밋 후 삭제는 파일이 삭제 또는 변화된 것으로 간주합니다. 따라서 커밋된 파일은 리셋으로 삭제한 후 정리해 주어야 한다.
참조
- https://conceptbug.tistory.com/entry/Git%EB%B2%84%EC%A0%84%EA%B4%80%EB%A6%ACVersionControl%EB%9E%80-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EB%AA%A9%ED%91%9C%EB%8A%94
- https://kurukurucoding.tistory.com/68
- https://gitscm.com/book/ko/v2/%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0%EB%B2%84%EC%A0%84-%EA%B4%80%EB%A6%AC%EB%9E%80%3F
- https://inpa.tistory.com/entry/GIT%E2%9A%A1%EF%B8%8F%EA%B0%9C%EB%85%90%EC%9B%90%EB%A6%AC%EC%89%BD%EA%B2%8C%EC%9D%B4%ED%95%B4#git_%EC%9E%91%EB%8F%99_%EA%B5%AC%EC%A1%B0
- https://www.juicylog.com/vcs--feat-git
'Git' 카테고리의 다른 글
[Git] 커밋 취소/되돌리기/덮어쓰기(reset / revert / amend) (0) | 2024.06.04 |
---|---|
[Git] 태그(tag)의 기초와 사용법 (0) | 2024.06.02 |
[Git] 깃(Git)의 원리(2, commit)와 깃 객체(Git Object) (0) | 2024.06.02 |
[Git] 깃(Git)의 원리(2, commit)와 깃 객체(Git Object) (0) | 2024.05.28 |
[Git] 깃(Git)의 원리(1, add) (0) | 2024.04.11 |