2025. 1. 30. 02:52ㆍdevOps

Git은 원격저장소인 github 으로 내가 한 작업내역을 보내는 수단 아니에요?
맞다. 내가 한 작업내역을 원격저장소에 내보낸다. 깃헙은 단순 내가 잔디 심는 것을 자랑하기 위함인가? 사실 지금도 그렇게 느끼고 있긴하다. 주기적으로 코드 작업을 하고 눈에 띄게 보여줄 수 있는 부분이긴 하다.
근본적으로 Git 을 왜 쓰는지에 대한 돌아봄이 필요했다. 작년 2학기동안 유닉스 시스템을 배우면서, 리눅스 셸 스크립트 명령어 뿐만 아니라 Git 명령어와 버전관리에 대해서도 진지하게 생각해볼 수 있던 것 같다. (사실 다시 교재를 읽으면서 느꼈다..🤣)
버전관리를 왜 하나요? 라고 나에게 반문해보자. 인생의 실수는 되돌릴 수 없고, 흘러간 추억들은 날조되거나 다르게 기억할 수 있다. 그치만 깃(Git)에서는 내가 되돌리고 싶은 부분으로 돌아가거나 취소할 수 있는 타임머신도 가능하고, 어떤 실수들을 했는지 돌아볼 수 있다. 버전 관리는 협업 시 혹은 회사에서 작업한 내역을 중앙서버에 저장한다. 또는 새로 온 신입이나 이직한 동료가 새 컴퓨터에 작업물을 받아야한다면 중앙서버에서 복사본을 받기에도 편할 것이다.
버전 관리하는 시스템의 타입도 두가지로 나뉜다. 중앙집중형 버전관리(CVCS: Centralized Version Control System)과 분산형 버전관리 시스템(DVCS: Distributed Version Control System) 이 있다. 중앙 집중형 버전 관리는 중앙 서버에 작업내역을 저장하거나 전달하려면 무조건 네트워크 연결이 되어야 하고, 중앙 서버 자체가 문제시에는 데이터가 손실될 수 있다. 모든 명령이 중앙 서버로 연결될 수 있기 때문에 작업속도도 느려질 수 있다. SVN(Subversion), CVS(Concurrent Version System) 이 있다.
반대로 분산형 버전 관리 시스템은 원격저장소와 각 개발자 저장소에 저장되는 지역저장소로 분리되어 있다. 모든 지역 저장소는 모든 기능을 갖춘 저장소로 중앙 원격 저장소와는 독립적으로 동작한다는 점이 중앙집중형 버전관리 시스템과는 다른 점이다. 작업수행시에도 원격저장소에 항상 연결될 필요가 없다. 여러 명 동시 작업을 할 때 병렬적으로 개발이 가능하다. 원격 저장소에 Pull(풀), Push(푸시)를 할 때만 인터넷 연결이 되면 된다. 그 종류엔 Git, 바자(Bazaar), 머큐리얼(Mercurial) 이 있다. 대부분의 개발자나 회사가 Git 을 사용할 것이다. 장점이 중앙집중형 버전관리에 비해 더 많고 작업에 대한 제한도 유동적이기 때문이다.
이번에 알아 보고 싶은 Git 기초 개념은
- Git 설정
- 작업디렉터리, 스테이지 영역, 깃 저장소에 대한 구별과 흐름
- 깃 파일 상태의 변화
정도까지 간단하게 짚고 넘어갈 예정이다.
Git 설정
예전에 깃헙의 원격저장소와 내 맥북의 깃을 연동할 때 처음 세팅했던 과정의 첫 시작이 아래와 같았다. 일종의 내 깃 정보인 이름과 이메일을 저렇게 설정하면 깃 로그(Log) 에 남는다. 아래와 같은 설정에서 --global 이라는 옵션을 보면 전역적이라는 의미를 띄고 있다.
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
즉, Git 설정하는 부분의 영역은 시스템 설정, 전역설정, 지역설정 3가지다.
- 시스템설정: 해당 시스템에 있는 모든 사용자와 모든 저장소에 적용되는 설정이다. 리눅스에서 설정 내용이 /etc/gitconfig 위치에 저장된다. git config 명령의 --system 옵션을 붙여야한다.
- 전역설정: 해당 사용자에게만 적용되는 설정으로 --global 옵션이 붙는다. 설정내용은 ~/.gitconfig 에 저장된다.
- 지역설정: 사용자가 현재 작업 중인 현재 지역 저장소에만 적용되는 설정이다. 일반적으로 특정 프로젝트 폴더를 만들고 git init 생성해서 그 프로젝트 폴더의 작업 내역만 커밋(Commit), 푸시(Push), 풀(Pull) 할 수 있게된다.


