2024-07-31 (TIL)

SanE·2024년 7월 31일
0

컴퓨터공학

목록 보기
19/23
Image

👨🏻‍💻학습 내용


💡 VCS 버전관리 시스템

VCS란 (Version Control System)의 줄임말로 파일 변경을 시간에 따라 기록하고 필요할 때 특정 버전을 호출할 수 있는 시스템을 의미한다.

종류

  • SCCS (Source Code Control System) : 최초의 버전 관리 시스템으로 파일 단위의 버전 관리를 제공한다.
    • 장점 : 최초의 형상을 저장하고 차이점만 저장하기 때문에 저장 공간을 크게 줄일 수 있다.
    • 단점 : 다중 사용자 환경에서 동시성 제어가 한계가 있다.
  • RCS (Revision Control System) : 로컬 버전 관리 시스템 중 하나. 파일 단위 버전 관리 제공, 파일의 변경 내역을 순차적으로 추적하는 것이 목적.
    • 장점 : 변화가 빈번하게 발생하는 파일에 유용.
    • 단점 : 다중 사용자 환경에서 사용이 제한적이다.
  • CVS (Concurrent Versions System) : 중앙 집중식 버전 관리 시스템. RCS 기반이지만, 파일 단위가 아니라 프로젝트 단위의 버전 관리 제공.
    • 장점 : 클라이언트 - 서버 구조이기 때문에 다중 사용자 환경을 제공.
    • 단점 : 불안정한 동시성 제어, 원격 저장소의 느린 속도.
  • Mercurial : 분산식 버전 관리 시스템.
    • 장점 : HTTP, HTTPS, SSH 프로토콜 지원. 일관된 명령어를 통해 실수로 인한 데이터 손상을 최대한 배제, Python을 기반으로, C를 서브로 개발되어 대규모 코드에서도 고성능을 제공.
  • Git : 리누스 토발즈가 리눅스 커널 프로젝트를 위해 개발한 분산식 버전 관리.
    • 장점 : 빠른 속도, 데이터 무결성, 대규모 프로젝트 지원 능력, 높은 유연성 제공.
    • 단점 : 명령어와 옵션에 익숙해지고 학습에 비용이 드는편.

💡 git

이번 git의 대한 설명은 이전의 포스트의 내용을 기반으로 작성을 했다.

파일 상태

깃에서 우리가 명령을 실행했을 때,
각각의 파일은 무조건 4가지 상태 중에 하나이다.

아래 그림은 동작에 따른 상태 변화를 보여준다.

  • Untracked : git에서 관리하지 않는 파일.
  • Staged : 커밋으로 기록될 상태.
  • Modified : git에서 관리하는 파일을 수정했을 때.
  • Unmodified : 관리 대상의 파일이 수정되지 않았을 때.

여기까지 우리가 이미 알고 있던 지식과 함께 생각해보면 어쩌면 당연한 이야기이다.
그럼 여기서 우리가 알고있던 지식에서 Git 객체를 합쳐서 생각을 해보자.

Git 객체

종류

  • Blob : 원본 컨텐츠 저장.
  • Tree : 프로젝트가 있는 디렉토리 저장. 하나 이상의 블록 객체 혹은 다른 트리가 포인터로 포함된다. 각각의 블롭 혹은 트리 객체의 해시값을 가진다.
  • Commit : 커밋이 수행될 때마다 해당 커밋의 모든 정보를 추상화. 부모 커밋의 해시값과 트리 객체의 해시값을 가진다.
  • 태그 : 특정 커밋에 대한 이름을 붙인다.

Blob 객체

git init 명령을 치면 .git 폴더가 생기고 그 안에 여러 파일이 생긴다.
여기서 만약 우리가 아래 보이는 파일을 추가했다고 가정해보자.

// test.txt
Hello World!!

그럼 .git/objects 위치에 디렉토리가 하나 생기고 디렉토리 안에 수상한 이름의 파일이 생성될 것이다.

결론부터 이야기하면 해당 디렉토리명과 파일명은 파일 내용 "Hello World"의 해시값을 기준으로 만들어진다.

참고 - SHA 256 으로 해시값을 만들어주는 사이트

"Hello World!!" 의 해시값

096c0a72c31f9a2d65126d8e8a401a2ab2f2e21d0a282a6ffe6642bbef65ffd9

해시 값을 기준으로 디렉토리 이름과 파일명은 다음과 같이 만들어진다.

  • 디렉토리명 : 해시 값에서 앞자리 2개 (ex : 09)
  • 파일명 : 나머지 해시값 38개(ex: 6c0a72c31f9a2d65126d8e8a401a2ab2f2e21d0a282a6ffe6642bbef65ffd9)

