Now Loading ...
-
nginx의 개요
개요
프론트 엔드 뷰어와, 백엔드 서버를 결합하는 작업을 수행하면서 CORS 오류로 인한 통신후 Body를 못보는 문제, 분명히 통신과 쿠키는 생성되었는데 쿠키를 읽어드리지 못하는 문제 등, 통신 자체는 성공했는데 웹의 자체적인 보안 및 시스템으로 인해 버그가 자주 발생하였다. 웹에 대한 지식이 없이 이런 버그를 고치는 것은 시행착오가 많을 것 같아, cs-note 섹션에 해당 정보들을 정리하려 한다.
웹에 대하여
초창기 웹은 단순히 URI(Uniform Resource Identifier) 을 통해 클라이언트에 리소스를 보내주고, HTML로 규정된 문서 규칙을 통해 문서끼리, 다른 문서를 쉽게 링크를 통해 가져올 수 있는 구조였다. 하지만 웹서버가 발전하며, 웹 서버는 기존의 서버에서, 클라이언트로 HTML 문서를 보내주는 것을 넘어서, 동적으로 움직이고 디자인이 가능한 문서의 송수신, 자원의 송수신을 넘어선 로직의 실행, 클라이언트와 서버 간의 상태의 저장 등 더욱 다양한 역할을 수행해주게 발전되었다.
해당 문서는 이러한 웹에 발전에 따라, 웹에서 구동되는 제품이 구현되기 위한 백엔드의 구성 요소와 도움이 되는 방법론 등을 정리하는 문서이다.
어떻게 통신할 것인가?
TODO Resource의 송수신
초창기 웹의 주요 역할은 서버에 저장된 리소스(HTML 문서, 이미지·동영상·오디오 같은 미디어 파일, 데이터 파일 등)를 URI를 통해 탐색하고, 이를 클라이언트로 전달하는 것이었다. 이후 웹은 단순한 파일 전송과 링크 연결을 넘어, HTML로 문서를 표현하고, CSS로 시각적 디자인을 더하며, JavaScript로 동적 기능을 구현하는 방향으로 발전하였다. 최근에는 단순한 정적 파일 전송을 넘어, XML·JSON과 같은 데이터 포맷을 송수신하여 브라우저가 직접 HTML을 생성하거나 동적 데이터 처리를 수행한다. 이러한 내용을 정리해보자.
정적 리소스
HTML (문서 구조)
하이퍼링크(URI 기반 파일 연결)
이미지·미디어 파일 전송
문서의 표현력 강화 & 동적 요소
CSS (스타일·디자인)
JavaScript (동적 상호작용)
현대 웹 (데이터 송수신 중심)
XML, JSON (데이터 교환 포맷)
AJAX (비동기 데이터 요청)
TODO 표준화된 데이터 송수신 방식
웹이 단순한 문서 전송을 넘어 다양한 데이터 교환을 필요로 하게 되면서, 서버와 클라이언트 간의 데이터 송수신을 표준화하는 프로토콜이 등장하였다. 이러한 프로토콜은 웹 서비스가 확장될수록 일관성 있는 데이터 접근과 통신 효율성을 보장하는 핵심 역할을 한다.
다룰 내용 예시 : RestAPI, GraphQL, gRPC
클라이언트와 서버의 상태관리
웹이 발전하면서 로그인, 장바구니 같은 기능을 제공하기 위해 서버와 클라이언트는 서로의 상태를 유지할 필요가 생겼다. 이를 위해 상태 관리와 인증 방식이 사용되며, 만약 인증 정보가 유출되면 다른 사용자가 이를 도용해 사칭할 수 있다. 따라서 안전한 인증과 보안 기능이 필수적이다.
인증(Authentication) 대표 기술
세션(Session) + 쿠키(Cookie)
토큰 기반 인증(JWT, OAuth2)
다중 인증(MFA, OTP)
보안(Security) 대표 기술
HTTPS/TLS(데이터 암호화 전송)
CSRF/XSS 방어 기법
세션 하이재킹 방지(만료시간, HttpOnly, Secure 옵션 등)
어떻게 배포환경을 파악할 것인가?
어떻게 WAS를 관리할 것인가?
데이터베이스 최적화
##
참고자료
용어설명
URI
URI(Uniform Resource Identifier)란 인터넷에 있는 자원을 어디에 있는지 자원 자체를 식별하는 방법이다. 우리가 어떠한 자원을 식별할 때는 그 자원이 어디에 있는가? 혹은 그 자원을 뭐라고 하는가? 2가지 방법을 통해 식별을 할 수 있다. 이들이 각각 URL(Uniform Resource Locator)와 URN(Uniform Resource Name)이다.
예시 URI : https://example.com:8080/articles/index.html?search=chatgpt#intro
Type
Context
Schema
https://
Host
example.com
Port
8080
Path
/articles/index.html
Query
?search=chatgpt
Fragment
#intro
우리는 Host + Port + Path를 통해 어떠한 자원이 어느 서버의 어느 위치에 있는지를 알아낼 수 있으며, 이런게 URL이다. 이런 자원이 만약 어디에서 접근하든 고유한 이름으로 구분 가능하면 URN이다. URI는 이 모든 개념을 포함하며, Fragment처럼 자원의 위치만이 아닌 해당 자원 내부를 가르키는 특정 지점에 대한 정보까지도 URI는 포함할 수 있다.
참고링크
웹 개발자가 봐야할 하나의 지도 강의
-
Git의 object와 refs 저장방식
Git의 저장방식
git으로 프로젝트를 진행하다보면, .git이라는 숨김폴더가 생성되는 것을 볼 수 있다. 이러한 .git 폴더 안에는 프로젝트 작업을 수행하면서 commit add 등 명령어를 통해 수행한 작업들의 결과들이 생성되는데 이번 포스트에서 해당 정보에 대한 저장방식, 그 중에서도 git의 objects와 refs에 저장되는 정보에 대해 알아보자.
Git objects
위의 그림에서 git이 실제로 어떻게 저장되느냐에 대한 설명이 잘 나와있다.
우리가 working directory의 작업을 commit을 수행하면,
해당 파일들과 디렉토리들은 Blob과 Tree라는 구조로 .git/objects에 저장된다.
commit 객체가 생성되어 해당하는 커밋에 프로젝트 폴더를 가르키는 Tree 객체를 가르킨다. 또한 해당 커밋 이전의 부모 커밋 또한 가르킨다.
commit object를 Head 포인터가 가르킨다.
자 전체적인 구조는 위와 같이 수행되지만, 하나하나가 잘 이해되지 않는다. 그러니 자세히 파악해보자.
git objects 파일을 자세히 볼 땐
git cat-file -p 파일의 hash코드
명령을 통해 해당 오브젝트 파일을 자세히 살펴볼 수 있다.
이 글을 포스트하는 github 블로그 역시도 git으로 관리되고 있다. 그러면 한번 예시를 살펴봐볼까?
abc83@develop MINGW64 ~/development/SeongWooJo.github.io/.git/objects (GIT_DIR!)
$ ls
0a/ 1b/ 34/ 4c/ 67/ 7e/ 8f/ a2/ b5/ c1/ ca/ e8/ fb/
0f/ 24/ 36/ 50/ 68/ 80/ 92/ a9/ b8/ c2/ d2/ ea/ fc/
13/ 25/ 38/ 51/ 76/ 85/ 9a/ ae/ ba/ c4/ d3/ ee/ fd/
19/ 2f/ 3e/ 60/ 7a/ 86/ 9e/ b0/ bc/ c5/ d5/ f3/ info/
1a/ 30/ 44/ 62/ 7d/ 8b/ 9f/ b2/ bd/ c7/ db/ f9/ pack/
abc83@develop MINGW64 ~/development/SeongWooJo.github.io/.git/objects (GIT_DIR!)
$ ls 1b/
2948a17f027fd4f4359c53a60b9582a3b1c265
abc83@develop MINGW64 ~/development/SeongWooJo.github.io/.git/objects (GIT_DIR!)
$ git cat-file -p 1b2948a17f027fd4f4359c53a60b9582a3b1c265
040000 tree 7a6a6a64b2bbae6b6cec73624b610e31830b56ac Projects
040000 tree 51fb9a02110fa88741738be230342544256e1f73 Tutorial
040000 tree 7a5657ae0999f622f6509b8416f659a0262eba33 cs-note
040000 tree c472bd9693f8ca55e7590d9ace65ee51b6f99179 dev-log
100644 blob a49ba48448f906d814cc83e50fc18f81cae53844 index.md
040000 tree b56fcfa45f3a0afaf2c480470f2b38f1b44fc26d tech-review
abc83@develop MINGW64 ~/development/SeongWooJo.github.io/.git/objects (GIT_DIR!)
$ git cat-file -p a49ba48448f906d814cc83e50fc18f81cae53844
---
---
자 이러한 결과가 나왔다. 그러면 이 결과를 한번 자세히 분석해보자!
Git Blob
먼저 git이 파일 버전 관리를 할 때 핵심이 되는 저장방식인 Blob(Binary Large Object)에 대해서 알아보자.
abc83@develop MINGW64 ~/development/SeongWooJo.github.io/.git/objects (GIT_DIR!)
$ git cat-file -p a49ba48448f906d814cc83e50fc18f81cae53844
---
---
자 Blob파일을 우리가 열어보았을 때 해당 파일인 index.md의 실제 저장된 값과 정확히 일치하는 결과를 확인할 수 있다.
그렇다면 파일이 수정되었을 때 Blob은 어떻게 저장할까?
# Blob 1
첫 번째 파일
# Blob 2
첫 번째 파일
두 번째 파일
파일이 위와 같이 수정되었을 때 Blob은 각 파일의 전체 내용을 기반으로 Hash함수를 통과시켜 40글자에 해당하는 문자열을 파일이름으로 사용한다. 이때 앞선 2글자는 폴더로, 뒤의 38글자는 파일이름으로 사용된다.
처음 objects의 폴더에 나온 수많은 2글자들은 이런 식으로 생성된 hash의 결과값들이다. git에서 각 오브젝트들은 이러한 hash값을 기반으로 접근할 수 있다.
각 파일이 조금의 수정이라도 일어난다면 git은 새로운 Blob파일로 저장하며, 수정이 일어나지 않았을 시 동일한 Blob파일로 저장된다.
이러한 구조의 장점은 무엇일까?
바로 hash함수의 특징인 같은 값을 통과시킬 땐 같은 결과가 나온다는 것이 핵심이다.
git은 버전관리 프로그램이다. 커밋을 수행할 때마다 파일의 버전을 기록해야하고 변화를 추적할 수 있어야한다. 하지만 우리가 git을 사용할 때 항상 모든 파일들이 커밋을 수행할 때마다 바뀌는가?
아니다. 대부분의 파일들은 이전버전과 변하지 않는 경우가 많으며 수십 번의 커밋 후에도 바뀌지 않을 수도 있다. 이때 Blob의 저장방식이 강점을 발휘한다. Blob은 파일 내용을 기반으로 hash를 생성해 파일이름을 생성한다. 즉 어떤 컴퓨터에서든 어떤 파일로 저장되었든 어느 시점에 저장하든, 파일 내용이 동일하다면 동일한 Blob으로 저장된다.
이러한 방식은 git이 버전관리를 수행하면서도 저장 공간을 효율적으로 사용하게 해준다. 각 커밋을 수행할 때 시점별로 commit 오브젝트는 tree오브젝트를 가르키고 각 tree 오브젝트는 Blob을 가르키는데, 이때 동일한 내용은 여러 커밋 시점에서 하나의 Blob만을 가르키게 저장할 수 있다.
여기서 또 하나의 용량을 감소하는 트릭이 존재한다.
git 저장구조, wikipedia
Blob 파일의 생성 원리를 보면 파일 전체를 스냅샷처럼 저장해 전체 파일 내용을 기반으로 hash를 생성한다. 하지만 이런 말을 들어보았을 것이다. git은 파일의 수정된 내역만 저장하여 효율적이게 디스크 공간을 활용한다.
실제로 git은 델타압축이라는 파일의 수정된 내역만을 저장하여 공간을 절약시켜, 각각의 Blob을 이전 버전에서의 수정 내역만을 기반으로 생성시키고 checkout 등으로 특정 버전을 불러와야할 때 이러한 수정 내역을 일괄적으로 읽어 해당 버전을 복구한다. 그렇기에 전체 내용을 저장하는 것도 수정된 내역만 저장하는 것도 맞는 말이다.
Git Tree
abc83@develop MINGW64 ~/development/SeongWooJo.github.io/.git/objects (GIT_DIR!)
$ ls 1b/
2948a17f027fd4f4359c53a60b9582a3b1c265
abc83@develop MINGW64 ~/development/SeongWooJo.github.io/.git/objects (GIT_DIR!)
$ git cat-file -p 1b2948a17f027fd4f4359c53a60b9582a3b1c265
040000 tree 7a6a6a64b2bbae6b6cec73624b610e31830b56ac Projects
040000 tree 51fb9a02110fa88741738be230342544256e1f73 Tutorial
040000 tree 7a5657ae0999f622f6509b8416f659a0262eba33 cs-note
040000 tree c472bd9693f8ca55e7590d9ace65ee51b6f99179 dev-log
100644 blob a49ba48448f906d814cc83e50fc18f81cae53844 index.md
040000 tree b56fcfa45f3a0afaf2c480470f2b38f1b44fc26d tech-review
이번엔 Tree 오브젝트를 살펴보자, 위의 그림을 보듯이 tree object는 자신이 가지고 있는 Tree와 Blob을 가르키는 오브젝트이다.
트리는 각 ‘디렉토리’별로 ‘파일 이름’을 저장한다.
현재 블로그에서 디렉토리를 담당하는 cs-note, dev-log 등은 tree로 저장되고ㅡ, index.md같은 실제 파일은 Blob으로 저장된 모습을 볼 수 있다.
또한 이러한 Tree 역시도 Blob과 마찬가지고 hash코드로 파일명이 지정된 것을 볼 수 있다.
Blob과 달리 Tree는 디렉토리 전체를 기반으로 hash값을 생성하기에, 포함된 일부 파일이 하나만 수정되더라도 Tree 역시도 새로운 Tree 객체로 생성된다.
하지만 이를 통해 git은 파일의 내용만 저장하는 Blob과 달리 파일의 이름, 실행권한, 디렉토리 구조 등을 Tree 객체를 통해 저장할 수 있다.
여기서 .git/index 파일을 한번 살펴보자.
$ git ls-files --stage | tail
100644 d344d060ac0c5db0f9bb01c4f1ce7e0d156598b9 0 search.html
100644 f259c5a08dd5d121a34a000017cd197ea02dc90b 0 sitemap.xml
100755 764df0355bdab53e2362b2f821e6c649162694d5 0 start.sh
100644 c9712bd9af8e82846391e82f7c50077b095f87fc 0 tag.html
100755 bdfb10641d93f265a382b3014341a15c68e4b139 0 tool/find-orphan-post-img.sh
100755 537c62c2bb5465d7594f085f8cf4935cf07ac4c4 0 tool/fix-image-references.sh
100755 01433e92888c8ce58bb79792ef786aa58d1acfc9 0 tool/pre-commit
100755 95b19d9863b6ad564bf6208f719a2bcc657a9ffc 0 tool/save-images.sh
100755 e36c4a696d2e351dc0efcd40db81d87e7ef1fb11 0 tool/to-skeleton.sh
100644 50fe65a76cb17611bb041bd5d2cc517ec863323f 0 utterances.json
git index 자료 출처
해당 파일의 컬럼은 각각 staging area로 옮겨진 파일들에 대한 나열을 수행하며, 각 staged 파일들에 대해
[mode] : 파일의 타입과 권한을 의미
[object] : 해당 파일을 나타내는 .git 내부 hash값
[stage] : 기본값 0 충돌이 났을 때 충돌난 각 파일 그룹들을 구분해주는 키
[file] : 실제 파일 경로
를 의미한다.
tree는 확실하게 commit된 디렉토리(Tree)와 Blob들을 기록하지만, Staging 공간은 오로지 add된 파일들을 Blob으로 생성하고 이들을 나열하는 차이를 확인할 수 있다.
하지만 만약 현재 staing 공간에 존재하는 파일들을 tree로 만들고 싶다면, git write-tree 명령을 통해 Tree객체를 생성해주고, 이에 대한 hash 값을 커맨드에 출력해준다.
Git Commit
프로젝트의 디렉토리에 대한 정보와 파일 내용에 대한 정보를 Tree와 Blob을 통해 저장하였다.
하지만 이는 한 시점에 프로젝트의 상태를 기록하는 방법론일 뿐이다.
git은 우리가 commit을 수행할 때마다 해당 시점에 누가 기록했는지, 이 이전 시점의 기록은 무엇인지 추적이 가능해야한다. 이러한 역할을 수행해주는 것이 commit 객체이다.
abc83@develop MINGW64 ~/development/SeongWooJo.github.io/.git/objects (GIT_DIR!)
$ git log
commit f342a499d9ea17b2956f9bea91c33354d1870984 (HEAD -> main, origin/main, origin/HEAD)
Author: SeongWooJo <abc8325767@gmail.com>
Date: Wed Aug 13 22:35:28 2025 +0900
search
commit 1a733fefb50c137ab2b95285b82f084dc60193aa
Author: SeongWooJo <abc8325767@gmail.com>
Date: Wed Aug 13 22:29:42 2025 +0900
Update _config.yml
commit 80646a438cff8f50884f6bf2945b2f4e15887ff4
Author: SeongWooJo <abc8325767@gmail.com>
Date: Wed Aug 13 22:23:09 2025 +0900
.
commit 19781c03fd83f4c185f9ab5051c8bba72983bace
Author: SeongWooJo <abc8325767@gmail.com>
Date: Wed Aug 13 22:22:41 2025 +0900
우리가 git log 명령을 수행하면 위와 같이 hash값과 함께 각 커밋에 대한 정보를 나열해주는 것을 볼 수 있다. 어떻게 이런 작업이 가능한 것일까?
아까처럼 hash 코드를 기반으로 파일을 열어보자.
abc83@develop MINGW64 ~/development/SeongWooJo.github.io/.git/objects (GIT_DIR!)
$ git cat-file -p 19781c03fd83f4c185f9ab5051c8bba72983bace
tree ba3c9fe46ea8e11d47e739b69c347cf1d5efd75e
parent dba0935cb5910000496ffac60c49ba2534de4001
author SeongWooJo <abc8325767@gmail.com> 1755091361 +0900
committer SeongWooJo <abc8325767@gmail.com> 1755091361 +0900
robot
해당 커밋은 git blog를 배포하기 위해 robot.txt를 시험하던 시점의 커밋이다. commit 메세지로 robot으로 간단하게 적었다.
이 객체를 분석해보자.
tree : 해당 커밋 시점의 프로젝트 전체를 가르키는 tree 객체의 hash값이다.
parent : 해당 커밋의 이전 커밋 객체를 가르키는 hash값이다.
author : 해당 커밋 시점의 코드를 작성한 사람에 대한 정보이다.
committer : 해당 커밋을 작성한 사람에 대한 정보이다.
“robot” 해당 커밋을 작성할 때 메세지이다.
이처럼 버전관리를 위해 필요한 추적을 위한 정보들이 커밋 객체에 담긴 것을 확인할 수 있으며, 커밋 객체역시도 tree,blob과 마찬가지로 내용을 기반으로 hash값을 폴더/파일명으로 삼는다.
Git Tag
자 hash를 기반으로 Blob, Tree, Commit의 접근하는 것은 저장도 효율적이고 버전 관리도 될 수 있는 방법이지만, 40글자에 해당하는 hash 코드는 사람이 구분하기에 어렵다.
이를 해결해주기 위한 객체가 바로 Tag 객체이다.
git tag [옵션] <tagname> [<commit>]
git tag -a v1.0 -m "First release"
git tag -s v1.0 -m "Signed release"
git tag v1.1 <commit_hash>
우리는 위와 같은 명령을 통해 각 hash 코드에 사람이 접근하기 좋은 이름을 붙여줄 수 있다.
이를 기반으로 기존에는 git checkout hash코드 처럼 40글자의 hash코드를 사용해야하는 명령에서, git checkout 태그명으로 미리 지정한 tagname을 기반으로 hash코드를 대체할 수 있다.
다만 위의 예시처럼 우리가 어떻게 태그를 생성했느냐에 따라 구현방식이 조금씩 다르다.
-a 옵션
$ git cat-file -p c3d5f2a
object 7a9b74c6b6f4d4c85b8e4cf59ef1fa3e63c5c3ad
type commit
tag v1.0
tagger Alice <alice@example.com> 1713250000 +0900
First release
-a 옵션을 사용했을 때는 해당 hash 파일에 대한 태그를 생성할 때 누가 태그를 붙였는지, 해당 태그를 붙일 떄 시점 및 메세지를 같이 남긴다.
-s 옵션
object 7a9b74c6b6f4d4c85b8e4cf59ef1fa3e63c5c3ad
type commit
tag v1.0
tagger Alice <alice@example.com> 1713250000 +0900
Signed release
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
iQEzBAABCAAdFiEE...
-----END PGP SIGNATURE-----
-s 옵션은 -a 옵션에 더해 해당 tagger를 검증할 수 있는 키를 남겨, public key를 통해 검증할 수 있게 한다.
그냥 만들시
이때는 tag 객체가 생성되는 것이 아닌, refs/tags에 해당 태그가 가르키는 hash코드에 대한 정보만이 한 줄로 기록된다.
git refs
.git/refs 폴더에는 이러한 객체를 가르키는 포인터를 만들 수 있으며 이곳에 저장되는 포인터 정보는
.git/refs/heads
각 브랜치별 최신 작업 커밋을 가르키는 hash값 및 working directory가 작업하고 있는 버전의 commit hash값
.git/refs/tags
사전에 태그로 등록한 commit, tree, blob hash값이 저장되는 장소
.git/refs/remotes
local 저장소가 아닌 remote 저장소에 브랜치들에 대한 최신 commit hash값이 저장되는 장소
와 같이 앞서 공부한 git의 객체들에 대한 hash값을 refs 폴더에서 실제 git에서 작업되는 hash값을 관리해줌으로써 우리가 브랜치명, 원격 브랜치명, 태그명으로 실제 hash값을 사용하지 않고 쉽게 이동할 수 있다.
참고자료
git의 저장방식 영상
git blob, tree, commit
git tags
git에 대한 추후 볼 내용1
-
Git 정리
Git
개요
백엔드 시스템을 개발하면서, 기존의 연구 개발과는 달리 여러 사람이 병렬로 작업을 수행하게 되었다. 이에 따라 Git을 사용하게 되었고, 버전 및 브랜치 관리를 철저히 해야 할 필요성을 절실히 느꼈다. 이에 따라 Git에 대해 정리할 필요성을 느꼈고, 그 첫 번째로 Git의 공간과 파일의 상태에 대해 기초적인 내용을 정리한다.
Git이란?
Git이란 Version Control System의 일종으로, 소프트웨어 개발 및 협업 프로젝트에서 소스 코드, 문서, 기타 파일의 변경 사항을 추적하고 관리하는 데 사용된다.
혼자 작업하든 팀으로 작업하든, 버전 관리를 도입하면 다음과 같은 장점이 있다:
파일과 프로젝트를 이전 상태로 쉽게 되돌릴 수 있다.
누가 언제 어떤 작업을 했는지 추적할 수 있으며, 문제 발생 시 관련 이력을 확인할 수 있다.
파일을 잃어버리거나 실수로 수정했을 때 쉽게 복구할 수 있다.
서로의 작업을 덮어쓰지 않고 병렬로 작업하며, 변경 사항을 손쉽게 병합할 수 있다.
버전 관리 시스템(VCS)은 Git 외에도 다양한 도구들이 존재한다. 예를 들어 GUI 기반의 간편함을 선호하는 개발자들은 Mercurial을 사용하기도 하고, 코드 외의 리소스까지 통합 관리하는 Perforce (P4V) 도 있다. 하지만 현재까지 가장 널리 사용되는 VCS는 단연 Git이다.
Git의 공간
Git은 파일들의 변경 이력을 추적하여 버전을 관리하는 도구다.
그렇다면 파일을 수정할 때마다 Git이 모든 변화를 자동으로 기록하는 것일까?
→ 그렇지 않다.
Git은 우리가 작업하는 디렉토리의 파일 상태를 추적하고, 특정 명령을 실행할 때마다 스냅샷처럼 그 시점의 파일 상태를 기록한다(그러나 저장 방식은 파일을 복제하는 것이 아닌 변화를 기록하는 차이가 존재한다). 이러한 과정에서 Git은 변경된 파일들을 다양한 단계에서 관리한다. Git이 추적하는 파일 상태는 아래와 같은 네 가지 주요 공간을 통해 이해할 수 있다:
1. Working Directory
Git으로 관리하기 위해 git init 등을 실행한 후 작업하게 되는 실제 디렉토리다.
이곳은 개발자가 직접 파일을 수정하거나 저장하는 공간이며, Git이 자동으로 버전을 기록하지 않는다.
즉, 파일을 수정하거나 새로 생성해도 git add 또는 git commit 명령을 실행하지 않으면, Git이 버전 이력에는 반영하지 않는다.
2. Staging Area
Staging Area는 로컬 저장소에 기록(commit) 하기 전에 Git이 변경 내용을 임시로 저장하는 공간이다. 해당 공간이 존재함으로써 Merge 등의 작업을 수행할 때 충돌을 해결하거나, 한번에 커밋에 어떠한 정보들만 업데이트할지 천천히 파일들을 추가할 수 있다. 메모리 등에 임시로 저장되는게 아닌 별도의 공간에 존재하기에 이런 작업들을 오래 수행할 수 있다.
git add 명령을 사용하면, 해당 파일은 Staging Area에 추가된다.
Staging Area를 사용하면 원하는 변경 사항만 선택적으로 커밋할 수 있어, 커밋의 목적과 단위를 깔끔하게 분리할 수 있다.
3. Local Repo
git commit 명령을 실행하면, Staging Area에 있던 변경 내용이 로컬 저장소에 커밋된다. 이 저장소는 .git 폴더 내부에 존재하며, 모든 커밋 이력, 브랜치 정보, 메타데이터 등을 포함한다. Git은 이곳에 실제 파일 내용뿐 아니라, 이전 버전과의 차이점, 커밋 메시지, 작성 시간, 작성자 등의 정보를 구조화하여 저장한다.
구체적인 .git 폴더의 저장 방식에 대해서는 링크를 참조하자 : 저장방법 로직
4. Remote Repo
로컬 저장소의 커밋 내역을 다른 사람과 공유하려면, git push 명령을 사용하여 Remote Repository로 전송한다.
Remote Repository는 GitHub, GitLab, Bitbucket 등의 원격 저장소이며, .git 폴더와 동일한 커밋 이력을 저장하고 관리한다.
원격 저장소를 통해 팀원 간의 협업이 가능해지며, pull, fetch, merge 등을 통해 변경 사항을 주고받을 수 있다.
Git의 파일의 상태
Git은 결국 각 파일이 시간에 따라 어떻게 변화해왔는지를 기록하는 도구이다. 이에 따라 각 공간으로 이동하는 것에 더해 Git은 사용자가 명시적으로 실행하는 명령에 따라 각 파일의 상태(state)를 구분하고 관리한다.
Git에서 파일이 가질 수 있는 상태는 다음과 같다:
Untracked / Tracked → (Unmodified, Modified, Staged)
1. Untracked
Git은 파일의 변경 이력을 추적하고 버전을 관리하지만, 한 번도 Git에 추가되지 않은 파일은 Git 입장에서 “변경”이 아닌 “새로운 파일” 일 뿐이다.
즉, Git이 한 번도 기록한 적이 없는 파일은 과거 상태가 없기 때문에 변경 이력을 추적할 수 없다. 이러한 상태를 Untracked 이다.
실제 Git에선 git 프로젝트 내에서 새로운 파일을 생성시켰을 때, 기존의 추적되던 파일을 삭제하였을 때,
또한, .gitignore에 등록된 파일들도 일부러 추적하지 않기 때문에 Untracked 상태로 간주된다.
이는 예를 들어 다음과 같은 경우 유용하다:
대용량 파일로 인해 Git 저장소에 포함시키고 싶지 않은 경우
민감 정보(예: API 키, 비밀번호)가 포함된 파일을 외부 저장소에 업로드하고 싶지 않은 경우
위의 상태 도식과 달리 Tracked 상태의 파일을 삭제하지 않으면서 Untracked로 만들고 싶을 수 있다. 그런 경우 위처럼 git add, unstaged 같은 명령으론 수행할 수 없고 git rm --cached example.txt 라는 명령처럼 실수로 추적한 파일을 local repo와 staging area에서 없앨 수 있다.
2. Staged
위의 공간 설명에서 Staging Area란 공간은 commit을 수행하기 전 기록할 파일의 상태를 임시로 모아두는 공간이다. 이처럼 해당 공간에 파일들이 옮겨졌을 때 해당 파일들은 Staged 상태를 가지게 된다. 만약 Untracked 파일이 Staged 상태가 된다면 그 때부터 추적이 시작되는 것이고, 다시 unstaged하면 Untracked 상태로 돌아간다.
만약 당신이 파일을 Staged 상태로 바꾸고 워크 디렉토리에서 파일을 수정한다면 어떻게 될까?
Staging Area에는 git add 시점의 파일 상태가 기록되는 것이다. 즉, 워킹 디렉토리의 파일과 Staged에 기록된 파일이 다른 것이다.
워킹 디렉토리에서 해당 파일을 수정하면, Git은 "Staging Area 버전" ≠ "Working Directory 버전" 인 것을 인식한다.
3. Unmodified
Commit을 수행하면, Staging Area의 파일 상태가 Local Repository에 기록된다.
이후 git status 같은 명령이 실행될 때마다 Git은 Local Repo(HEAD) 와 워킹 디렉토리를 비교한다.
두 상태가 완전히 동일하다면 해당 파일은 Unmodified 상태이다.
예를 들어, 파일을 Staged 상태로 변경하고, 추가 수정 없이 commit을 하면
commit 직후 그 파일은 Unmodified 상태로 남는다.
4. Modified
위의 상태처럼 Commit 등을 통해 Staged를 Local Repo로 옮긴 후 추가적으로 워킹 디렉토리에서 파일을 수정했을 때, 해당 파일은 Local Repo와 상태가 다른 Modified 상태가 된다.
Touch background to close