관리 메뉴

A seeker after truth

Rebase 집중 공략 본문

Git

Rebase 집중 공략

dr.meteor 2019. 10. 21. 15:35

* 본 글은 리얼 리눅스에서 진행한 <Git, 어디까지 써봤니?>(유료 강좌)를 수강한 후 한 사이트(https://rogerdudler.github.io/git-guide/index.ko.html)를 참고하여 배운 내용을 정리, 기록한 것이다.

 

아까 fork후 clone했던 플젝 경로로 이동하여 upstream 을 추하자 * 주의 ) 본인 프로젝트 URL 이 아닌 오리지널 플젝 저장소 url을 끌어와야 한다!

앞에서 기존에 있던 원격 저장소를 복제한 것이 아니므로 다음 명령어를 통해 원격 서버의 주소를 git에게 알려줘야 한다. upstream은 원격 저장소의 이름으로 붙여준 것이다.

# git remote add upstream (해당url)

* remote 저장소란? - 리모트 저장소를 관리할 줄 알아야 다른 사람과 함께 일할 수 있다. 리모트 저장소는 인터넷이나 네트워크 어딘가에 있는 저장소를 말한다. 저장소는 여러 개가 있을 수 있는데 어떤 저장소는 읽고 쓰기 모두 할 수 있고 어떤 저장소는 읽기 권한만 있을 수도 있다. 간단히 말해서 다른 사람들과 함께 일한다는 것은 리모트 저장소를 관리하면서 데이터를 거기에 Push하고 Pull하는 것이다. 리모트 저장소를 관리한다는 것은 저장소를 추가, 삭제하는 것뿐만 아니라 브랜치를 관리하고 추적할지 말지 등을 관리하는 것을 말한다.