NOTE
브랜치는 독립적으로 개발되고 있는 순서가 있는 일련의 커밋 목록이다. 현재 작업 중인 브랜치(Branch)를 가리키고 있는 것은 HEAD
깃(Git)은 그냥 내 컴퓨터에서 작업한 내역을 바로 깃헙으로 보내버리는 거 아녀?? 라고 내가 단순히 생각하며 작업을 했었다. - 작업디렉토리, 스테이지 영역, 깃 저장소의 정의
깃의 파일 변경이나 내역을 저장하고 업데이트 하는 과정과 공간이 있다. 이 3군데를 구별해야 할 것이다. 바로 작업 디렉터리, 스테이지 영역, 깃 저장소이다.
- 작업영역(Working Area): 파일을 만들고 변경할 때 사용하는 리눅스 디렉터리로서, 작업트리(Working Tree), 작업 디렉터리, 작업폴더, 프로젝트 폴더라고도 한다.
- 스테이지 영역(Stage Area): 작업영역과 깃 저장소 사이에 존재하는 공간이다. 스테이지, 인덱스 라고도 한다.
선택된 개별파일의 변경 파일을 기록하는 가상의 공간이라고 한다. - 깃 저장소: 버전이 만들어지고 관리되는 가상의 공간이다. 필요할 때 특정 시점에서 커밋을 수행해 스테이지의 스냅샷(Snapshot)을 저장한다. 시간의 흐름에 따라 수행되었던 여러 커밋이 연결되면서 커밋의 이력이 형성되고 관리된다.
깃에서 커밋을 실행하려고 할 때 작업 영역에 있는 변경 내용은 바로 깃 저장소에 저장되는 것이 아니고, 그 전에 변경된 파일을 스테이지 영역에 기록해야한다.

