git 실습 사이트 : https://learngitbranching.js.org/?locale=ko
로컬 저장소에서 git remote add origin [원격저장소 주소]
하면 로컬저장소가 원격저장소와 연결되고,
push하면 로컬에서 했던 commit들이 원격저장소로 올라간다.
git clone [주소] .
하면 현재 디렉토리에 바로 clone된다
Git은 커밋에 바뀐 것만 저장하는 것이 아닌 전체 코드를 저장한다.
바뀌지 않은 파일은 이전 파일의 링크만 저장한다.
추적 안됨 -> add하면 staged상태 -> commit을 통해 스냅샷을 남기고 unmodified상태 -> push를 통해 원격저장소로 올림.
브랜치는 물리적으로 길이 존재해서 그 길에 커밋을 올리는게 아니라 단순히 커밋을 가리키는 포인터이다.
따라서 분기를 만드려면 프로젝트를 통째로 복사해야하는 SVN과 달리 가볍고 빠르다.
브랜치간에 이동은 어떻게 가능할까? 그건 바로 HEAD라는 특수한 포인터에 의해 가능하다. HEAD는 브랜치 혹은 커밋을 가리킨다. (과거 커밋도 가리킬 수 있다)
협업자는 각각 브랜치를 만들고, 자신의 브랜치로 이동한 다음, 브랜치에 커밋을 올리고, 완료되면 브랜치를 합친다.
현재 코드 버전에 이름을 붙이는 것이 Tag
남의 원격저장소를 내 계정의 원격저장소로 복사
원격저장소에 있는 커밋 히스토리를 받아오는 것(새로고침)(코드엔 영향 없음)
커밋의 베이스를 똑 떼서 다른 곳으로 붙이는 것. 한 달 전의 코드를 기준으로 만들었던 브랜치를 마치 최신 코드를기준으로 만든 것처럼 이력을 조작하는 방식.
리베이스는 히스토리를 강제로 조작하기 때문에 혼자만 쓰는 브랜치에서 수행해야 한다.
리베이스한거는 강제 푸시를 해야 푸시가 된다.
현재 위치(HEAD) 아래에 있는 일련의 커밋들에대한 복사본을 만들겠다는 것을 간단히 줄인 말입니다.
git cherry-pick <commit1> <commit3> <commit5> ...
Git 체리-픽은 여러분이 원하는 커밋이 무엇인지 알때(각각의 해시값도) 아주 유용합니다.
체리-픽이 제공하는 간단함은 아주 매력적입니다.
하지만 원하는 커밋을 모르는 상황에는 어쩌죠? 고맙게도 git은 이런상황에 대한 대안이 있습니다.
우리는 이럴 때 인터렉티브 리베이스를 사용하면됩니다.
리베이스할 일련의 커밋들을 검토할 수 있는 가장 좋은 방법입니다.
인터렉티브 리베이스가 의미하는 뜻은 rebase 명령어를 사용할 때 -i 옵션을 같이 사용한다는 것입니다.
이 옵션을 추가하면, git은 리베이스의 목적지가 되는 곳 아래에 복사될 커밋들을 보여주는 UI를 띄울것 입니다. 각 커밋을 구분할 수 있는 각각의 해시들과 메시지도 보여줍니다.
"실제" git 에서는 UI창을 띄우는것 대신에 vim과 같은 텍스트 편집기에서 파일을 엽니다.
Git 태그는 특정 커밋들을 브랜치로 참조하듯이 영구적인 "milestone(이정표)"으로 표시합니다.
커밋 트리에서 태그가 훌륭한 "닻"역할을 하기 때문에, git에는 여러분이 가장 가까운 "닻(태그)"에 비해 상대적으로 어디에 위치해있는지 describe(묘사)해주는 명령어가 있습니다. 이 명령어는 git describe 입니다!
Git describe는 커밋 히스토리에서 앞 뒤로 여러 커밋을 이동하고 나서 커밋 트리에서 방향감각을 다시 찾는데 도움을 줍니다; 이런 상황은 git bisect(문제가 되는 커밋을 찾는 명령어라고 간단히 생각하자)를 하고 나서라던가 휴가를 다녀온 동료의 컴퓨터에 앉는경우가 있습니다.
git fetch는 두가지의 중요한 단계를 수행합니다. 사실 이 두 단계만을 진행합니다. 그것은 :
원격 저장소에는 있지만 로컬에는 없는 커밋들을 다운로드 받습니다. 그리고...
우리의 원격 브랜치가 가리키는곳을 업데이트합니다 (예를들어, o/main)
git fetch는 본질적으로 로컬에서 나타내는 원격 저장소의 상태를 실제 원격 저장소의 (지금)상태와 동기화합니다.
git fetch는 그러나, 여러분의 로컬 상태는 전혀 바꾸지 않습니다. 여러분의 main 브랜치도 업데이트하지 않고 파일 시스템의 모습이던 그 어떤것도 바꾸지 않습니다.
이것을 이해하는게 아주 중요한데, 왜냐하면 수 많은 개발자들이 git fetch를 하면 자신의 로컬 작업이 변경되어 원격 저장소의 모습을 반영해 업데이트 될것이라고 생각하기 때문입니다. 앞의 과정에 필요한 데이터를 다운로드는 하지만, 실제로 로컬 파일들이나 브랜치를 변경하지는 않습니다
사실 원격 저장소의 변경을 fetch하고 그이후에 merge하는 작업의 과정이 워낙 자주있는 일이라서 git은 이 두가지를 한번에 하는 명령을 제공합니다! 이 명령어는 git pull 입니다.
git pull은 본질적으로 git fetch후에 내려받은 브랜치를 병합하는 과정의 단축입니다.
git pull --rebase를 하면 fetch와 리베이스를 하는 작업의 줄임 명령어 입니다
커밋하면 커밋 객체가 생긴다. 커밋 객체에는 부모 커밋에 대한 참조와 실제 커밋을 구성하는 파일 객체가 들어있다.
브랜치는 논리적으로는 어떤 커밋과 그 조상들을 묶어서 뜻하지만, 사실은 단순히 커밋 객체 하나를 가리킬 뿐이다.
HEAD~<숫자n> : HEAD의 n번째 위쪽 조상 커밋
HEAD^<숫자n> : 병합 커밋처럼 부모가 둘 이상인 커밋에서 n번째 부모를 가리킨다.
git checkout은 크게 브랜치 전환, 작업 디렉토리의 파일 내용 복구 2가지 기능을 한다. git switch와 git restore로 분리된다.
rebase : HEAD와 대상 브랜치의 공통 조상을 찾는다. 공통 조상 이후에 생성한 커밋들을 대상 브랜치 뒤로 재배치한다.
원격 저장소에 푸시한 브랜치는 rebase하지 않는다.
스테이지 파일 : /git/index
git status 명령어는 working directory와 stage, HEAD 세가지 저장 공간의 차이를 비교해서 보여준다.(세 저장소의 내용이 같으면 아무 내용도 보여주지 않는다.)
git status로 Clean한 상태는 워킹트리와 스테이지, HEAD 커밋의 내용이 모두 똑같다는걸 의미한다.
파일을 생성하면 워킹트리에만 해당 파일이 존재한다.
add를 하면 워킹트리에 존재하는 파일을 stage에 추가한다. 실제로 .git/index에 해당 파일이 올라가며 index가 stage다.
.git/objects안에 존재하는 파일들은 Git 객체이다.
stage에 올라간 파일 객체는 blob가 된다. (binary large object)
add를 하면 해당 파일의 해시값과 동일한 이름을 가지는 blob객체가 생성되고 이는 .git/objects 파일에 저장된다. 그리고 스테이지의 내용은 .git/index에 기록된다.
커밋은 객체이고, 객체는 .git/objects에 저장된다.
커밋객체는 커밋 메시지와 트리객체로 구성되어 있다.
트리 객체의 체크섬(해시)은 파일의 내용을 기반으로 부여된다.
파일의 내용을 수정하면 워킹 트리의 체크섬만 다르다. modified는 스테이지와 워킹트리의 내용이 다른 파일을 일컫는 말이다.
이 때 add를 하면 워킹트리와 스테이지의 내용이 같아져 staged 상태라고 한다.
git에서 파일은 blob으로 관리되는데 blob은 파일 내용이 같으면 같은 체크섬을 가진다.
우리가 새로운 커밋을 여러 개 만들거나 같은 파일을 다른 폴더 등에 복사해서 여러 개 만들어도 파일의 내용이 같다면 하나의 blob으로 관리된다.
브랜치를 만들면 .git/refs/heads/test 텍스트 파일을 하나 생성하는 것이다.
checkout은 .git/HEAD 파일의 내용을 참조하는 브랜치로 변경하고, 워킹트리와 스테이지 내용을 해당 커밋의 내용으로 변경해 주는 것.
체크아웃은 '해당 브랜치로 HEAD를 이동시키고 스테이지와 워킹트리를 HEAD가 가르키는 커밋과 동일한 내용으로 변경하는 것'