(출처: https://git-scm.com/book/ko/v1/Git%EC%9D%98-%EA%B8%B0%EC%B4%88-%EB%A6%AC%EB%AA%A8%ED%8A%B8-%EC%A0%80%EC%9E%A5%EC%86%8C)

저장소를 Clone하면 명령은 자동으로 리모트 저장소를 origin이라는 이름으로 추가한다. 그래서 나중에 git fetch origin을 실행하면 Clone한 이후에(혹은 마지막으로 가져온 이후에) 수정된 것을 모두 가져온다.

 

리모트 저장소 즉 upstream에서 데이터를 가져오자. upstreamdev 브랜치를 오자.

* 단순히 원격 저장소의 내용을 확인만 하고 로컬 데이터와 병합은 하고 싶지 않은 경우에는 fetch 명령어를 사용할 수 있습니다.

fetch 를 실행하면 원격 저장소의 최신 이력을 확인할 수 있다. 이 때 가져온 최신 커밋 이력은 이름 없는 브랜치로 로컬에 가져오게 된다. 

# git fetch upstream dev

 

그니까 여기까지의 상황으로 미루어 보면...remote add 파트는 원격 저장소 주소를 알려주기만 하는 역할...? 이고 upstream은... 이게 진짜 미스테리...인터넷은 다 add origin 주소 이렇게 되어 있어서 말여... 그담에. fetch의 경우 정말 말그대로 최신 이력으로 업뎃해주는 역할...인데 upstream dev  이 파트가...upstream의 최신 이력을 원래는 이름 없는 브랜치...?로 로컬로 가져오는데 이 경우에는 이 이력 뭉치를 dev라고 해준 것인지...

 

현재 내 브랜치develop 인지 확인하자

# git status

 

rebase 하자
# git rebase upstream/dev

 

 

이제 중간에 낀 commit을 수정해보고자 한다.

commit 최초기록 부터 2 번째 commit 을 수정해보자
# git rebase -i --root

 

vi 에디터열리면 수정하려는 commit(2 번째 ) 맨앞“pick” 을 지대신에 edit” 을 적고 저장하고 에디터를

* --root 를 사용한 이유는 최초의 commit 까지 수정할 수 있도록 하기 위함

 

상태 확인해서 rebase 진행 정상적인지 보고

# git status

 

commit 정보 수정 (“packing knapsack:” commit 메시지에 추) 하고 --continue 무리

# git commit --amend -sm “packing knapsack: Add knapsack problem PDF”

# git rebase --continue

 

 

여기서,

파일이든 누라인을 수정했는지 파악하고자 한다면

# git blame report_card.c

해당 commit ID 를 이용하여 그 당시 commit 정보를 확인하고자 한다면

# git show <commit ID>


실습 1: 가장 오래된 커밋으로부터 두번째에 위치한 commit 이후에 새로운 커밋 commit 3개 넣기

# git rebase -i --root 를 입력하면, 다음과 같은 터미널 화면이 뜬다.

여기서 변경할 지점을 정해서 'pick'을 'edit'으로 수정하여 진행해야 한다. 그럼 어느 부분을 edit으로 바꿔서 수정을 진행해야 할까? 2번째에 넣어야 할까? 혹은 세번째에 넣어야 할까? 혹은 첫번째? 그를 위해 우리는 git의 특징을 먼저 이해해야 할 필요가 있다. 저번에 git의 기본을 다룬 글에서 나는 다음과 같은 부분을 사이트에서 인용하여 적은 적이 있었다.

"Git은 가능한 한 커밋을 가볍게 유지하고자 하기 때문에, 커밋할 때마다 디렉토리 전체를 복사하진 않는다. 각 커밋은 저장소의 이전 버전과 다음 버전의 변경 내역("delta"라고도 함)을 저장한다. 그래서 대부분의 커밋이 그 커밋 위의 부모 커밋을 가리킨다."

즉 시간 순으로 커밋이 쌓여 있다는 특징 때문에, 2번째와 3번째 사이에 커밋을 추가하고 싶다면 2번째 커밋에 edit을 지정하여 진행해야 한다.

3번의 add 및 commit을 진행 완료한 뒤에는 다음과 같은 명령어를 입력하면 된다.

# git rebase --continue

이는 되감은 것을 다시 풀어준다는 의미다. rebase할 사항을 마무리짓고 결과를 보겠다는 것과 같다. 다시 풀리니까, 자연스럽게 중간에 커밋을 끼워넣은 상황이 되었다.

 

 

실습2: 위 예제에서 넣은 (중간에 낀) 3개를 commit을 1개로 합치기

 

위에서 첨부한 캡쳐는 이 실습 2까지 완료한 뒤의 상황이다. 하지만 실습 1만 마친 상태에서는, "packing knapsack: Add knapsack problem PDF"와 "packing knapsack: Basic code solving this question" 두 커밋 사이에 "add hello_1.c", "add hello_2.c", "add hello_3.c"3개에 해당하는 커밋이 있었다. 그럼 2,3에 해당하는 커밋이 어떤 과정을 거쳐 "add hello_1.c" 라는 하나의 커밋 안으로 합쳐졌을까?

 

우선 똑같이 다음 명령어를 입력한다.

# git rebase -i --root

 

그리고 다음과 같이 입력한다.

# git reset --soft HEAD ~1

reset 명령어는 checkout 명령처럼 HEAD가 가리키는 브랜치를 바꾸지는 않지만, 현재 브랜치가 가리키는 커밋을 바꾼다. --soft 옵션은 가리키는 커밋 위치를 바꾸는 작업까지만 하고, --hard 옵션의 경우엔 head 가장 최상위로 취급하고 ? 아래? 있는 차례대로 지운다. ~ 뒤의 숫자만큼 부모 커밋을 지운다. 아무 숫자도 주지 않으면 Index나 워킹 디렉토리는 그대로 놔두고 브랜치가 가리키는 커밋만 이전으로 되돌린다. Index를 업데이트한 다음의 git commit --amend 명령의 결과와 같아진다.

<reset의 3가지 역할>(출처: https://git-scm.com/book/ko/v2/Git-%EB%8F%84%EA%B5%AC-Reset-%EB%AA%85%ED%99%95%ED%9E%88-%EC%95%8C%EA%B3%A0-%EA%B0%80%EA%B8%B0)

reset 명령은 정해진 순서대로 세 개의 트리를 덮어써 나가다가 옵션에 따라 지정한 곳에서 멈춘다.

1. HEAD가 가리키는 브랜치를 옮긴다. (--soft 옵션이 붙으면 여기까지)

2. Index를 HEAD가 가리키는 상태로 만든다. (--hard 옵션이 붙지 않았으면 여기까지)

3. 워킹 디렉토리를 Index의 상태로 만든다.