
브랜치를 합치는 방법은 여러가지가 있다.
3-Way merge
저번 포스팅에서 했던 것 처럼
브랜치에 각각 신규 commit이 1회 이상 있는 경우
merge 명령을 내리면 두 브랜치의 코드를 합쳐서 새로운 commit을 자동으로 생성해주는데
이걸 3-way merge라고 부른다
이게 merge의 기본 동작 방식이다
A.
내 브랜치 (Local) : commit 2-2
상대 브랜치 (Remote/Other) : commit 3
두 브랜치가 갈라져 나온 공통 부모 (Base) : commit 2
이렇게 세 지점의 상태를 동시에 비교해서 합치기 때문에 3-way merge라고 부른다.
fast-forward merge
가끔은 새로운 브랜치에만 commit이 있고
기준이 되는 브랜치에는 신규 commit이 없는 경우도 있다.
이 경우 merge 하게 되면 fast-forward merge 되었다고 알려준다
fast-forward merge가 뭐냐면
딱히 합칠게 없어서 그냥 신규 브랜치보고
지금부터 니 이름은 main 브랜치여 하는 것과 같다.
그래도 결과는 같지 않을까여
그래서 기준이 되는 브랜치(main)에 신규 commit이 없으면 자동으로 fast-forward merge가 발동된다
물론 싫으면 git merge--no-ff 브랜치명 해서 강제로 3-way merge 할 수도 있다.
브랜치를 삭제하려면
3-way, fast-forward 아무렇게나 merge해도
브랜치를 merge하고 나면 브랜치가 자동으로 삭제되진 않는다.
git branch -d 브랜치이름
git branch -D 브랜치이름
둘중 하나 사용하면 이제 필요없는 브랜치를 삭제할 수 있다.
병합이 완료된 브랜치 삭제시엔 -d 이것만 해도 되는데
병합하지 않은 브랜치 삭제시엔 -D 이거 해야함
rebase and merge
브랜치를 rebase하고 나서 merge하는 짓거리도 가능하다
rebase란

