Git 기초부터 DevOps까지: 버전 관리 시스템의 핵심 개념과 활용법
OSSCA 2차 체험형 프로젝트 Git / Github 시작부터 DevOps / MLOps 까지를 6주간 참여하게 되었습니다. 이번 포스팅에서는 git 개념과 프로젝트 실습 내용을 정리해나갈 예정입니다.
프로젝트 명
Git / Github 시작부터 DevOps / MLOps 까지
기간
협업도구(Git) 심화 과정 멘토링(3주) + 분야별 오픈소스 프로젝트 활용 실습 멘토링(3주)
기본 교육
사전 학습 내용
Git이란
소스 코드를 관리하기 위한 분산 버전 제어 시스템입니다. 소스 코드의 변경 사항을 기록하므로 언제든지 이전 버전으로 복원하며 기록을 추적할 수 있습니다.
세가지 주요 구성 요소
- 저장소
- 모든 변경 사항을 추적하는 컨테이너
- git log command를 사용하여 커밋 기록 액세스
- 작업 트리
- 작업 중인 파일
- 인덱스(스테이징 영역)
- 커밋이 준비 되는 곳
- 작업 트리의 파일이 저장소의 파일과 비교 됨
변경사항 기록
Git은 모든 변경사항을 자동으로 기록하지 않습니다.
인덱스에서 해당 변경 사항을 준비하여 기록하려는 변경 사항을 Git에 알려줘야 합니다. 스테이징 후 해당 변셩 사항을 커밋하여 저장소에 기록합니다.
커밋한 모든 내용은 각 파일 또는 디렉토리에서 시간순으로 볼 수 있습니다. (40자 체크섬 해시)
변경 취소
변경 사항을 취소하는 두 가지 주요 방법은 git revert, git reset입니다.
- git revert
- git reset
저장소 동기화
git push, git pull, git merge 명령어를 통해 저장소를 동기화 합니다.
변경사항 병합
로컬 저장소가 오래된 경우 원격 저장소에 대한 푸시가 거부됩니다.
이 경우 푸시 전 git merge를하여 원격 브랜치와 로컬 복사본에서 최신 변경 사항을 통합합니다.
병합동안 git은 기록 변경 사항을 자동으로 적용하고 현재 브랜치와 병합을 시도합니다. 충돌이 있을 경우엔 수동으로 해결해야합니다.
커밋 수정
git commit –amend 를 통해 동일한 브랜치에서 가장 최근 커밋을 수정 할 수 있습니다. 이 명령어는 새 파일이나 업데이트된 파일을 이전 커밋에 추가하거나 이전 커밋 메시지를 편집하는데 사용됩니다.
새 브랜치에 커밋 복사
리베이스는 하나의 브랜치에서 커밋된 모든 변경 사항을 새 브랜치로 복사합니다. git rebase -i
는 기록에서 개별 커밋을 다시 작성, 교체 삭제, 병합 합니다.
rebase
또한 아래를 수행할 수 있습니다.
- 과거 커밋 메시지 다시 쓰기
- 커밋 그룹을 함께 스쿼시
- 커밋되지 않은 파일 추가
다른 브랜치에 커밋 복사
git cherry-pick
명령어는 다른 브랜치에서 저장소 내의 현재 브랜치로 기존 커밋을 복사할 수 있습니다. - 잘못된 브랜치에서 올바른 브랜치로 커밋 이동
- 다른 브랜치의 기존 커밋을 기반으로 현재 브랜치에 커밋을 추가
커밋 병합
스쿼싱은 여러 커밋을 단일 커밋으로 병합합니다.
git merge --squash
은 새 커밋이 브랜치의 모든 커밋을 함께 그룹화합니다. 해당 커밋이 현재 브랜치에 병합됩니다.
브랜치 전환
git checkout
명령을 통해 전환하려는 브랜치에 저장된 버전과 일치하도록 작업 트리의 파일을 업데이트합니다.
브랜치 가리키기
HEAD는 브랜치의 현재 스냅샷을 나타냅니다. 새 저장소의 경우 기본적으로 HEAD가 main 브랜치를 가리킵니다. HEAD가 가리키는 위치를 변경하면 활성 브랜치가 업데이트 됩니다.
~ 및 ^ 은 특정 커밋과 관련되 위치를 가리킵니다.
- ~ 조상을 나타냅니다(몇 세대 전의 세대는 숫자에 따라 다름).
- HEAD~1은 커밋의 첫 번째 부모를 나타냅니다.
- HEAD~2는 커밋의 첫 번째 조부모를 나타냅니다.
- ^ 은 병합 커밋의 부모를 나타냅니다.
- HEAD^1은 헤드가 병합 커밋인 HEAD의 첫 번째 부모를 나타냅니다.
- HEAD^2는 헤드가 병합 커밋인 HEAD의 첫 번째 조부모를 나타냅니다. 커밋은 병합 커밋에서 두 개의 부모를 가질 수 있습니다.
브랜치 보관
작업 트리에 커밋되지 않는 변경 사항(또는 새파일)이 있고, 새 브랜치로 전환하려는 경우 커밋되지 않은 변경 사항도 새 브랜치로 전달됩니다. 커밋한 변경 사항은 새 브랜치에 커밋됩니다. 그러나 이 과정에서 충돌을 발견하면 전환이 허용되지 않고 해당 변경사항을 커밋하거나 임시로 저장하는 stash
를 해야합니다.
stash
에 저장된 커밋되지 않은 변경사항은 언제든지 꺼내서 원래 브랜치나 다른 브랜치에 나중에 적용할 수 있습니다.
원격 브랜치 풀링
원격 브랜치가 로컬 브랜치의 업스트림 ( 원격 브랜치에는 아래와 같이 로컬 브랜치의 모든 변경 사항이 포함 )일 경우 원격 브랜치(origin/main)에서 로컬 브랜치 main으로 적용한다면 fast-forward
병합이 됩니다.
그러나 로컬 메인 브랜치의 변경 사항이 원격 origin/main 브랜치에 없는 경우 pull 명령은 병합을 실행하고, 이러한 변경 사항을 함께 묶는 병합 커밋을 생성합니다.
풀링을 실행할 때 로컬 저장소에 병합 커밋이 자동으로 생성됩니다. 충돌이 있는 경우 충돌을 해결하고 병합을 수동으로 커밋해야합니다. 충돌이 없으면 커밋이 자동으로 병합됩니다.
원격 브랜치 가져오기
원격 브랜치의 변경 사항은 충돌이 없을 때 pulling을 하면 현재 로컬 브랜치에 자동 병합됩니다.
원격 변경 사항을 얻고 싶지만 현재 로컬 브랜치에 병합하지 않으려면 git fetch
를 사용합니다.
변경사항을 가져오면 FETCH_HEAD엥서 병합하거나 풀링을 하여 해당 변경 사항을 로컬 저장소에 적용할 수 있습니다.
FETCH_HEAD가 병합되면 개정 기록은 git pull 작업과 동일한 결과를 생성합니다.
브랜치를 원격으로 푸시
로컬 브랜치를 원격 저장소로 푸시할 때까지 모든 커밋을 사용할 수 있습니다. 푸시로 인해 non-fast-forward
병합이 발생하면, git 은 커밋을 덮어쓰는 것을 방지하기 위해 푸시를 거부합니다. 이 경우 최신 원격 변경 사항을 pulling하고 다시 push해야합니다.
원격 저장소에 이미 커밋된 커밋을 덮어쓰거나 변경하면 다른 티웜의 로컬 저장소가 원격 저장소와 갈라지게 되니 금지합니다.
브랜치 통합
- 병합
- 병합된 브랜치의 모든 변경 사항 및 기록을 유지합니다. 복잡해 질 수 있습니다.
- bugfix를 다시 main으로 병합하는 것은 큰 문제아닙니다. bugfix가 생성된 이후로 main이 변경되지 않았기 때문입니다. git은 main 위치를 bugfix의 최신 위치로 이동하여 병합하는 데 이를
fast-forward
라고 합니다. - 위는 bugfix이후 main이 여러번 업데이트 되었기 때문에 두 브랜치 병합을 위해
merge commit
이 생성되고, main 위치가 새로 생성된 병합 커밋으로 업데이트 됩니다. fast-forward가 아닌 병합은 bugfix 브랜치를 그대로 둡니다.
- 리베이스
- 병합된 커밋이 대상 브랜치의 끝에 추가되므로 깨끗한 개정 기록을 유지합니다. 병합방법보다 충돌이 더 자주 발생할 수 있습니다.
non-fast-forward
병합 시나리오가 있는 두개의 브랜치가 있습니다.- 리베이스를 수행하면 아래와 유사한 브랜치 기록이 생성됩니다.
- 버그 수정 브랜치를 메인 브랜치로 리베이스하면, 버그 수정 브랜치의 커밋이 재생되고 메인 브랜치 끝에 추가됩니다. 그 결과 bugfix 브랜치 기록에 단일 커밋 스트림이 생성됩니다.
- 커밋이 추가할 때 충돌이 발생된느 경우 git은 다른 커밋을 리베이스하기 전에 충돌을 수정하라는 메시지를 표시합니다.
- 리베이스는 메인 위치를 이동하지 않습니다. 어떤 경우든 리베이스 후 버그 수정에서 메인으로 foast-forward 또는 클린 병합을 수행할 수 있습니다.
태깅
git 태그는 기록에서 특정 커밋에 레이블을 지정하고 표시합니다. 일반적으로 릴리스 이름(v1.0)이 태그의 이름인 릴리스 버전을 나타내는데 사용합니다.
유형
- 경량 태그
- 변경되지 않는 브랜치와 유사
- 기록의 특정 커밋을 가리킴
- 주로 로컬 작업 공간에서 일시적으로 사용
- 주석이 달린 태그
- 체크섬 처리되며 중요한 커밋을 표시할 계획을 세울 때 자주 사용
- 메시지, 서명,날짜, 태거의 이름과 이메일을 추가 가능