따라서 git add 명령이 들어오면 아래와 같이 Blob 객체가 만들어진다.

  • 파일 내용을 기반으로 해시값 생성.
  • 해시값을 이용해 디렉토리 생성.
  • 해시값을 이용해 파일 생성.
    • 파일은 zlib으로 기존 파일을 압축해서 저장.

Tree 객체

  • 특정 시점의 디렉토리를 의미.
  • git commit을 할 때마다 생성.
  • 파일 모드 / 개체명 / 해시값 / 파일명 과 같이 기록한다.

앞서 말했던 "Hello World!!" 로 만들어진 블롭을 기준으로 생각해보자.

Tree에는 해당 블롭 객체에 대한 정보가 다음과 같이 저장될 것이다.

100644 blob 096c0a72c31f9a2d65126d8e8a401a2ab2f2e21d0a282a6ffe6642bbef65ffd9 test.txt

어떤 파일인지 (ex: 일반파일은 100644) / 객체명(ex: blob) / 해시값 / 파일명 형식이다.

그럼 여기서 파일이 여러개 더 생기면 어떻게 될까?

당연하게도 트리에 어떤 파일인지 / 객체명(ex: blob) / 해시값 / 파일명 형식의 문자열이 몇줄 더 생길 것이다.

Commit 객체

  • 스냅샷 형태로 데이터가 저장.
  • 스냅샷을 누가, 언제, 왜 저장했는지 저장.
  • 현재 Tree 객체 하나(해시값)와 User의 정보가 저장됨.

전체 흐름 예시

  1. 파일 test.txt를 수정.
  2. git add test.txt를 실행.
    • 새로운 블롭 객체가 생성.
    • 새로운 블롭 객체를 가리키는 트리 객체가 생성.
  3. git commit -m "대충 커밋 메시지"를 실행.
    • 새로운 커밋 객체가 생성.
    • 이 커밋 객체는 부모 커밋을 가리키고, 새로 생성된 트리 객체를 가리킴. (ex : [이전트리 해시값, 현재트리 해시값])

💡 git branch 동작

그럼 이제 위의 동작을 바탕으로 git branch는 어떻게 될지 상상이 되는가?
나는 상상이 잘 안간다.

그 이유는 우리가 모르는 부분이 있기 때문이다.
깃이 생성되면 앞서 우리가 말한 깃 객체가 저장되는 objects 폴더도 생기고 다른 파일도 많이 생기지만, 주요 기능을 담당하는 2가지가 더 있다.

  • objects/ : 블롭, 트리, 커밋, 태그 객체가 저장된다.
  • refs/ : 브랜치와 태그 등의 참조가 저장된다.
  • HEAD : 현재 체크아웃된 브랜치를 가리키는 포인터.

우리가 궁금한 부분이 refs에 간단하게 적혀있다.
이정도로는 쉽게 이해가 되지 않으니 동작의 흐름과 각 파일의 역할을 살펴보자.

1. HEAD 파일

HEAD 파일은 현재 체크아웃된 브랜치를 가리키는데 아래 예시를 보면 쉽게 이해된다.

예시

  • main 브랜치가 체크아웃된 상태: ref: refs/heads/main
  • new-branch 브랜치가 체크아웃된 상태: ref: refs/heads/new-branch
  • 디태치드 HEAD 상태: 특정 커밋 해시값, 예를 들어 a1b2c3d4e5f6...

2. refs/heads/ 디렉토리

위에서 HEAD 파일에 저렇게 저장된다고 하는데 그럼 이 위치에는 무엇이 저장되어 있을까?

이 부분의 각 파일에는 각각의 브랜치가 가리키는 최신 커밋 객체의 해시값이 저장되어 있다.

예시

  • .git/refs/heads/main 파일의 내용: a1b2c3d4e5f6... (main 브랜치의 최신 커밋 해시값)
  • .git/refs/heads/new-branch 파일의 내용: f7g8h9i0j1k2... (new-branch 브랜치의 최신 커밋 해시값)

브랜치 생성 및 전환 과정

  1. 브랜치 생성 (git branch new-branch):

    • 현재 브랜치가 가리키는 커밋 해시값을 복사하여 .git/refs/heads/new-branch 파일을 생성.
    • 이 파일에는 현재 브랜치의 최신 커밋 해시값이 저장됩니다.
  2. 브랜치 전환 (git checkout new-branch):

    • .git/HEAD 파일이 ref: refs/heads/new-branch로 업데이트된다.
    • 작업 디렉토리는 new-branch 브랜치의 최신 커밋 상태로 변경된다.

브랜치에서의 커밋

이 부분은 이제 우리가 앞서 말한 동작과 동일하다.