Git 파일 상태 변화 - LifeCycle(주기)
Working Area(작업 영역)에서 untracked(추적되지 않는 상태) 와 tracked(추적된) 로 상태가 나뉜다. 파일을 처음 생성할때는 untracked 상태다. 그러므로 git add 명령으로 Stage 에 먼저 올려야 한다. 추적됨의 상태는 수정 전(unmodified), 수정함(modified), 스테이지에 올라오는 녀석들이 그러하다. 그리고 이러한 파일의 상태를 확인하는 것은 우리가 자주 쓰는 아래 명령어와 같다.
$ git status
참고
한국방송통신대학교 교재 - UNIX 시스템 / 김희천, 김진욱 공 저
(갓진욱 교수님 운영체제 강의 잘 들었는데 기억이 희미해졌다 제대로 완강하지 않아서일까..UNIX 시스템은 김희천 교수님께서 잘 설명해주셨다.)
유닉스 시스템에서 알게된 Git - 작년 2024년 2학기 때 배운 후 회고
이렇게 체계를 다시 잡으니, 터미널 메시지를 잘 파악한 후 대처를 할 수 있게 될 것 같다. 모르면 메시지 긁어서 구글링 하곤 했었는데, Git 공식문서와 교재 등을 공부해 나가는 것도 필요해진 것 같다. Git 명령어는 Git 뿐만 아니라, 리눅스와 셸 스크립트 명령어와 정규식 등을 활용하기에 두루두루 개략적으로 알아두면 좋겠다는 생각이 들었다.
가제 2 . 깃에 미쳐보는 시간
작년 12월 글또의 재호님이 Git 강연에 대해 모집을 하는 공고를 글또 내에서 개최해주셨다. 예전에 iOS 단톡방에서도 어느 분이 토미님의 깃미남 소스트리 무료 전자책을 공유해주기도 했어서, 어렴풋이 들은 적이 있었다. 그래서 관심을 가지고 Git 강연을 신청했다. 작년 2학기에는 유닉스 시스템을 공부했기도 했고, 팀 협업을 했을 때 팀원들이 쓰는 용어인 rebase, revert, squash 등 자주 쓰지 않은 깃 용어들도 많았기에 깃에 미친 남자인 Tommy 님의 깃 강연을 듣고 싶었다.
두근두근,, 강남의 한 공유스페이스에 도착하고 깃미남 토미님을 뵈었을 때 인상이 좋고 친근한 미소로 나를 반겨주셨다. 인사를 나누고, 토미님의 블로그를 보다 익숙한 RxSwift 라는 카테고리를 보았고, iOS 개발을 하셨던 건지 조심스레 여쭸다. 알고 보니 전직 iOS 개발을 하시기도 했고, 내가 예전에 익숙하게 봤던 swift.org 공식문서의 한국어판을 번역해주셨던 분이었다. 지금은 그 링크가 닫혀있긴 한데, 삐구떡님과 이 링크를 통해 초중반에 Swift 공식문서를 보곤 했었다.
Git 의 4가지 개체
응? 깃에 4가지 개체가 있다고? 굳이 생각해보지 않았던 부분이어서 이를 알려주셨을 땐 유레카Eureka 였던 것 같다.
깃(Git)의 핵심은 content-addressable 시스템이다. Key와 value 로 해시구조로 되어 있다. 파일 이름은 Key고 파일 데이터가 일종의 Value(값)인 거다. 어떤 형식의 데이터여도 집어넣을 수 있고, 해당 Key 로 데이터 접근이 가능하다. 파일의 key는 SHA-1 키 형태고 이를 외우기는 쉽지 않다. 이런 종류를 Blob(Binary Large Object) 으로 불린다.
트리(Tree)개체는 디렉터리나 폴더를 가리킨다. 이 개체에 파일을 저장하며 한꺼번에 파일들을 저장할 수도 있다.
Tree 의 개체 구성은 여러 항목을 지녔고 아래와 같다.
- Blob 개체 또는 Tree 개체를 나타내는 SHA-1 포인터
- 파일모드
- 개체 타입
- 파일 이름
아래는 위의 항목의 예이다. git-scm.com 공식문서에 나오는 예제 셸 스크립트다.
$ git cat-file -p master^{tree}
100644 blob a906cb2a4a904a152e80877d4088654daad0c859 README
100644 blob 8f94139338f9404f26296befa88755fc2598c289 Rakefile
040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0 lib
Commit 개체는 특정 시점의 프로젝트 상태에 대한 스냅샷을 저장하는 객체다. 커밋은 Tree와 해당 시점 프로젝트 상태에 대한 메타데이터(작성자, 작성시간, 커밋메시지 등)을 포함한다. 프로젝트의 변경 히스토리는 시간 순으로 연결된다.
Tag의 개체: 특정 커밋에 대한 별칭을 지정할 수 있는 객체다. 커밋의 해시값을 가리키고, 특정 버전의 릴리스를 표시할 수 있다.
예) v1.0 이라는 Tag 를 특정 커밋에 지정하면 해당 커밋은 v1.0 이라는 이름으로 쉽게 참조할 수 있게 되는 것이다.
다시 한번 요약하자면
- Blob 은 파일 내용을 저장
- Tree 는 디렉터리 구조와 파일(Blob)의 관계를 저장
- Commit 은 특정 시점의 프로젝트 상태(Tree) 와 메타데이터를 저장
- Tag 는 특정 커밋에 대한 별칭을 제공한다. 일종의 북마크 같은 느낌이랄까
세련된 가지치기 나(rebase)랑 같이 할래요? Rebase의 세계
리베이스는 말그대로 베이스를 바꾼다. Rebase 는 일렬로 된 단뱡향 그래프라고 한다. 커밋 히스토리를 간결하게 만들고 싶을 때 사용한다. 특정 커밋을 기반으로 한 커밋을 재생성하는 명령이다. 내역이 지워지지는 않지만 깃 입장에서는 완전히 다른 커밋이라고 하셨다.
리베이스는 브랜치의 변경 사항을 다른 브랜치에 재적용하는 방식으로 브랜치를 통한다. 머지와 달리 새로운 커밋을 생성하며, 기존 커밋들을 수정하고 재배치해 브랜치의 이력을 선형으로 만들어주는 녀석이다. 머지(Merge)는 두 브랜치의 최종결과만을 가져와 합친다.
⚠️ 주의사항!!
- 원격저장소에 푸시되지 않은 커밋을 대상으로 수행
- 커밋을 amend 하고 변경해 다시 새로 커밋
- 공유브랜치: 여러 사람이 함께 사용하는 공유 브랜치에는 Rebase를 사용하지 않는 것이 좋다. Rebase 는 커밋이력을 변경하므로 다른 사용자의 작업에 혼란을 줄수 있다고 한다..(Gemini의 답변..)
-> 공유 브랜치에서의 사용은 지양하고 개인 브랜치에서 숙련된 후 사용하는 것이 좋다고 한다. - 강제 푸시: Rebase 후 변경된 브랜치를 원격 저장소에 푸시할 때는 강제 푸시(git push --force) 를 사용해야한다
- 리베이스가 머지보다 더 충돌이 잦다고 하는데, 이럴 때 리베이스 충돌을 해결한 경우 계속 진행해달라는 의미의 continue 명령어를 써야한다. 그래야 리베이스를 이어간다고 한다.
활용 팁
커밋 메시지 수정 및 로컬 브랜치 이력 정리가 가능하다!!
NOTE
amend: 가장 최근 커밋을 수정하는 기능, 커밋에 빠진 파일이나 변경사항을 추가하거나 수정하고 커밋 메시지를 수정할수도 있다.
$ git commit --amend
시간을 되돌리고 싶어요.
reset 과 revert 를 사용할 수 있다.
reset 은 브랜치의 포인터를 특정 커밋으로 이동시키는 명령어다. 해당 커밋 이후의 모든 커밋을 삭제하고 해당 시점으로 되돌려준다.
- --soft: 브랜치 포인터만 이동시키고 변경사항은 스테이징 영역에 남겨둔다.
- --mixed: 브랜치 포인터와 스테이징 영역을 이동시키고 변경사항은 작업 디렉터리에 남겨둔다(이게 기본값이다.)
- --hard: 브랜치 포인터, 스테이징 영역, 작업 디렉터리 모두 이동ㅇ시키도 변경 사항을 완전히 삭제한다.
예시
# 바로 이전 커밋으로 되돌리기
$ git reset --soft HEAD^
# 특정 커밋 ID로 되돌리기
$ git reset --mixed abcefg01234
# 세번째 이전 커밋으로 되돌리기
$ git reset --hard HEAD~3
유의: 과거 이력을 영구적으로 삭제함으로 신중하게 사용해야함. 이미 원격 저장소에 푸시된 커밋을 reset 하면 충돌 발생할 수 있음.
Git revert
특정 커밋의 변경 사항을 취소하고 새로운 커밋을 생성하는 명령어다. 해당 커밋의 내용을 반대로 되돌리는 새로운 커밋을 추가해 과거 시점으로 돌아가는 것처럼 보이게 한다.
장점
과거 이력을 보존하면서 특정 커밋의 변경 사항을 취소할 수 있다.
원격저장소에 푸시된 커밋을 revert 해도 충돌이 발생하지 않는다.
만약 git reset 으로 날리거나 stash(작업 내역 임시 저장해두기) 다면? 쓸 수 있는 것
바로 reflog 라는 명령어다. reference log 로 stash 를 안했을 때나 reset 으로 날렸을 때 이 명령어로 복원이 가능하다. 단, 로컬에서만 사용가능.
reflog 의 정보
- 커밋 해시: 변경이 발생한 커밋의 고유 식별자
- HEAD 이동 정보: HEAD(현재 브랜치 포인터)가 이동한 경로
- 시간 정보: 변경이 발생한 시간
예시
$ git reflog
abcdef1 HEAD@{0}: commit: Initial commit
fedcba2 HEAD@{1}: checkout: moving from master to feature/login
9876543 HEAD@{2}: commit: Add login functionality
즉, 잃어버린 작업 내용을 복구하고 Git 저장소의 변경 이력을 추적하는데 좋다.
좋았던 점
Git 에 대해 알지 못했던 역할이나 명령어부분에 대해 세심하게 알 수 있게 된 계기가 되었다. 브랜치를 관리하는 방법과 스쿼시를 사용하는 이유에 대해서도 알게 되었다.
조금 아쉬웠던 점
1. 똑같은 예제의 상황에서 깃 명령어를 시범으로 보여주시고 바로 같은 걸로 실습을 진행했던 것이 아쉬웠다. 그 명령어를 칠 때 나는 이해하면서 명령어를 같이 쳤고, 같은 문제로 실습해보라고 했을 땐 이미 명령어를 다 치고 끝나 있었기 때문이다. 조금 다른 응용문제로 실습을 해보라고 제시해주셨으면 좋았을 것 같다.
2. 대부분의 협업이나 개인 프로젝트 작업을 하면서 내가 겪은 것은 conflict 가 많아서 conflict 해결을 할 때도 많았다. 어떤 상황에서 컨플릭트(충돌)이 나는지 그에 대한 케이스들도 보여주면 좋을 것 같다고 생각했다. 이건 아마 내가 적극적으로 의견을 제시하지 않아서 반영하시지 못했을 수도 있다. 왜 이걸 제안할 생각을 못했을까 아쉽다.
3. fast-forward 와 3-way merge 에 대해 사전 공부를 하면 좋다고 하셔서 도움은 되었는데, 강의 때 간결하게 한번 더 언급해 주셨으면 리베이스 공부하면서 이해가 더 잘 되었을 것 같다.
오프라인이 직접 질문하기 좋았지만, 온라인으로 했다면 시간 상관없이 늦게까지 할수도 있었을 것 같아서 아쉬웠다.
깃을 하나하나 공부하기엔 버겁고 와닿지 않을 것이다. 그래도 터미널에 직접 깃 명령어를 치면서 이해를 하는 것이 도움이 되긴 한다. 프로젝트를 진행하면서 적재적소 필요할 때 명령어를 보고 체득하는 것도 도움이 될 것이다. 필요한 부분들을 단편적으로 잘 배웠던 계기가 되었으나 조금은 이론적인 부분의 정리가 부족하여 학교 책과 공식문서를 보고 다시 정리를 했다.
더 언급하지 못한 부분들은 3-way와 fast-forward 방식의 병합(Merge)방식인데, rebase 와 연관이 많은 부분이었다. 제대로 언급을 하면 글이 길어질 것 같아, 다음에 따로 글을 써보고 싶다.
참고
git-scm 공식문서
깃미남 - 토미님의 오프라인 강의
gemini 답변
글쓰기 소요시간: 약 3-4시간
Git 공부: 유닉스시스템, 깃미남 강의 (대략 4-5시간)
본 게시물에 문제가 되는 내용이나 사진이 있다면 댓글을 남겨주세요. Git 에 관련된 의견이나 조언, 틀린 부분 피드백 모두 환영합니다.
'devOps' 카테고리의 다른 글
[ zsh ] 맥 터미널에서 내 프로젝트 파일 구조를 보고 싶다면? (0) | 2023.08.25 |
---|---|
[ git ] mac terminal message : Changes not staged for commit (0) | 2023.08.02 |
[ Git ] Error log - Git 터미널 : fetch 하고 push, rsh 터미널 세팅 (2) | 2023.05.11 |
[ Github ] SSH 로 Git Clone 하는 방법 (0) | 2022.05.21 |