
Git을 사용하면 소스 코드의 수정 내역에 쉽게 접근할 수 있습니다.
가장 중요한 부분은 버전이 어떻게 변경되었고 누가 변경했는지 확인할 수 있습니다.
또한 Git 은 협업하는데에 가장 중요합니다.
Git에서 변경사항을 저장하고 기록하기 위해서는 세 단계를 거칩니다.
🧇 Working Directory (작업 디렉토리)
파일을 수정하는 공간입니다. 즉 여러분들이 코드로 작업을 하고 원하는 기능을 만드는 공간입니다.
🧇 Staging Area (스테이징 영역 또는 인덱스)
변경된 파일 중 일부를 선택하여 저장할 목록에 추가하는 공간입니다.
git add 명령을 통해 변경사항을 스테이징 영역에 추가합니다.
git add text.html
git add chan.css
git add .
🧇 Repository (저장소)
스테이징 영역에 있는 변경사항을 커밋하여 영구적으로 저장하는 공간입니다.
git commit 명령을 통해 스테이징 영역의 변경사항을 저장소에 기록합니다.
git commit -m "작업 완료"
git commit -m "로그인 페이지 구현"

왜 굳이 스테이징 영역이 필요할까?
그냥 작업하다가 바로 commit 을 사용하면 되는 거 아닌가??
이유는 다음과 같습니다.
🥞 효과적인 변경 관리
인덱스를 통해 변경사항을 선별적으로 스테이징할 수 있어, 모든 변경사항이 아닌 선택된 변경사항만을 다음 커밋으로 이동시킬 수 있습니다.
text.html, text2.html 을 스테이징 영역에 올리고 계속 작업을 하던 중 text.html 만 commit 하고 저장소로 올려야 할 때 text.html 만 commit 할 수 있습니다.
🥞 커밋 이전의 수정 및 검토
변경사항을 스테이징 영역에서 확인하고 검토할 수 있기 때문에, 커밋 전에 수정하거나 확인할 수 있습니다.
즉 commit 하기 전에 내가 재대로 오류 없는 코드를 만들었는지 검토할 수 있습니다.
Git 저장소에는 원격 및 로컬의 두 가지 유형이 있습니다.
원격 저장소는 다른 팀원들도 모두 이용할 수 있는 공통 저장소입니다.
하지만 로컬 저장소는 나만 이용할 수 있고 다른 팀원은 접근 가능하지 못하는 저장소를 의미합니다.
git 에는 정말 다양한 명령어가 있습니다.
이 중에서 중요하다고 생각하는 부분을 설명하겠습니다.
git merge 명령은 서로 다른 브랜치의 변경 내용을 하나로 합치는 데 사용됩니다.
일반적으로 현재 브랜치에서 다른 브랜치를 병합할 때 사용합니다.
두 브랜치를 병합하는 git merge는 기본적으로 두 가지 시나리오로 나뉩니다.
Fast-forward 병합은 두 브랜치가 분기되었을 때, 두 브랜치 중 하나가 다른 브랜치의 최신 커밋을 가지고 있지 않아서 단순히 브랜치를 앞으로 이동시키는 경우입니다.
A---B---C (master)
\
D---E (feature)
//master 브랜치로 이동
git checkout master
// feature 브랜치를 master 브랜치에 병합
git merge feature
A---B---C---D---E (master, feature)
Non-fast-forward 병합은 두 브랜치가 각자 독립적으로 변경되었을 때, 두 브랜치의 변경 내용을 하나로 합치는 경우입니다. 이 경우 새로운 병합 커밋이 생성됩니다
A---B---C (master)
\
D---E (feature)
//master 브랜치로 이동
git checkout master
//feature 브랜치를 master 브랜치에 병합
git merge --no-ff feature
A---B---C-------F (master)
\ /
D---E (feature)
다른 브랜치로부터 가져온 커밋을 현재 브랜치의 끝에 추가하는 등의 작업에 사용됩니다.
이러한 rebase 는 주로 나만의 branch 를 작업할 때 사용합니다. 이게 무슨뜻이냐면
만약 내가 login branch 를 작업하던 도중 login branch 에 button 부분을 수정하고 싶다면
login button branch 를 만든후 작업을 하다가 login branch 로 돌아와서 rebase 를 해주는 식으로 사용합니다.
또한 rebase 를 쓰는 가장 큰 이유는 Git History 가 깔끔해 집니다.
즉 rebase 는 나혼자 관리하는 브랜치가 여러개 있을때 나의 브랜치로 합치는 용도 입니다.
하지만 git 공식 사이트에서도 나와 있듯이 일반적인 해답을 굳이 드리자면 로컬 브랜치에서 작업할 때는 히스토리를 정리하기 위해서 Rebase 할 수도 있지만, 리모트 등 어딘가에 Push로 내보낸 커밋에 대해서는 절대 Rebase 하지 말아야 합니다.
A---B---C (master)
\
D---E (chan)
// master 브랜치로 이동
git checkout master
// chan 브랜치를 master 브랜치에 rebase
git rebase chan
A---B---C---D---E (master)
git cherry-pick은 제목과 마찬가지로 필요한 commit만 골라서 가져오는 명령어이다.
쉽게 말해 다른 브랜치에 있는 commit들 중에서 원하는, 필요한 commit을 지금 내 브랜치에 가져와 commit을 하는 것이다.
그럼 cherry-pick 은 어떨 때 사용할까?
🍰 팀으로 협업할 때
팀으로 협업을 진행하고 있을때, 다른 동료가 만들고 있는 기능이 필요한 순간이 있다.
만약 동료가 해당 기능을 이미 다 만들어 놨고, 동료가 맡은 모든 작업을 merge 할 때까지 시간이 걸린다면 동료가 만들었다는 기능이 들어있는 commit만 골라서 가져올 때 사용한다.
🍰 버그를 수정할 때
새로운 기능을 개발하는 동안 기존에 있던 기능에서 버그가 발견되었을 때, 개발자는 이 버그를 패치하기위해 명시적 커밋을 만들고 해당 커밋만 골라서 master 브랜치에 배포할 수 있다.
🍰 반영되지 않은 손실된 커밋 복원
실수로 pull request를 merge하기 전에 닫아버렸을 때, cherry-pick을 사용해 해당 commit을 가져옴으로써 살릴 수 있다.
A---B---C (current_branch)
\
D---E (other_branch)
//current_branch로 이동
git checkout current_branch
// 원하는 commit 을 가져오기
git cherry-pick E
A---B---C---E' (current_branch)
\
D---E (other_branch)
git rebase 와 git cherry-pick 의 다른점?
git rebase : 주로 브랜치를 정리하고 커밋 히스토리를 깔끔하게 유지하기 위해 사용됩니다. 기존의 커밋 히스토리를 변경하고자 할 때 주로 활용됩니다.git cherry-pick : 특정 커밋이나 여러 커밋을 다른 브랜치로 가져오고자 할 때 사용됩니다. 다른 브랜치에서 특정 기능이나 수정을 현재 브랜치로 가져오는 데 유용합니다.git revert 명령은 특정 커밋의 변경사항을 되돌리는데 사용됩니다.
예를 들어 현재 브랜치에 A , B , C 라는 세 개의 commit 이 있다고 가정합시다.
A --- B --- C
이때 C 라는 commit 의 작업물이 마음에 들지 않아서 되돌리고 싶다고 생각합니다.
그럴 때 revert 명령어를 사용합니다.
git revert C
// 밑은 revert 하고 난 뒤 작업 history
A --- B --- C --- D
// D <-- C 작업을 삭제한 commit
이제 D 커밋은 C 커밋의 변경사항을 취소한 것을 나타내고, 변경 이력에 새로운 커밋으로 기록되었습니다.
즉, revert 명령어는 이전 커밋의 반대 효과를 가진 새로운 커밋을 생성합니다.
git revert를 사용하면 변경사항을 되돌리면서도 히스토리에 새로운 커밋이 등록됩니다.
git commit --amend 명령어는 최근의 커밋을 수정하고자 할 때 사용됩니다.
이 명령어는 세 가지 주요 용도를 가지고 있습니다
🍜 커밋 메시지 수정
🍜 파일 추가 / 변경 사항 추가
🍜 커밋 날짜 변경
git commit --amend -m "an updated commit message”
이렇게 하면 명령창을 띄우지 않아도 바로 바꿀 수 있습니다.
git add <file>
git commit --amend
이미 커밋한 후에 추가 파일이나 변경된 내용이 있을때 위에 코드처럼 사용하면
최근 커밋에 추가할 수 있습니다.
# 가장 최근의 커밋을 수정하여 변경사항 추가
git add .
# 이전 커밋을 수정하고 변경사항을 추가, 커밋 메시지 변경 없음 (--no-edit)
# --date 옵션을 사용하여 새로운 날짜로 지정
git commit --amend --no-edit --date="2022-01-01T12:00:00"
어디에서 호스팅을 하든 다른 팀 구성원과 변경 사항을 공유하려면 로컬 저장소를 원격 저장소와 자주 동기화해야 합니다.
🍞 git push
변경 사항을 원격 저장소로 보내기 위해 사용됩니다.
이렇게 하면 원격 저장소가 업데이트 되고 로컬 저장소와 동기화 됩니다.
🍞 git pull
누군가 원격 저장소에 변경 사항을 푸시할 때마다 그 원격 저장소에서 가져온 나의 로컬 저장소가 변경된 원격 저장소가 아닌 옛날 구식 원격 저장소 이기 때문에 변경해 주어야 합니다.
🍞 git fetch
fetch는 원격저장소에서 커밋된 코드를 임시 브랜치로 다 내려받습니다.
그러나 내려받은후 현재 브랜치와 자동 병합하지 않고, 그렇기 때문에 워킹디렉터리도 변화가 없습니다.
그래서 merge 명령어를 이용해서 수동 병합해야합니다.
'git pull'은 원격 저장소의 업데이트를 가져오는 동시에 현재 작업하는 로컬 브랜치로 병합(merge)합니다. 즉, 'git pull'은 현재 브랜치와 원격 저장소를 동기화하여 최신 변경 사항을 즉시 반영하는 명령어입니다.
반면에 'git fetch'는 원격 저장소의 업데이트를 확인하고 로컬 저장소에 업데이트된 내용을 다운로드합니다. 하지만 이 내용을 현재 작업 중인 브랜치에 병합하지 않습니다. 따라서 'git fetch' 명령어를 실행한 이후에는 'git merge'나 'git rebase' 명령어를 사용하여 로컬 브랜치에 업데이트를 병합해야 합니다.
쉽게 말하면, 'git pull'은 내용을 다운로드하고 병합까지 수행하는 반면, 'git fetch'는 내용만 다운로드하고 병합은 따로 수행해야 한다는 차이가 있습니다.