git이란
- 프로젝트의 버전관리, 백업, 협업을 획기적으로 도와주는 도구
- 대표적인 플랫폼이 GitHub, Subversion 등이지만 플랫폼 없이도 사용 가능
local/remote repository
- 지역 저장소(local repository): 사용자가 직접 작업하는 컴퓨터
- 원격 저장소(remote repository): 백업/서버 컴퓨터 등
- origin: 기본 branch의 이름이 (주로) master인 것처럼, 주로 쓰이는 기본 remote의 이름
commit과 그 흐름
- commit: 저장소에 작업을 저장해서 '버전을 만드는' 행위
- 이전 버전과 비교하여 어떤 부분이 변경되었는지 손쉽게 확인할 수 있음
- reset: 이전 commit으로 돌아가고 그 이후 commit을 제거
- hard reset: 완전히 돌아감
- soft reset: 그 사이의 변경점을 staged 상태로 남겨
- revert: 이전 commit 상태를 복원하는 새로운 commit
- stash: 현재 작업 내용을 commit하지 않고 임시저장하고 감춰 둠 (물론 다시 불러올 수 있음)
- 만약 commit도 stash도 하지 않고 checkout 한다면, 현재 작업한 내용이 checkout한 branch에 영향을 주게 됨
- push: 저장소의 commit 내역을 다른 저장소로 보내 저장하는 행위 (보통 remote로)
- fetch: 원격 저장소에 올라온 commit 정보를 받아오는 행위
- pull: 다른 저장소의 commit 내역을 저장소로 받아와 적용시키는 행위. 말하자면 fetch+merge
- clone: 저장소를 다른 곳에 복제. 말하자면 init+pull
branch
- 모든 저장소는 기본적으로 main(※플랫폼마다 이름은 다를 수 있음) branch를 가지고 있음
- 목적에 따라 프로젝트를 현재 버전으로부터 분기
- HEAD: 현재 작업중인 branch
- checkout: 현재 branch에서 체크아웃 하고 다른 branch로 작업환경/HEAD 옮김
- merge: 현재 branch에 분기 branch를 병합
- 분기 branch가 더 이상 필요 없다면 수동으로 삭제해야 함 (merge 후 사라지지 않음)
- 남아있는 분기 branch에서도 계속 commit할 수 있음
- fast forward: 현재 branch에 특별한 변화가 없어, 분기 branch의 마지막 commit 상태로 '빨리감기' 되는 것. 별도의 commit이 이루어지지 않음
- "recursive" strategy/3-way: 현재 branch에도 변화가 생겼을 경우, ①branch가 분기한 commit ②현재 branch의 최신 commit ③분기 branch의 최신 commit 세 가지가 병합된 새로운 commit을 만듦
- conflict: 두 branch 모두 같은 파일의 같은 라인을 변경했을 경우 충돌이 생겨 자동으로 merge할 수 없게 되는 것. 사용자가 직접 문제를 해결해야 함
- 같은 파일이라도 다른 라인을 변경했다면 merge 자체는 문제 없이 일어남
rebase
- branch의 뿌리(분기점)를 옮기는 과정
- 현재 branch를 원 분기점으로 돌리며 그간의 commit 내역을 임시저장한 후, 대상 branch의 최신 commit에 분기점을 두고 commit을 되돌림
- 대상 branch에서 현재 branch로 merge되는 효과
- 말하자면
soft reset → (stash save) → branch 삭제 → 대상 branch로 checkout → branch 생성 → checkout → (stash apply) → commits
- 이 때 commit 내역을 선택적으로 남길 수 있음: history를 깔끔하게 할 수 있음
- 아무튼 commit을 새로 만드는 것이기 때문에 주의해야 함
이미 공개 저장소에 Push 한 커밋을 Rebase 하지 마라
_3번 레퍼런스 3.6 챕터
fork
- 어떤 remote를 clone하여 새로운 remote를 만듦
- (git의 기본 기능은 아닌 것 같음. GitHub에는 존재)
- GitHub에서는 fork와 clone을 구분하고 있지만 제가 봤을 땐 fork도 사실상 clone임
- 해당 프로젝트의 참여자가 아니라도 할 수 있다는 점에서 branch와 차이가 있음
- 원 저장소와 연결이 되어있어 서로 merge가 가능
issue
- (git의 기본 기능은 아닌 것 같음. GitHub에는 존재)
- 작업요청. 관련 내용들이 타임라인으로 그려지기 때문에 쉽게 트래킹할 수 있음 (물론 관련 내용작성을 규칙대로 해야 함)
- issue에 따라 분기한 branch
- issue에 따라 작업한 commit 등
자가 QnA
Q: origin, master, HEAD의 차이가 뭔가요?
A:
- origin: local의 기본 remote
- master: 저장소의 기본 branch
- HEAD: 현재 작업중인 branch(의 최신 commit)
Q: fetch가 왜 명령어로 존재하나요? 자동으로 이루어지면 안 되나요?
A: 개발환경이 언제나 online일 것이라는 보장도 없고, 개발환경이 커질수록 fetch 한 번에 오가는 데이터량도 많아질테니 트래픽 관련 이슈 측면에서도 이득이라고 합니다.
Q: fetch와 pull을 구분하는 이유가 뭘까요?
A: pull이 fetch와 merge를 동시에 해주는 편의기능인 것입니다. 다만 pull이 fetch를 포함하고 있다는 말은 달리 말하면 pull 하기 전에는 remote의 변경내역을 확인할 수 없다는 말이므로 협업시에는 fetch와 merge를 분리하는 편이 나을 수 있다는 말이 있네요.
Q: fetch 후에 merge를 해야한다는 게 무슨 말인가요?
A: commit은 버전 정보이고, merge는 저장소(작게는 branch)간에 commit 정보를 업데이트할 수 있는 방법이라고 생각해보세요.
쉽게 말해서 merge는 버전 업데이트이고, 3-way merge나 conflict merge에서처럼 아예 새로운 commit(진짜 '병합')이 필요한 경우가 아니라면 그냥 최신 버전으로 '동기화'되는 것이죠.
Q: 그럼 fetch 후 따로 merge 하지 않는 방법도 있나요?
A: 네, 그렇게 되면 fetch한 내용이 FETCH_HEAD라는 임시 branch에 남아있게 됩니다.
하지만 언젠가는 merge 하든지 branch를 나누든지 해야겠죠?
Q: merge하지 않고 있다가 결국 branch를 나누기로 결정했으면 어떻게 하면 될까요?
A: branch 분기 → 원 branch hard reset → 원 branch pull
같은 방식으로 처리하시면 될 것 같습니다.
적고 보니 전부 fetch 관련이군요
참고한곳