Git은 버전관리 소프트웨어 (VCS) 입니다.
버전 관리 소프트웨어는 집중형과 분산형이 있습니다.
- 집중형 : 말 그대로 모든 소스코드가 한 곳에 집중되어 있는 형태입니다.
장점 : 저장소 하나를 중심으로 운영하므로 시스템 운영이 수월합니다.
단점 : 서버에 문제가 생기면 아무도 접근할 수 없으므로 문제가 발생할 가능성이 있습니다.
또한 동시에 접근해서 수정하면 수정한 내용의 충돌이 발생할 수 있으므로 순서대로 대기 했다가 수정해야 합니다.
- 분산형 : 집중형과 달리 저장소가 여러 개 있습니다. Git이 분산형에 해당합니다.
버전관리가 필요한 이유 : 많은 기능이 추가되고, 코드가 변경되기 때문에 불안정한 코드가 아닌 안정적인 복귀지점이 필요하기 때문입니다.
Git
깃은 대표적인 분산형 버전관리 시스템입니다.
특징으로 네트워크나 인터넷이 연결되어 있지 않은 상태에서도 소스코드만으로 관리할 수 있습니다.(추후에 인터넷 연결 시 동기화) 또한 많은 원격저장소에 연결 및 작업이 가능합니다.
- 협업 : 깃을 사용하면 네트워크를 통해 코드를 더 쉽게 공유할 수 있습니다. 즉 , 소스코드를 쉽게 주고 받을 수 있습니다.
- 병합 : 소스코드를 수작업으로 병합하기는 매우 어렵습니다. 그러나 깃에서는 다양한 병합 알고리즘을 제공하므로 소스코드의 충돌을 최소화하고 최종 코드를 쉽게 유지할 수 있습니다.
- 공개 : 코드가 공개되어 있을 뿐만 아니라, 외부 개발자가 fork하여 소스코드의 버그 수정, 기능 개선, 코드 병합이 가능하기 때문에 프로젝트를 빠르게 성장 및 발전 시킬 수 있습니다.
Git config
[git config 설정값] 명령어를 통해 환경설정 파일을 직접 수정하지 않고도 환경 설정 할 수 있도록 합니다.
ex) git config user.name jhl8109
응용하여 global 옵션도 사용할 수 있습니다. global은 로컬 저장소를 생성할 때마다 설정하지 않고, 공통된 사용자 등록할 수 있습니다.(개인 컴퓨터 권장)
ex) git config --global user.name jhl8109
ex) git config --global alias.show-graph 'log --graph --pretty=online' ''의 명령어를 show-graph로 간단하게 사용가능
Git 상태
Untracked상태 : 파일이 추가되었거나 수정되었지만 추적되지 않는 상태입니다.
Tracked상태 : git add 명령어를 통해 추적 중인 상태입니다.
이처럼 요청받은 파일들만 관리한다면 매번 파일 목록을 추적하는 불필요한 리소스 낭비를 줄일 수 있습니다.
Stage : stage는 워킹 디렉토리와 실제로 저장되는 공간 사이 임시영역입니다. tracked 파일을 잠시 복사합니다.(콘텐츠 내용이 아닌 파일 변경 정보 등을 복사)
하는 일로는 stage 영ㅇ역에서 가르키는 파일 내용을 기반으로 커밋을 빠르게 처리하는데 도움을 줍니다.
Unstaged상태 : 파일에 변화가 있을 때, 혹은 아직 untracked 상태 파일들이 unstaged 상태입니다.
Modify : 깃은 tracked 파일만 수정 여부를 관리할 수 있습니다. tracked 상태인 파일이 수정되면 modified 상태가 되고 이 때 modified 상태로 변경된 파일은 stage에서 제외됩니다.
Git ignore
.gitignore : 깃은 tracked 상태인 모든 것을 추적 관리하지만 추적하지 않아야 하는 파일을 .gitignore 설정 파일로 설정 할 수 있습니다. .gitignore 목록에 있는 파일은 추적하지 않습니다. 또, 로컬 저장소를 서버로 이동하거나 다른 사람과 공유할 때도 이를 분리하여 처리합니다.
<주의> .gitignore 파일을 작성할 때는 저장소 폴더의 최상위 디렉토리에 두어야 합니다.
Git Download VS Clone
git download : 다운로드는 최종 복사본을 내려받지만 깃의 이력(기록, .git)을 포함하지 않습니다.
git clone : 저장소의 URL을 통해 새 폴더에 복제하며 직접 폴더명을 바꾸지 않으면 레포지토리 이름과 동일한 폴더로 복사합니다. 다운로드와 달리 깃의 이력을 포함합니다.
Git 파일 등록 취소(git add 되돌리기)
만약 tracked 상태의 파일을 untracked 상태로 변경하려면 어떻게 해야할까요?
rm 명령어를 사용할 수 있습니다. git rm --cached "파일이름"
이는 tracked 상태의 파일은 untracked 상태로 변경할 수 있지만 이미 커밋을 했다면 reset을 사용해야 합니다.
Commit
커밋 이전에 HEAD에 대해 먼저 알아보겠습니다.
HEAD는 커밋을 가리키는 묵시적 참조 포인터 입니다. 최종적인 커밋 작업의 위치를 가리킵니다.
커밋은 파일 전체를 저장하는 것이 아니라 파일 변화를 저장하는 것이라 알아본 바 있습니다.
용량을 효율적으로 관리하기 위해 변경된 부분을 찾아 수정된 내용만 저장합니다. 이를 `스냅샷`방식이라고 합니다.
HEAD가 가리키는 커밋을 기반으로 빠르게 버전의 차이점을 처리합니다.
commit message
커밋은 모든 파일별로 따로 하는 것이 아니라 여러 개의 파일을 커밋하면 하나의 이름을 가지기 때문에 커밋 메세지는 매우 중요하고 반드시 작성해야합니다.
git commit -m "커밋메세지" 명령어를 통해 커밋 메세지와 함께 커밋 할 수 있으며
git commit -a add와 동시에 commit 하는 명령어와 합치면
git commit -am "커밋메세지" 파일 등록과 함께 커밋 메세지를 입력할 수 있습니다.
git commit --allow-empty-message -m 을 통해서 커밋 메세지를 작성하지 않을 수 도 있습니다.
commit 확인
git log 명령어를 통해 커밋 기록을 확인할 수 있습니다. 최신 커밋 기록부터 내림차순으로 나열합니다.
git commit 되돌리기
컴퓨터에서 파일을 수정하다가 파일을 잘 못 수정한 경우 되돌릴 수 있습니다.
git checkout -- "수정파일 이름" 을 통해서 이전 커밋 내용으로 되돌릴 수 있습니다.
git diff
git diff head 명령어는 워킹디렉토리와 최신 스테이지의 차이점을 터미널에 출력해줍니다.
Github
깃허브는 대표적인 깃 호스팅 서비스 입니다. 깃의 원격 저장소 주소를 알려줌으로써 손쉽게 코드를 공유할 수 있게 되었습니다. 개인 깃허브 주소는 https://github.com/사용자이름 입니다.
git remote add 로 원격 저장소와 연결 할 수 있고 git remote -v 를 통해서 연결된 원격 저장소를 확인할 수 있습니다.
사용하지 않는 원격 저장소는 git remote rm 으로 삭제할 수 있습니다.
git에서 commit 했던 내용 들을 git push "원격 저장소 별칭" "브랜치이름" 으로 깃 저장소의 내용을 전송할 수 있습니다.
git clone : 복제
clone 명령어는 초기화 init명령어 외에 원격 서버 접속에 필요한 추가 설정을 자동으로 수행합니다. 서버의 연결 설정을 마친 후 서버 안에 있는 모든 커밋된 코드 이력들을 한 번에 내려받습니다.
git pull : 서버에서 내려받기
pull 명령어는 복제 후 원격 저장소의 갱신된 내용을 추가로 받으려면 pull 명령어를 사용합니다.
로컬 저장소 보다 최신인 갱신된 원격 저장소의 커밋 정보를 현재 로컬 저장소로 내려받습니다.
pull 명령어는 내려받은 최신 커밋을 현재 브랜치로 자동 병합 처리한다는 특징이 있습니다.
git fetch : 가져오기
fetch는 원격 저장소에서 코드를 수ㅈ동으로 내려받는 작업을 합니다. 내려받은 후 현재 브랜치와 자동 병합하지 않습니다.
git merge : 수동 병합
git merge 원격저장소별칭/브랜치이름 명령으로 수동으로 병합할 수 있습니다.
주의 사항
- 원격 저장소에 푸시하려면 자신의 로컬 저장소를 최신 상태로 유지해야합니다. 그렇지 않으면 깃은 푸시 동작을 거부합니다.(충돌(conflict)을 방지하기 위함.)
- pull 과 push 를 자주 하여 버전 관리를 효율적이고 충돌 없이 유지할 수 있습니다.
Branch
깃 브랜치는 기존 폴더를 복제하는 것과 다르게 가상 폴더를 사용하여 개발 작업을 구분합니다.
원본 코드에 병합하기만 하면 되기 때문에 코드 통합 부분에도 유용합니다.
git branch 명령어를 통해 branch를 확인할 수 있습니다.
git branch -a 명령어를 통해 모든 브랜치를 확인할 수 있습니다.
git branch "브랜치 이름" "커밋 ID" 를 통해 브랜치를 생성할 수 있습니다.
git branch -d "브랜치 이름" 으로 브랜치를 삭제할 수 있습니다.
git push origin --delete "리모트 브랜치 이름" 으로 원격저장소에 있는 브랜치도 삭제할 수 있습니다.
git checkout 명령어를 통해 branch간 이동이 가능합니다.(branch 변경)
브랜치 이동을 하기위해서 주의해야 할 사항이 있습니다.
git checkout -b "브랜치 이름" : 브랜치생성과 동시에 이동
현재 작업하고 있는 워킹 디렉토리를 정리하고 넘어가야 합니다.
브랜치가 변경 됨에 따라 워킹 디렉토리도 변경되기 때문입니다.
git checkout HEAD~5 를 통해서 HEAD보다 5단계 이전 커밋 상태로 돌아갈 수 있습니다.
1,2,3,4등 모든 숫자가 가능합니다.
다시 현재 시점으로 돌아올면 git checkout - 를 통해서 checkout 전 브랜치로 다시 돌아올 수 있습니다.
git checkout -b "원하는 이름" origin/"브랜치이름" 으로 원격 저장소의 리모트 브랜치를 로컬 저장소에도 가져올 수 있습니다.
이렇게 브랜치에서 수정한 내용을 git push "원격 저장소 별칭" "브랜치 이름" 으로 push 할 수 있습니다.
브랜치는 다른 개발자와 협업할 때 상호 간섭없이 별개 작업을 수행할 수 있어서 유용합니다.
별개 작업 후 병합까지 가능하기 때문에 자주 사용됩니다.
Git stash
작업 브랜치를 변경하려면 워킹 디렉터리는 깨끗한 상태로 정리되어 있어야 합니다. 워킹 디렉터리에 작업 중인 내용이나 커밋되지 않은 변경 사항들이 남아 있으면 브랜치를 변경할 수 없습니다. 예를 들어 브랜치에서 코드를 수정하는 도중에 새로운 버그가 발견 되어 긴급히 코드를 수정해야하는 경우 현재 작업 중인 코드를 임시 보관하고 이동하여야 할 것 입니다. 이때 사용되는 것이 git stash 입니다.
git stash는 완료되지 않은 작업이 남아 있을 때 현재 작업을 임시로 저장할 수 있는 기능입니다.
현재 작업중인 내용은 임시 저장되고(임시 스택 영역), 수정 전 마지막 커밋 상태로 돌아 갑니다.
간단하게 git stash 를 사용할 수 있고 스태시를 여러 개 생성할 때 git stash save "메시지"로 사용합니다.
저장된 stash 는 git stash list 를 통해서 확인할 수 있습니다.
git stash pop을 통해 제일 마지막에 저장된 내용을 읽어올 수 있습니다.
git stash apply를 통해 제일 마지막에 저장된 내용을 복원할 수 있습니다.
pop은 스택 내용을 복원한 후 스택 목록에서 자동으로 삭제합니다.
apply은 스택 내용을 복원한 후 스택 목록에서 자동으로 삭제 되지 않습니다.
따라서 apply의 경우 git stash drop 을 통해 복원한 후 스태시 목록에서 수동으로 삭제하기도 합니다.
스태시를 복원하는 경우 충돌이 일어나면 어떻게 될까요?
스태시를 복원하는 경우 충돌이 일어나면 스택에 저장된 내용을 자동으로 삭제하지 않습니다.
수동으로 충돌을 해결 한 후 스태시 목록을 수동으로 삭제해야 합니다.
git stash branch "브랜치 이름" 으로 스태시 스택에 저장된 내용으로 새로운 브랜치를 생성할 수도 있습니다.
참고 사항
스태시를 너무 많이 만들어 사용하는 것은 바람직하지 않습니다. 사용한 스태시는 그때그때 삭제하여 정리하는 것이 좋습니다.
git clean 명령어를 통해 워킹 디렉토리에 있는 추적되지 않는 파일들을 찾아 삭제할 수 있습니다.
강제로 삭제하고 싶은 경우 git clean -f 를 통해서 강제로 삭제할 수 있습니다.
깃을 안정적으로 잘 사용하려면 워킹 디렉터리를 항상 깨끗하게 유지 관리해야합니다. 워킹 디렉토리가 정리되어있지 않다면 브랜치를 옮길 수 없습니다. 워킹 디렉토리를 정리하려면 수정된 코드를 스테이지 하고 커밋하는 것입니다.
Git 병합
Branch 분리를 함으로써 분리된 개발 작업이 가능해지고, 병합을 통해 직접 코드를 비교하지 않고 코드를 합칠 수 있습니다. Git은 원본을 기준으로 두 파일의 변경 이력을 비교합니다. 변경된 파일 내용이 발견되면 자동으로 수정된 코드 내용을 병합합니다. 브랜치를 기준으로 분리된 각각의 브랜치에서 수정된 사항을 하나의 브랜치로 병합합니다.
Git은 병합을 위해 두 가지 기본적인 알고리즘 방식을 제공합니다. 깃에서 충돌 없이 병합하려면 이 두가지 병합 방식의 차이를 알아야합니다.
- Fast-Forward : 순차적 커밋에 맞추어 병합을 처리하는 방법. 즉, 메인이 아닌 브랜치에서 여러 번의 커밋이 수행되었을 때 브랜치의 커밋들이 하나씩 main 브랜치에 병합됩니다. 원본 브랜치 이후를 작업한 브랜치의 시작 커밋으로 가르켜 원본 브랜치에 병합합니다. 일반적으로 혼자 개발을 진행하는 경우에 사용합니다.
- 3-Way : 3-way병합은 공통 조상 커밋 즉, 분할 기준을 자동으로 찾습니다. 이를 토대로 브랜치를 병합합니다. 여러 개발자 와 협업으로 작업하는 경우 대부분 3-Way 병합을 사용합니다.
git merge "브랜치 이름" 명령어는 현재 브랜치를 기준으로 다른 브랜치의 모든 커밋을 병합합니다.
현재 브랜치 기준임을 주의하여 주시면 되겠습니다.
git merge -e 혹은 git merge --edit 명령어를 통해서 병합하는 과정에 메시지를 작성할 수 있습니다.
병합 되지 않은 branch를 삭제할 때에는 git branch -d 가 아닌 git branch -D 대문자 옵션을 사용하여 제거할 수 있습니다.
주의사항 : 병합하려면 모든 브랜치가 단일 저장소(로컬 저장소)에 있어야합니다.
모든 병합 작업이 완벽히 처리되지는 않습니다. 이 때 일어나는 문제를 "충돌" 이라고 합니다.
대표적으로 여러 사람과 개발한 코드 일부분이 충돌하는 경우가 있습니다. 같은 위치의 코드를 동시에 수정하는 경우 일반적으로 발생합니다.
이렇게 충돌이 일어난 경우 자동으로 커밋이 생성되지 않고 개발자가 직접 충돌을 해결해야 합니다.
충돌한 소스코드를 확인하면
<<<<main
~~~~~~
========
~~~~~~
>>>>branch
의 형태로 나타납니다. 상단은 기준이 되는 브랜치, 하단은 병합하고자 하는 브랜치 내용입니다. 두 코드 중 남길 코드로 수정하면 됩니다. 깃에서 표시한 충돌 기호도 함께 삭제 해야합니다. 충돌을 해결한 후 따로 또 커밋을 해주어야 합니다.
병합이 잘 되었는지 확인하려면 git branch --merged 를 통해 확인할 수 있습니다.
병합하는 또 다른 방법이 있습니다.
git rebase입니다. rebase 는 커밋 순서를 재배열합니다.
원래 새로운 브랜치를 생성할 때 브랜치가 파생되는 커밋(공통 조상 커밋)을 베이스라고 합니다.
rebase 란 base를 재설정 하는 것인데 이를 하는 이유는 무엇일까요?
브랜치가 많아지면 커밋을 관리하고 파악하기 어렵습니다. 수많은 브랜치의 경로가 꼬여 진행 상황을 한 눈에 파악하기 어렵게 합니다. 그래서 코드의 베이스 분기점을 변경합니다.
그렇다면 rebase와 merge의 차이는 무엇일까요?
merge는 두 브랜치의 공통 조상 커밋을 먼저 찾고 공통 조상 커밋을 찾으면 서로 다르게 커밋이 진행된 두 브랜치를 3-way 방식으로 병합할 수 있습니다. 두 브랜치는 순차적으로 커밋을 비교하면서 최종 커밋을 생성합니다.
rebase는 두 브랜치를 서로 비교하지 않고 순차적으로 커밋 병합을 시도합니다. rebase 또한 공통 조상 커밋을 찾지만 merge와 달리 베이스 커밋을 변경하여 두 브랜치의 커밋 위치를 바꿉니다. 그리고 파생된 브랜치의 diff를 임시 공간에 잠시 보관합니다. 변경하는 기준 브랜치의 마지막 커밋(바뀐 base)에서 차례로 임시 공간에 저장한 diff를 하나씩 적용합니다. 새로운 베이스를 기반으로 커밋을 연장하여 커밋을 생성합니다.
결과물을 확인해 보면
- 3-way병합은 병합 커밋이 있지만, 리베이스는 병합 커밋이 없습니다.
- 브랜치의 마지막을 가리키는 커밋 위치가 다릅니다.
git rebase "브랜치 이름" 으로 rebase 할 수 있습니다.
rebase는 merge와 달리 기준 브랜치에서 다른 브랜치로 병합을 하는 정반대로 이해할 수 있습니다.(파생브랜치 에서 git rebase main)
rebase는 커밋 위치를 재조정하지만 브랜치의 HEAD포인터는 옮기지 않습니다
따라서 rebase한 후에는 병합 브랜치의 HEAD를 맞춰야 합니다.
main이 아닌 branch에서 rebase했기 때문에 다시 main 브랜치로 checkout 해준 후 merge를 실행해 줍니다.
== git merge description 명령어로 HEAD 포인터를 조정합니다.
rebase도 merge 처럼 충돌이 일어날 수 있고 동일한 방법으로 직접 코드를 수정하여 해결할 수 있습니다.
충돌을 수정한 후에는 git rebase --continue 로 rebase를 할 수 있습니다.
충돌이 일어났을 때 rebase를 취소하고 싶으면 git rebase --abort로 취소할 수 있습니다.
git rebase -i HEAD~3 과 같은 식으로도 사용할 수 있습니다. 여러 커밋들을 하나로 묶을 수 있습니다.
주의할 점 : rebase는 커밋 위치와 해시 값을 변경하기 때문에 외부에 공개된 저장소라면 공개된 순간부터 커밋은 리베이스를 사용하지 않는 것이 좋스습니다.(혼란을 야기할 수 있음. 공개된 커밋을 변경할 때에는 revert 명령어 사용 추천)
정리 : rebase는 merge와 달리 커밋 구조를 비선형에서 선형 구조로 바꾸기 때문에 실무에서도 유용하게 사용할 수 있을 것 같습니다. 브랜치가 많아지면 많아질 수록 rebase를 적극적으로 사용하면 좋을 것 같습니다.
되돌리기
깃은 커밋을 기준으로 이전 상태로 되돌릴 수 있습니다. 이를 통해 코드를 항상 안정적인 상태로 유지할 수 있습니다.
깃에서 코드 작업을 되돌리는 방법은 reset 과 revert 두 가지가 있습니다.
git reset 옵션 커밋ID
reset은 커밋을 기준으로 이전 코드로 되돌리는 방법으로, 기록한 커밋을 취소합니다.
git log --online 옵션으로 로그들의 커밋 해시 값과 메시지를 확인할 수 있습니다.
reset의 옵션에는 세 가지 옵션이 있습니다.
- soft : 스테이지 영역을 포함한 상태로 복원합니다.
- mixed : 기본 옵션 값은 mixed입니다.
- hard : 실제 파일이 삭제된 이전 상태로 복원합니다.
soft 옵션은 커밋을 삭제하지만 스테이지 영역의 상태도 같이 복귀합니다. 파일을 수정하고, add 명령어로 스테이지 영역에 올려 커밋을 실행하기 직전의 단계로 되돌립니다.
mixed 옵션은 soft 옵션과 달리 instaged 상태로 변경시킵니다. 따라서 soft는 바로 commit 을 하면 되지만 mixed 옵션의 경우는 add 후 commit을 실행해야 하는 상태입니다.
hard 옵션은 복귀 시점의 커밋 상태 이후의 작업 내용은 모두 삭제됩니다. 즉, 워킹 디렉토리 내용도 함께 삭제됩니다.
git --soft HEAD~2의 경우는 어떻게 될까요?
HEAD로 부터 2단계 전 상태로 리셋되고 staged 상태에는 두 개의 커밋이 합쳐진 상태입니다. 이처럼 사용하면 두개의 커밋을 하나의 커밋으로 만들 수도 있습니다.
커밋을 되돌리는 것이 아니라 add명령어로 등록된 스테이지 영역의 파일을 다시 unstaged 상태가 되도록 staging을 취소할 수도 있습니다. git reset "파일이름"으로 해당 파일만 unstaged 상태로 만들 수 있습니다.
이는 git reset --mixed HEAD "파일이름" 과 동일합니다. HEAD자리에 다른 커밋 ID 를 넣어 다른 커밋 ID를 사용할 수도 있습니다.
특정 작업만 취소하지 않고 현재 작업을 모두 취소하기 위해서는 git reset --hard HEAD 명령어를 통해서 워킹 디렉토리 안의 작업을 모두 삭제할 수 있습니다.
병합 취소
리셋 명령어로 병합된 브랜치도 취소할 수 있습니다.
git reset --merge HEAD~ 옵션으로 병합한 커밋을 리셋하여 취소할 수 있습니다.
주의할점
저장소를 외부에 공개했거나 공유하고 있다면 주의해서 리셋을 사용해야합니다.
함께 작업하는 개발자에게 혼란을 줄 수 있습니다.
git revert
공개한 저장소를 되돌릴 때 주로 사용합니다. revert는 기존 커밋을 남겨 두고 취소에 대한 새로운 커밋을 생성합니다.
커밋을 삭제하기 보다 삭제를 위한 새로운 커밋을 생성합니다.
revert의 특징은 한 번에 커밋 하나만 취소할 수 있습니다. 만약 직전 커밋이 아닌 그 이전의 커밋을 취소하고 싶다면 차례대로 revert 해줘야합니다. git revert 를 한 번씩 해주거나 혹은 git revert 커밋ID .. 커밋ID (..은 연산자입니다.) 의 형태로 여러 커밋을 리버트 할 수 있습니다.
revert를 이용하여 병합한 커밋을 취소할 수 있습니다.
git revert --mainline 숫자 "병합 커밋 ID" 명령어를 통해 병합을 취소한 후 체크아웃이 되는 브랜치로 이동합니다.
--mainline 숫자 명령어로 체크아웃이 되는 브랜치를 지정할 수 있습니다.
참고로 rebase된 병합은 revert하기 어렵습니다. rebase로 병합된 공통 조상 커밋을 찾기 어렵기 때문입니다.
주의할점
revert를 실행하면 새 커밋이 추가되기 때문에 커밋 이력이 복잡합니다. reset이 더 간단하게 이전 상태로 되돌린다고 생각될 수 잇습니다. 하지만 저장소를 공개했다면 reset으로 커밋을 삭제하는 것은 협업하는 개발자가 변경사항을 인지하지 못할 위험이 있습니다. 따라서 저장소를 공개했다면 revert가 유용할 수 있습니다.
배포 관리와 태그
배포란 프로그램을 개발한 후에 완성된 결과물을 사용자에게 전달하는 과정을 말합니다.
개발을 완료했다고 바로 배포하는 것이 아니라 개발 단계에서 발생한 테스트 메시지나 불필요한 주석들을 정리합니다.
요즘에는 인터넷이 발달하면서 과거의 물리적인 배포 대신 온라인으로 배포합니다. 온라인 배포는 물리적 생산 비용과 유통 비용이 들지 않고, 빠르게 배포할 수 있습니다.
버전 : 배포 당시에는 발견하지 못했는데 이후에 잘못된 동작을 하거나 예외적인 상황이 생겨 처리하지 못하는 동작들이 있을 수 있습니다. 또는 사용자에게 추가 기능을 제공할 수도 있습니다. 이렇게 코드는 계속 배포 이후에도 계속 수정됩니다. 버전은 프로그램을 수정하거나 개선할 때마다 코드를 구분하려고 부여된 식별자 입니다. 숫자가 클수록 최근에 수정된 코드입니다.
SemVer(Semantic Versioning) 규칙
- Major : 메이저 버전은 프로그램에서 큰 기능을 변경 했을 때 바뀝니다. 첫 자리가 0 일 경우 초기 개발 중인 제품이라는 의미입니다. 정식 버전은 1부터 시작합니다. 메이저 번호를 변경하면 하위 버전과 호환성이 낮아질 수 있습니다.
- Minor : 마이너 버전은 메이저 버전에서 기능을 추가하거나 변경 사항이 있을 때 바꿉니다.
- Patch : 패치 버전은 버그 수정 등 미미한 변화가 있을 때 바꿉니다.
태그 : 태그는 특정 커밋의 해시 값을 가리키는 꼬리표를 의미합니다. 사용자는 개발자가 부여한 태그를 사용하여 코드 버전을 구별합니다. 태그는 커밋 해시 값을 기준으로 생성됩니다. 그리고 특정 커밋 해시 값을 가리키는 것뿐만 아니라, 꼬리표 이름과 정보도 포함합니다. 이러한 태그는 추가 정보를 보유하는지 여부에 따라 두 가지로 구분합니다.
- Annotated : 태그 이름 + 정보 포함
- Lightweight : 태그 이름만 포함
Annotated 태그는 git tag -a "버전" 명령어로 생성할 수 있습니다. 명령어를 작성하면 태그 메시지를 작성할 수 있는 vi 에디터가 함께 실행됩니다. 간단한 메시지일 경우 git tag -a "버전" -m "메시지" 명령어로 바로 작성할 수도 있습니다.
git tag -d "태그 이름" 명령어로 기존에 생성한 태그를 삭제할 수 있습니다.
git tag 명령어로 상세 정보가 없는 태그 목록을 확인할 수 있습니다.
git show "태그이름" 명령어로 해당 태그의 상세 정보를 확인할 수 있습니다.
Lightweight 태그는 git tag "태그이름" 명령어로 생성할 수 있습니다.
일반적으로 태그는 현재 HEAD가 가리키는 커밋을 기준으로 태그를 생성합니다. HEAD 포인터가 가리키는 커밋이 아닌 특정 커밋을 직접 지정하여 태그를 생성할 수 있습니다.
git tag -a "태그버전" "커밋ID" 이 경우 tag명령어는 지정된 커밋 해시 값을 기준으로 새로운 태그를 생성합니다.
태그는 특정 커밋을 가르키는 포인터 입니다. 따라서 태그를 사용하여 특정 커밋으로 체크아웃을 할 수도 있습니다.
git checkout "태그이름" 대신 태그를 사용하여 브랜치를 바꾸면 특정 커밋으로 체크아웃할 수도 있지만 브랜치처럼 추가로 커밋을 작성할 수는 없습니다. checkout -b 로 브랜치를 생성하듯이 git checkout -b "태그이름" 으로 태그 기준으로 브랜치를 생성할 수 있습니다.
git push "브랜치이름" 은 태그 정보가 함께 전달되지 않기 때문에
git push "태그이름" 을 사용해야 태그 정보가 함께 전달됩니다.
태그들을 한번에 전달하려면 git push origin --tags 옵션으로 origin 브랜치에 모든 태그를 원격 서버에 전송할 수 있습니다.
주의사항
깃에 등록된 태그 이름은 유일해야 합니다. 즉, 태그는 같은 이름으로 중복해서 생성할 수 없습니다.
서브모듈
깃 저장소는 용량 한계가 없습니다 . 컴퓨터의 하드디스크에서 지원하는 용량만큼 깃 저장소를 생성할 수 있습니다. 또 깃은 파일을 기반으로 데이터베이스를 관리합니다. 하지만 저장소 크기가 너무 크면 컴퓨터에 부담을 줍니다.
이러한 이유로 깃 호스팅 서비스들은 제공되는 저장소 용량을 제한합니다. 보통 1GB용량으로 제한하기 때문에 파일 개수가 많은 프로젝트에서는 좀 더 효율적인 관리 방법이 필요합니다. 대규모 프로젝트의 경우 저장소 용량이 많이 필요합니다.
단지 용량이 크기만 한 저장소는 비효율적이기 때문에 필요에 맞게 작은 저장소로 분할하여 운영하는 것이 좀 더 효율적 입니다. 깃 역시 큰 규모의 저장소를 작은 저장소로 나누어 관리할 수 있습니다. 이렇게 저장소 하나가 다른 깃 저장소에 포함될 수 있고 이러한 형태를 서브모듈 이라고 합니다.
보통 대형 프로젝트는 모듈화하여 개발하는 추세입니다. 기능들을 모듈화하여 독립된 깃 저장소로 관리합니다.
메인 저장소와 서브 저장소의 저장소 간 상하 관계가 존재합니다. 부모 저장소, 자식 저장소 형태로 나눕니다.
이렇게 분리된 로컬 저장소는 또다시 개별 원격 저장소와 연결됩니다. 원격 저장소로 동기화된 자식들은 언제든지 다른 프로젝트의 모듈별로 기능을 처리하고 결합할 수 있습니다.
git submodule add "원격저장소URL" "레포지토리이름" 명령어로 메인 저장소에 자식 저장소를 연결할 수 있습니다.
추가되면 메인저장소는 서브 저장소를 서브 폴더 형태로 취급합니다.
이렇게 서브 모듈 형태로 변경되면 메인 저장소 내부에 child 폴더가 생기며 child 폴더에 자식 저장소가 저장되어 있습니다.
자식 저장소에 변경사항이 있는 경우 메인 저장소에서 git status를 입력하면 child에 변경사항이 있음을 표시합니다.
즉, 상위 메인 저장소에서는 서브모듈의 저장소 자체를(child 통째로 변했는지 안변했는 지를 판단함) 추적합니다.
cd 명령어를 통해서 child 에서 git commit -am "메시지" 의 명령어를 통해 직접 커밋해주어야 합니다. 이 때 커밋은 하위로 복제 생성된 자식 저장소에만 커밋하는 것입니다.
이렇게 자식 커밋이 완료되면 부모에서도 커밋을 하여 기록해야합니다.
메인 저장소의 자식 저장소는 실제로 다른 저장소에 있는 내용의 복제본입니다. 따라서 자식 저장소에 연결된 원격 저장소를 이용하여 실제 자식 저장소를 최신 커밋 정보로 갱신해야합니다.
실제 자식 저장소로 이동하여 git pull ~~~~ 를 통해 갱신합니다.
만약 실제 자식 저장소를 수정했다면, 복제된 자식 저장소로 이동하여 git pull ~~~(origin main) 을 수행하여 최신 정보를 갱신합니다. 물론 이 때 서브모듈이 변경 되었기 때문에 메인 저장소에서는 add 와 commit을 수행해야 합니다.
git clone 을 통해 서브 모듈이 있는 메인 저장소를 복제할 경우 서브 모듈 폴더 안에는 아무 것도 없습니다.
.gitmodules 파일은 존재하지만(서브 모듈 정보는 존재) 실제 하위 저장소는 같이 복제하지 않습니다. 따라서 서브모듈의 하위 저장소는 직접 명령어를 실행하여 가져와야 합니다.
메인 저장소에서 아래의 명령어를 수행해야합니다.
git submodule init --- 서브 모듈 초기화
git submodule update --- 서브 모듈 업데이트
이를 통해 서브 모듈의 복제한 하위 저장소 내용이 추가되었습니다.
주의할점
하위 저장소에 새로운 커밋이 생성되면 메인 저장소는 이를 반영합니다. 반영한 하위 저장소의 변경된 내용 때문에 메인 저장소를 pull 해줘야 합니다. 하지만 메인 저장소를 pull 한다고해서 부모 저장소에 종속된 모든 서브 저장소까지 자동으로 갱신되지는 않기때문에 서브 모듈 업데이트는 git submodule update의 별도의 명령어를 수행해 주어야 합니다.
깃 상태 이미지 출처
https://dev.to/mollynem/git-github--workflow-fundamentals-5496
'GIT' 카테고리의 다른 글
Github를 활용한 협업 방법 (0) | 2021.07.08 |
---|