브랜치의 시작점을 다른 commit으로 옮겨주는 행위이다.
1. rebase를 이용해서 신규 브랜치의 시작점을 main 브랜치 최근 commit으로 옮긴 다음에
2. fast-forward merge하는 것이다.
이따구로 하는 이유는
1. 3-way merge 말고 강제로 fast-forward하고 싶을 때
2. 브랜치 그딴거 필요 없이도 코드 잘짜는 것 처럼 보이고 싶을 때
3. commit 내역을 한 줄로 계속 이어서 남기고 싶을 때
그러고 싶으면 일반 3-way merge 대신 rebase & merge해도 된다.
그래서 실제로 rebase & merge 하고 싶으면
1. 새로운 브랜치로 먼저 이동해서
2. git rebase main 하면 된다
3. 그럼 브랜치가 main 브랜치 끝으로 이동하는데 그걸 fast-forward merge하면 된다.
git switch 새로운 브랜치
git rebase main
git switch main
git merge 새로운 브랜치
정리해보면
1. rebase는 내가 작업하고 있는 브랜치의 최신 커밋을 main에 붙인다.
2. 거기서 merge 하니깐 fast-forward가 되는 원리
3. ㅇㅈ?
물론 main 말고 다른 브랜치끼리도 가능하다.
물론 단점도 있는데
브랜치끼리 차이가 너무 많은 경우 rebase하면 충돌이 많이 발생할 수 잇는데 그거 해결하기 귀찮다.
그래서 많은 코드들이 들어오는 main 보다는 혼자 쓰는 feature branch에 rebase해서 쓰는게 나을 수 있다.
squash and merge 하는 경우도 있음
대충 모든 브랜치를 3-way merge해버리면 나중에 대참사가 일어날 수 있다.
왜냐면
1. 3-way-merge 된 것들은 매우 복잡해보임
2. main 브랜치에서 git log 출력해보면 3-way merge된 브랜치들의 commit 내역도 다같이 출력되어서 더러워짐
그러기 싫으면 rebase도 있지만 squash도 있다.
그거 쓰면 새로운 브랜치에 있던 commit을 연결해주는게 아니라 똑 떼와서 main 브랜치에 붙여주기 때문에 1번 2번 걱정을 할 필요가 없다.
squash and merge는 3-way merge 처럼 선으로 이어주지 않고
새 브랜치에 있던 코드 변경사항들이 main 브랜치로 텔레포트한다.
그럼 이제 main 브랜치의 git log 출력해볼 때
merge 완료된 브랜치의 commit 내역 같은 것은 출력되지 않는다.
이게 왜 좋은지는 체감해봐야 알기 때문에 3-way merge 많이 해보시길 ㅊㅊ
git switch main
git merge --squash 브랜치명
git commit -m '메세지'
squash 하는 법은 그냥 --squash 옵션을 추가하면 끝이다
브랜치에서 만들어 놨던 많은 commit을 다 합쳐서
하나의 commit으로 main 브랜치에 생성해준다.
A. 초보땐 대충 해도 ㄱㅊ
나중에 코딩 노예로 취직하면 브랜치마다 merge 방법 가이드라인이 있다
없으면 퇴사 ㄱㄱ
commit만 주구장창하는 사람들이 있는데
git은 버전관리시스템이기 때문에
언제든지 이전 commit으로 되돌아가거나
문제가 되는 commit 내역을 취소하거나 그럴 수 있다.
git restore / git revert / git reset 명령어써서 파일 복구하는 법을 알아보자
각각 파일하나 복구, commit 복구, 시간되돌리기가 가능하다.
commit id를 이용해야 "그 commit으로 되돌려주세요~" 같은 명령들이 가능하다
파일 하나를 되돌리려면 git restore
파일하나가 잘못되었을 경우 Ctrl + z 여러번 눌러도 되겠지만
수정사항이 너무 많다면 명령어 하나로 처리할 수 있다.
git restore 파일명
이러면 최근 commit된 상태로 현재 파일의 수정내역을 되돌릴 수 있다.
git restore --source 커밋아이디 파일명
이러면 입력한 파일이 특정 커밋아이디 시점으로 복구된다.
git restore --staged 파일명
이건 복구랑은 상관없지만 이러면 특정 파일은 staging 취소할 수 있다.
commit을 되돌리려면 git revert
코드 열심히 짜다가
갑자기 과거 commit 하나가 문제를 일으키면 어쩌져?
commit하나를 취소하고 싶으면 git revert 사용하면 된다.
실은 없애버리는건 아니고 commit 하나를 취소한 commit을 하나 생성해준다.
git revert 커밋아이디
이거 입력하면 그 커밋아이디에서 일어난 일만 취소해준다.
실행하면 아마 에디터가 뜰 텐데 맘대로 커밋메세지 수정하고 닫으면 끝
아무튼 에디터 닫고나면 새로운 커밋이 생성되고 그 파일만 뿅 삭제가 될 것이다.
(그 커밋id 이후에 했던 파일이나 커밋들은 영향없이 유지됨)
(참고)
그냥 전부 시간을 되돌리고 싶으면 git reset
지옥같은 개발에 대해 아무것도 모르던 어린 시절로 되돌아가고 싶으신가여?
현실에선 안되지만 git에서 ㄱㄴ함니다
git reset 명령어 사용하면 특정 commit 시절로 아예 모든걸 되돌릴 수 있다
git reset --hard 커밋아이디
입력하면 그 커밋이 생성될 때로 시간을 되돌려준다
작업폴더 내의 파일도 그 시절로 돌아간다
commit2로 reset --hard 해버리면
commit2 이후의 미래 기억을 모두 잃는다
지금 기억을 다 포기하고 인생을 7살로 리셋해준다면 돌아갈것인가?
인생 망한놈들은 맘대로 갈 수 있겠지만
어느정도 궤도에 인생을 올려둔 사람들이라면 돌아가기 힘들 것이다
마찬가지로 git reset은 그냥 프로젝트 망하면 쓰거나
아니면 짧은 거리를 돌아갈 때 쓰도록 하자
(참고)
참고 : reset시 옵션 설정 가능
git reset 뒤에 hard / soft/ mixed 설정을 넣을 수 있는데
git reset --hard d874b2b
이러면 a,b 파일은 남아있고 c 파일이 삭제된다
git reset --soft d874b2b
이러면 ac 파일은 남아있고 b 파일은 staging area에 남아있다
이제 commit하거나 그럴 수 있다
git reset --mixed d874b2b
이러면 a,c 파일은 남아있고 b 파일은 staging 되지 않은 상태가 된다
이제 git add하고 commit하거나 그럴 수 있다
결론은 reset 하면서 파일을 아예지워버리는게 아니라
검토하고 다시 commit하고 싶으면 --soft / --mixed 사용
실은 git reset 어쩌구 하면 mixed가 기본으로 발동됨
github 같은 원격 레포지토리에 대해 알아보자
repository가 뭐냐면
git이라는 친구가 파일버전을 저장해두는 곳이다
로컬 작업폴더엔 .git 폴더가 있는데 그게 repository임
한국말로는 저장소
실제로 개발할 땐 온라인 repository를 많이 사용한다
내가 컴퓨터에 만들어놓은 repository를 온라인으로 저장해두는 거다
github 가입하고 repository 만들기
(생략)
구글링 잘해보면 나온다
로컬에서 github로 옮기기
원격저장소는 내 컴퓨터에서 만들어둔 저장소를 백업하기 위함이다
그래서 내 컴퓨터에서 만든 로컬저장소를 원격저장소로 백업해보자
일단 새로운 작업폴더에다가 git init해서 저장소를 하나 만들어보자
작업폴더를 하나 만든 다음 터미널에서 열어서 git init 한다
이게 로컬 저장소 생성하는 짓
github.com은 이제 기본 브랜치 이름을 master가 아니라 main으로 사용하라고 강요한다
그래서 우리 로컬 작업 폴더에 있는 기본 브랜치 이름도 main으로 변경해준다
git branch -M main
입력하면 기본 브랜치 이름이 변경된다
안해도 될 수 있음
그 뒤 커밋 몇번 해보자
로컬 저장소 -> 원격 저장소
이렇게 올리고 싶음 터미널 열어서
git push -u 원격저장소주소 main
하면 된다
원격저장소 주소 길게 입력하는게 귀찮으면
그니깐 깃허브 주소 이거 매일 입력하기 귀찮으면 어떻게 하냐는 거냐
그럴 땐 그 주소를 변수에 저장해서 사용할 수 있다
변수에 저장하려면
터미널에 git remote add 변수명 저장소주소
입력하면 된다
git remote add origin https:~~~~~~~.git
이렇게 입력하면 어쩌구 주소가 필요할 때마다 origin이라는 변수명을 쓸 수 있다.
원격저장소에 있던거 그대로 내려받기
돈벌어서 맥북을 샀는데 그 컴퓨터에서 갑자기 개발을 시작하고 싶다면
귀찮게 소스코드 공유할 필요없이
원격저장소에 있던 내용을 그대로 내려받아서 시작하면 편리하다
git clone https:원격저장소주소
저장소에 올리지 않는 파일들은 .gitignore
원격저장소를 효율적으로 쓰고 싶으면 쓸데없는 파일은 commit해서 올리지 않는게 좋슴미다
.gitignore 파일을 하나 만들면 저장소에 올리지 않을 파일들을 쉽게 명시 ㄱㄴ
거기있는 파일들은 git add. 해도 스테이징 되지 않아서 편리하다
원격 저장소의 장점은 남들과 협업할 수 있다는 것이다
어려운건 아니고 개발자 10명이서 각각 작업한 내용을 원격저장소에 올리면 그게 협업임
소스코드 다운받기
다운받는 법은 github.com 가서 다운받아도 되고
git clone 원격저장소주소
새로운 작업폴더에서 이거 입력해도 된다
그럼 원격저장소에 있던 내용을 그대로 복제해줌
참고로 필요할 땐 특정 브랜치 1개만 clone 해올 수 있음
git clone -b [브랜치명] --single-branch [저장소_URL]
팀원이 commit 하려는데 문제가 생김
git push는 맘대로 할 수 있는게 아님
갑자기 다른 놈이 만든 파일이 원격저장소에 생기면 git push 못한다
다른 곳에서 일하던 팀원도 방금 만든 파일을 원격저장소에 업로드 하고 싶어진거다
그래서 hi라는 파일을 commit하고 push했다
그 뒤 내가 hello 라는 파일을 받아서 올리려고 하니 에러가 난다
이유는?
원격 vs 로컬 내용이 다르다면 로컬 저장소에서 git push가 안된다
그런 상황에서 대충 push해버리면 코드가 꼬이기 때문에 미리 예방해주는 것이다
git pull 이용하면 현재 원격 저장소 내용 가져올 수 있음
git pull 원격저장소 주소
이러면 원격저장소에 있는 모든 브랜치 내용을 가져와서 로컬에 합치라는 소리다
이걸 해주면 로컬에 있는 코드가 원격 저장소를 반영한 최신상태가 되기때문에 git push가 가능해진다
결론은 변동사항이 생겼다면 git pull하고 git push하면 됩니다
(참고)
참고사항 : git pull 명령어는 git fetch + git merge 축약어임
git pull하면 자동으로 git fetch + merge 해준다
git fetch는 원격저장소에 있는 commit 중에 로컬에 없는 신규 commit을 가져오라는 뜻이고
git merge는 그걸 merge하라는 뜻이다
그래서 git pull 할 때 팀원 2명이서 같은 파일을 건드리고 있을 경우 merge conflict가 날 수 있다.
conflict는 알아서 해결하자 앞에서 설명함
오늘의 결론 : 협업시 push하기 전에 pull ㅈㄴ게 하자
신기능을 만들고 싶으면 main 브랜치에 짜지말고 다른 브랜치를 만들어서 거기에 개발하는 것이 안전하고 좋다고 했다
원격저장소에도 브랜치를 만들 수 있다
브랜치 생성하려면
1. 깃헙에서 만들어도 되고
2. 로컬에서 만든거 올려도 된다
git clone으로 복사해온 작업폴더에서 새로운 브랜치를 만든다
그 후에 커밋한다.
그 다음에 로컬 브랜치를 원격에 올리고 싶으면
git push 원격저장소주소 로컬브랜치명
이거 하면 된다
참고로
git push 원격저장소주소 로컬브랜치명하면 특정 로컬저장소 브랜치 -> 원격저장소
git push 원격저장소주소하면 모든 로컬저장소 브랜치 -> 원격저장소이다
pull request하기
브랜치 만들면 뭐하나 그걸 merge해야 완성이지
합치려면 git merge로 합치면 끝이다 그리고 푸시하면 되는데
팀끼리 일하는 경우 merge하기 전에 토론하거나 검토하거나 그래야하는 경우가 많다.
그래서 github.com은 pull request기능이 있다
쉬운 말로 merge request다
이거 누르면 내 브랜치좀 merge해달라는 요청을 할 수 있고
팀원끼리 merge전에 코드 검토가 ㄱㄴ하다
아무나 상단 pull request에서 pull request 버튼 누르면 pull request 생성이 가능하다
그 다음엔 어떤 브랜치를 어디에 합칠 건지 선택하고 하단에서 commit 내역, 변경내역 잘보고 버튼 누르면 pull request가 열림
그럼 pull request 메뉴에서 확인이 가능한데
누르면 팀원들이 토론할 수 있는 곳도 있다 거기서 코드 리뷰하면 된다
잘 된것 같아서 merge하기로 했으면 merge할 때 여러가지 옵션이 있는데 택1 하면된다.
create a merge commit 하면
새로운 merge commit을 하나 생성해주는 3-way-merge를 실행해준다.
squash and merge 하면
rebase and merge 하면
- 합쳐질 브랜치를 main 브랜치 최신 commit으로 rebase하고나서 fast-forward 비슷한걸 해줌
- 결과는 squash와 비슷한데 합쳐질 브랜치의 commit 내역이 전부 보존됨
- 얘도 git log --oneline --graph 해보라
오늘의 결론 :
깃헙 등 원격 저장소에서 브랜치만들 수 있음
pull request할땐 3개중 맘대로
이 포스트는 코딩애플의 매우 쉽게 알려주는 git & github 강의를 참고했습니다.
코딩애플 너무웃겨