add를 하면 블롭 객체가 저장되고 objects 디렉토리에 저장된다.

commit을 하면 트리 객체와 커밋 객체가 objects 디렉토리에 저장된다.
여기서 한가지 다른점은 HEAD가 가리키는 위치의 최신 커밋 해시값이 저장되는데,
HEAD가 refs/heads/main을 가리키면 해당 위치의 main 파일에 최신 해시값이 저장되고
HEAD가 refs/heads/new-branch를 가리키면 new-branch 파일에 최신 해시값이 저장되는 점이다.

깃 생성시 간략한 파일 구조

.git/
├── HEAD (현재 체크아웃된 브랜치나 커밋을 가리킴: ref: refs/heads/<브랜치 이름> 또는 커밋 해시값)
├── refs/
│   └── heads/
│       ├── main (main 브랜치의 최신 커밋 해시값)
│       └── new-branch (new-branch 브랜치의 최신 커밋 해시값)
├── objects/
│   ├── (블롭, 트리, 커밋 객체들)
...

💡 Crypto 모듈

crypto 모듈은 암호화 기능을 제공하며 해시 생성, 암호화, 복호화 작업을 진행할 수 있게 해주는 Node.js에서 기본적으로 제공하는 모듈이다.

주요 기능

  1. 해시 생성: 다양한 해시 알고리즘을 사용하여 데이터를 해싱할 수 있습니다.
  2. 암호화 및 복호화: 대칭 및 비대칭 암호화를 수행할 수 있습니다.
  3. HMAC 생성: 해시 기반 메시지 인증 코드(HMAC)를 생성할 수 있습니다.
  4. 디지털 서명: 데이터를 서명하고 서명을 검증할 수 있습니다.

사용 방법

해시 생성

const crypto = require('crypto');

// 데이터 해시
const hash = crypto.createHash('sha256');
hash.update('Hello, world!');
console.log(hash.digest('hex'));

💡 zlib 모듈

Node.js에서 데이터 압축과 압축 해제를 지원하는 기본 모듈로 공간을 절약하거나 네트워크 전송 시 데이터 전송량을 줄일 수 있다.

일반적으로 gzipdeflate 알고리즘을 사용.

주요 메서드

  • 압축

    • zlib.gzip(): Gzip 형식으로 압축.
    • zlib.deflate(): Deflate 형식으로 압축.
  • 압축 해제

    • zlib.gunzip(): Gzip 형식으로 압축 해제.
    • zlib.inflate(): Deflate 형식으로 압축 해제.

파일 압축

const fs = require('fs');
const zlib = require('zlib');

// 압축할 파일 경로와 압축된 파일을 저장할 경로
const inputFilePath = 'input.txt';
const outputFilePath = 'input.txt.gz';

// 읽기 스트림과 쓰기 스트림 생성
const input = fs.createReadStream(inputFilePath);
const output = fs.createWriteStream(outputFilePath);

// Gzip 압축 스트림 생성
const gzip = zlib.createGzip();

// 읽기 스트림을 Gzip 압축 스트림을 거쳐 쓰기 스트림으로 전달
input.pipe(gzip).pipe(output);

console.log('File compression complete.');

파일 압축 해제

const fs = require('fs');
const zlib = require('zlib');

// 압축 해제할 파일 경로와 복원된 파일을 저장할 경로
const inputFilePath = 'input.txt.gz';
const outputFilePath = 'input.txt';

// 읽기 스트림과 쓰기 스트림 생성
const input = fs.createReadStream(inputFilePath);
const output = fs.createWriteStream(outputFilePath);

// Gzip 압축 해제 스트림 생성
const gunzip = zlib.createGunzip();

// 읽기 스트림을 Gzip 압축 해제 스트림을 거쳐 쓰기 스트림으로 전달
input.pipe(gunzip).pipe(output);

console.log('File decompression complete.');

참고

깃 동작
https://conceptbug.tistory.com/entry/Git-버전-관리-시스템Version-Control-System의-역사

https://nulab.com/ko/learn/software-development/git-tutorial/git-basics/what-is-git/git-components/

https://inpa.tistory.com/entry/GIT-⚡%EF%B8%8F-개념-원리-쉽게이해#

깃 파일 상태 & 동작

https://dev-coco.tistory.com/48

깃 객체

https://sjevie.tistory.com/entry/Git-개체

zlib

https://blog.naver.com/ndb796/221047657914

JS Blob 객체

https://www.heropy.dev/p/QlwiuS

Node crypto

https://inpa.tistory.com/entry/NODE-📚-crypto-모듈-암호화#

https://minu0807.tistory.com/84

profile
완벽을 찾는 프론트엔드 개발자

0개의 댓글