Notion 에서 보기
소프트웨어 형상 관리 ( SCM )
소프트웨어를 개발에는 많은 자료들이 작성된다. 소스 코드, 문서, 버그 리포트 등 다양한 결과물이 기록으로 남는다. 이 기록들은 일시적이지 않고 계속 변경된다. 특히, 가장 중요한 소스코드는 한 사람이 아니라 여러사람이 변경할 경우 코드의 일관성이 깨진다. 소프트웨어의 변경사항을 체계적으로 추적하고 통제하는 것이 SCM이다.
SCM의 요소에는 여러가지가 있다. 그 중 하나가 VCS이다.
VCS ( Version Control System )
소프트웨어 개발 시, 산출되는 문서의 변경사항에 Version 이라는 표지를 붙여 변경이력을 관리하는 시스템이다. 버전으로 관리하기 때문에 버전 관리 시스템이라고 불린다.
버전 관리 시스템은 모든 변경이력을 저장하므로 과거부터 현재까지 모든 변경이력을 볼 수 있다. VCS는 구조에 따라 2가지로 나뉜다.
- 중앙집중식 :CVS, subversion (SVN)
- 분산식 : git, mercurial
CVCS ( 중앙집중식 버전 관리 시스템 )
- 중심이 되는 메인 트리가 존재한다. 즉, 중앙 저장소 날라가면 다 날라간다.
- 중요한 단위로만 Branching한다. 충돌 가능성이 크기 때문이다.
- 모든 작업에 네트워크 사용해서 느리다.
DVCS ( 분산 버전 관리 시스템)
- 중심 저장소가 없다.
- 의존하고 있는 저장소가 없으므로, Branching이 자우룝다.
- 업로드에만 네트워크 사용.
대표적인 DVCS 오픈소스가 Git 이다. 중심이 없으므로, 여러명이 개발하는 프로젝트의 소스코드 관리에 용이하다.
Git의 특징
- Branch & Merge : Branch로 코드를 중간에 분기해, 독립성 유지한채로 개발 할 수 있다. 분기된 코드는 Merge를 통해 합칠 수 있다. 병렬 개발 가능
- 빠르다: 대부분 Local작업이므로 빠르다.
- Commit id : Hash값으로 ‘버전’을 나타낸다. Hash값이기 때문에 온라인, 오프라인 상관없이 커밋 가능하다. 즉, 서버에 접속해서 최신 Commit 번호를 확인하는 절차가 불필요하다. 오프라인에서 커밋이 되었다면, 나중에 서버에 업로드 될 때 한꺼번에 업로드 된다. 단, 부모Hash 값도 같이 저장해 Commit id만으로 순서를 기억한다. 오프라인 개발 가능 (Hash는 SHA-1 사용)
( 비둘기집 원리에 의해 Hash는 충돌이 존재하지만, 그 확률은 엄청나게 낮다. 2017년, 구글에 의하면 SHA-1은 더이상 안전하지 않다. ) - 원격저장소가 삭제되어도 로컬 저장소는 삭제되지 않는다.
- 고전 VCS와 다르게 스냅샷 기반으로 작동된다. 파일이 수정되었다면 수정된 부분 포함 전체 파일을 저장한다. 그래서 속도가 빠르다.
( 고전적 VCS는 스냅샷 기반이 아닌, 델타 방식을 사용한다. 파일이 수정되었다면, 수정된 파일 전체가 아닌, 수정된 부분만 저장한다. 그래서, 스냅샷 기반보다 느리다. 스냅샷 비교로 델타를 얻을 수 있다. )
( 만약 수정된 부분만 따로 저장한다면, 수정된 파일을 얻기 위해서는 원본파일에 수정된 부분을 적용해야 한다. 즉, 추가 작업이 필요해서 스냅샷 보다 느리다. 스냅샷은 파일 자체를 저장하므로 바로 불러오기만 하면 된다.)
Git 상태
- Working Directory( = Working Tree ): 작업중인 Directory. Directory라는 의미보다 Tree라고 쓰는것이 더 정확하다. 특정 Directory를 의미하는 것이 아니라, 그 아래에 있는 모든 폴더, 파일을 포함하기 떄문이다.
- Staging Area: 커밋할 파일(변경한 파일)에 대한 정보가 저장된다. 즉, 커밋할 준비가 된 파일이 이 영역에 속한다.
- Repository: 커밋된 결과가 저장되는 저장소
Github
깃허브는 Git을 웹 호스팅 서비스로 제공한다. 텍스트기반 Git과는 다르게, GUI 도구를 제공한다.
GIT 용어
Repository
파일을 저장하는 공간. Local과 Remote로 나뉜다. 이 때 Remote(원격) 저장소는 같은 로컬 시스템에 존재할 수 있다. 원격저장소는 주로 인터넷이나 네트워크 어딘가에 있다.
Working Tree
Git 커밋 기록에 따르면, Working Directory대신 Working Tree라고 불러야 한다.Working Directory는 Current Directory와 헷갈릴수 있기 때문이다.
Use "working tree" instead of "working directory" for git status · git/git@2a0e6cd · GitHub
Clone
원격 저장소의 모든 데이터를 로컬로 복사해 로컬 저장소를 만든다. 복사와 동시에 로컬저장소와 원격 저장소는 연결된다.
Fork
다른 사람의 저장소를 나의 저장소로 그대로 복사한다. 이 때, 복사된 저장소는 원본 저장소와 연결되어 있다. 그래서, 원본 저장소의 변경점을 반영할 수 있다.
Add
Modified 상태의 파일을 Staged 상태로 만든다. 작업한 파일을 Staged Area 에 올리는 명령이다.
git add 파일1, 파일2 // 특정 파일만 Add. 디렉토리 경로도 가능하다.
git add . // 현재 디렉토리의 Modified 상태인 모든 파일 Add. ( 하위 디렉토리 포함 )
git add -A // Working Tree의 Modified 상태인 모든 파일 Add
이 때, Add해서 Staged 상태로 바꾼 파일을 수정하면, 파일은 동시에 Staged면서 Unstaged이다.
Commit
Staged 상태의 파일들을 커밋한다. 커밋은 데이터를 로컬 데이터베이스에 저장하는 행위이다. 즉, 깃 저장소에 있는 모든 파일들은 Commited 상태이다. Commit 시점은 마지막으로 Git Add를 했을 때의 시점이다.
git commit -m "커밋 메시지"
Push
로컬 저장소의 현재 브랜치를 원격 저장소의 특정 브랜치에 반영한다. 주로 Commit 내용을 원격 저장소에 반영할 때 사용한다.
git push <원격 저장소 이름> <브랜치 이름>
Pull
원격 저장소 브랜치에서 데이터를 가져오고 자동으로 로컬 브랜치와 Merge한다.
git pull <원격 저장소 이름> <브랜치 이름>
Fetch
Clone한 이후에, 원격 저장소에서 수정된 내용을 모두 로컬 저장소에 반영한다. Pull과는 다르게 Merge하지 않는다.
git fetch <원격 저장소 이름>
Head
리비전(revision)은 특정 시간 혹은 브랜치의 상태를 나타낸다. 위에서 설명한 Commit ID와 동일한 의미이다.
Head는 저장소의 현재 브랜치의 마지막 커밋에 대한 포인터이다.
Branch
코드를 중간에 분기한 결과를 의미한다. 기술적으로 이야기하면, 커밋 사이를 이동할 수 있는 포인터이다. 브랜치를 바꾼다는 것은 HEAD가 가리키는 브랜치를 바꾸는 것이다.
Merge
다른 브랜치의 내용을 현재 브랜치에 합치는 행동이다.
- Fast Forward Merge
다른 브랜치가 현재 브랜치에 기반하였다면, Merge 과정없이 합쳐진다.
- 3-Way Merge
현재 브랜치의 커밋이 다른 브랜치의 조상이 아니면, 각 브랜치가 가르키는 커밋 2개와, 공통 조상 커밋 1개를 이용해서 Merge 한다.
Checkout
저장소의 브랜치를 다른 브랜치로 변경한다. 이 때, 현재 브랜치는 커밋이 되어있어야 한다. 커밋 하기 싫으면 Stash 이용한다.
git branch <브랜치 이름> // 브랜치 생성
git merge <merge할 브랜치 이름>
git checkout <브랜치 이름>
git checkout -b <브랜치 이름> //해당 이름의 branch생성 후 이동
Stash
현재 저장소에서 커밋하지 않은 변경사항을 저장하는 장소. Modified 이면서 Tracked 상태인 파일과 Staging Area의 파일들을 저장하는 장소이다. 스택형식으로 저장한다. 그래서 브랜치가 달라져도 다시 꺼내서 적용할 수 있다.
git stash //임시 저장
git stash pop //마지막으로 임시저장한 작업 가져오기
git stash apply //git stash로 저장했던 작업 가져오기
git stash drop // stash 제거하기(apply와 같이 사용)
Rebase
브랜치를 합치는 방법 중 하나로 브랜치의 Base를 재설정한다. 커밋이 깔끔해지지만, 공개 저장소에 Push한 커밋을 Rebase 하면 안 된다. Rebase는 새로운 커밋을 만드는 것이기 때문에 코드가 엉망이 될 수 있다.
Merge를 했을 때와 비교해서 결과는 같지만, 커밋 히스토리는 다르다. Rebase는 브랜치의 커밋기록을 순서대로 다른 브랜치에 적용시키면서 합친다. Merge는 브랜치의 최종결과만 가지고 합친다.
Reset
현재 브랜치의 커밋을 취소한다. HEAD 브랜치 이동, Index 업데이트, Working Tree 업데이트, 총 3단계로 이루어져 있다.
옵션에 따라 단계를 중간에 멈출 수 있다.
git reset --hard <commitid> //head가 <commitid>을 가리키게 하고 변경사항도 없는 상황으로 만듬
// --hard 옵션이 있으면 3단계 전부 수행.
Revert
원격 저장소에 PUSH 까지 했을 때, 커밋을 되돌릴 수 있다.
git revert <커밋을 되돌리는 commitid>
Amend
마지막 커밋의 내용을 덮어씌운다. 커밋 메시지를 수정하거나, 커맷 니용을 바꾼다.
git commit --amend
GIT 기타 명령
유저 등록
# Author identity unknown Please tell me who you are
git config --global user.email "해당email"
git config --global user.name "해당name"
//등록 후 확인
git config user.email
git config user.name
Auto merge가 안되었을 때.
몇몇 파일이 Merge가 안되어있음.
# Pull is not possible because you have unmerged files
git status
git commit -am'커밋메세지'
Master 브랜치에 내용 강제 덮어쓰기
git checkout <특정 브랜치명>
git branch master <> -f //-f force의 단축
git checkout master
git push origin master -f
기타 오류
untracked 파일이 있을 때.
# Please move or remove them vefor you can merge
git add -A
git stash
# 위에 두줄 혹은
git stash --all
git pull
원격저장소 기본 브랜치 설정
# The current branch master has no upstream branch.
git push --set-upstream <원격 저장소 이름> <브랜치 이름>
참고
http://dogfeet.github.io/articles/2012/git-delta.html
https://git-scm.com/book/en/v2
https://ssafycsstudy.notion.site/Git-01bce8b99c1d411f8a67e04f7caf2c5d