본문 바로가기
교육/Open Up 공개SW 실습 교육

[Open Up] 공개SW 실습 교육 정리 - 2일차

by Taler 2022. 6. 19.

교육이 끝난 한참 뒤의 정리라... 아직까지 수료증이 발급되지 않은 것도 의문이긴 하다. 이건 언제오는거지..?

이번 전체 강의도 줌으로 진행됐고 또한 5시간의 강의였다.

그래도 들으며 필기해둔 내용이 있기에, 다시 복기하는 마음으로 기록을 공유한다.

 

 

Rebase란?


Rebase란 간단히 base를 재설정하겠다는 것을 의미한다. 또한, base는 상위 커밋을 의미하기 때문에 git log 상의 어떤 커밋이라도 Base commit이 될 수 있다.

오픈소스 개발은 혼자 개발하는 것이 아니라, 몇 천명이 함께 개발한다. 다른사람들의 commit과 겹쳐버리면 base가 꼬이게 된다! 아래 그림을 보자.

 

충돌이 발생하는 상황. 직접 그림

1번 fork가 일어나고, User B가 2번 fork를 발생시켰다. 두 fork된 repository의 base는 같을 것이다.

만약 UserA가 먼저 수정하고자 하는 부분을 수정하고 PR을 올렸고, 원본에 병합이 됐다 해보자. 그렇다면, 원본 레포의 base commit은 이제 UserA가 올린 commit이 될 것이다.

반면 UserB에서는 여전히 Base가 원래와 같다. 그 B가 해당 base에 commit 후 PR을 날린다면 상황은 아래와 같아진다.

User B의 PR의 Git history와 Upstream의 것이 같지 않아 어디에 User B commit을 넣을지 몰라 충돌이 발생하는 것

그림의 설명에도 적었지만, 두 레포의 history가 달라짐에 따라 User B의 Commit을 User A 전에 넣을지, 후에 넣을지 GitHub이 판단할 수 없다. Push 권한을 가진 maintainer가 교통정리를 해줘야하는 것.

즉, User B의 PR에 maintainer는 다음과 같이 review를 남길 것이다.

"최신 Base로 rebase 해주세요."

그럼 User B는 Base commit을 Upstream Repository와 동일하게 맞춘 뒤 자신의 commit을 다시 그 위에 얹음으로써 해당 충돌을 해결해야만 한다.

 

이처럼 오픈소스 개발을 하다보면 rebase를 해야되는 상황이 온다.

 

 

Rebase 절차


rebase 절차는 다음과 같이 요약할 수 있다.

1. 최신 내용 가져오기

git fetch upstream master

Upstream의 master branch의 history를 fetch를 통해 가져오는 과정이다.

fetch를 통해 가져오면 .git 폴더에만 임시 저장된다.

또한, 자동생성된 브랜치명 “upstream/master”으로 생성됨

pull과 비교하자면, pull = fetch + merge라고 생각하면 쉽다.

2. Base 교체하기

git rebase -i --root 		# 되감기
git rebase upstream/master 	# Base 변경
git rebase --continue 		# 감았던 commit들 풀어주기

현재 branch의 base로 지정된 branch를 upstream/master branch로 교체하는 과정

 1) 여기서 rewind(되감기) 과정을 먼저 해서 base가 같은 커밋까지 돌아간다. (git rebase -i --root 이후 콘솔에서 수정)

 2) 이후 rebase를 통해 가져왔던 upstream의 최신 역사로 base를 바꿔끼운다. (git rebase upstream/master)

  - 이 과정에서 에러가 난다면, Maintainer가 base 이전의 커밋을 삭제하거나 수정해 base가 바뀐 것이다.

  - 바뀌기 전커밋까지 돌아가서 rebase를 해주자.

 3) 마지막으로 처음 되감았던, 본인이 기여했던 commit들을 다시 풀어준다. (git rebase --continuue)

  - 해당 과정에서도 오류가 자주 일어난다.

3. Push하기

git push origin {branch-name} -f

 

이후 강제로 현재 커밋을 Push한다.

-f 태그를 넣어 강제해야하는 이유는, remote 저장소의 history와 local의 history가 달라 conflict가 나기 때문이다.

지금 변경한 history가 올바른 history이기 때문에 이 commit을 push해준다.

PR되어있던 commit은 자동으로 conflict 해제를 감지한다. (다시 PR할 필요 없음)

 

또 중간에 무언가 문제가 생겼다면 아래 두 초기화 커맨드를 기억하자

초기화 명령어
(1) rebase -i 도중 취소하는 방법
git rebase --abort
(2) commit 히스토리 전체 복구 방법
git reset --hard origin/master

 

아직 Rebase가 끝난 것은 아니다. 시작도 안했다고 볼 수 있는데, rewind를 저렇게만 쓰면 손도 못 댄다. git rebase -i --root 명령어 이후 콘솔에서 뭘 어떻게 수정해야 되감을 수 있는지를 설명한다.

 

 

Rewind


git rebase -i —root로 들어가면 지금까지의 git log가 모두 뜬다.

Rewind의 과정을 간단히 말하자면, 돌아가고 싶은(되감고 싶은) commit의 pick을 edit으로 바꾸고 저장하면 rewind가 된다. 이전에 git의 기본 에디터인 nano가 익숙하지 않다면 해당 글의 git config 파트를 다시 참조하여 에디터를 다시 설정하자.

 

일단 git rebase -i --root를 쳐보자. 참고로 이전 글에서 사용했던 코드를 그대로 사용한다.

보면 가장 첫 번째 커밋부터 지금까지의 git log가 모두 뜨는 것을 확인할 수 있다.

이제 여기서 돌아가고 싶은 commit의 pick(각 줄 맨 앞의 pick)을 edit으로 바꾸고 저장하면 rewind가 된다.

위 이미지에서 ec20aff 커밋의 pick을 edit으로 바꿨다. 이제 esc + :wq를 통해 저장 후 나가보자.

그럼 이렇게 ec20aff에서 멈췄고, 뭔가 commit을 여기에 더하고 싶다면 git commit --amend를, 감았던 것들을 다시 풀고 싶으면 git rebase --continue를 하라는 메세지를 확인할 수 있다.

 

참고로 위 그림에서 여러 줄의 pick을 한 번에 edit으로 바꿔도 상관 없으며, 각각에 대해서 git rebase --continue를 해줘서 각각 되감아진 것을 풀어줘야 한다.

 

간단해 보이면서도 직접 해보면 생각보다 그렇지 않음을 알 수 있다. 여기서 만약 꼬였다면, `git reset —hard upstream/master` 명령어를 통해서 upstream/master로 아예 되돌려버리자. (주의: 커밋한 내용 사라짐)

꼬일 수도 있고, 생각보다 어렵지도 않다. 그렇다면 Rewind를 왜 쓰는 걸까?

Rewind 사용 이유

만약 어떤 오픈소스 프로젝트에 참여하여 PR을 보냈고, maintainer가 다음과 같은 리뷰를 달았다고 해보자.

### Review Message ###
1번 커밋은 메세지를 ~~ 이렇게 수정해주시고
2번 커밋은 삭제해주세요
3번 커밋은 두 개로 나눠주시고
4번 커밋은 5번 커밋과 합치는 게 좋을 것 같습니다.

상당히 시비거는 것 같지만(싸우자는 거 같기도 하다...), 실제로 이렇게 리뷰가 달린다고 한다.

사실 commit 하나의 사이즈를 어느 정도로 할 지에 대한 고민은 사람마다 다르기 때문이고, 기준이 다르기 때문에 이런 일이 발생한다는 것이다.

참고로 하나의 commit에는 하나의 목적만 담는 것이 좋다. 그래야 리뷰하기도 편하고 commit log도 깔끔해지기 때문

아무튼 이런 내용들을 모두 rewind를 통해 유연하게 대처할 수 있다는 것이다.

 

Rewind 주의사항

주의해야될 사항으론, 기존의 commit들에는 rewind를 안한다.

실제 rewind 작업은 내가 만든, PR로 제출하는 커밋들을 대상으로 진행하는 경우가 보통이다.

 

또한, 실제로 rebase 명령어를 사용할 때도 git rebase -i HEAD~2 처럼 범주를 지정해서 사용한다.

(맨 마지막 커밋부터 2개라는 뜻이다)

 

rebase를 자세히 알아봤으니, 이제 임시 저장인 stash로 넘어간다.

 

 

Stash


수정한 후 commit을 하지 않았을 때, 새로운 것을 가져왔어야 된다 하자. 그때마다 우리는 늘 수정분은 따로 복사를 해놨다가 rebase나 pull한 후 다시 붙여넣기를 해야 하나? 아니다.

Stash를 통해서 변경분을 저장한 후 변경 반영 후 stash pop한다.

그렇다면 다른 방법들이 아니라 stash를 사용하는 이유는 무엇일까? 아래서 살펴보자.

Stash를 사용하는 이유
1. 코드 수정했던 내용 잠시 keep해두고 싶어서
2. test 검증 (Before/After) 비교하고 싶어서.
    - stash를 통해 전과 후를 비교하는 것이 훨씬 간편하다.
    - commit을 생성한 후 그때가서 수정하면 cost가 너무 높아진다.

즉, stash는 커밋 전에 확인작업할 때 사용하거나, rebase를 할 때 쓰면 편하다.

또한 Stash가 저장되는 스택은 영구적이다.

 

이때 수업시간에 재밌는 질문이 나왔다.

 

Stash와 checkout의 차이점이 무엇인가요?

 

아무튼 아주 좋은 질문이라며 강사분께서도 답변해주셨다.

Stash vs Checkout

Stash는 저장하는것, 임시저장하는 것이기 때문에 어딘가에 Keep된다.
Checkout은 덮어쓰는 것. 일단 Checkout을 하면 돌아갈 수 없다..! (에디터를 켜고있다면 재빨리 ctrl+z를 누르자)

 

다음은 commit을 수정하는 amend에 대해서 알아봤다.

 

 

Amend


Amend는 수정사항이 생겨서 commit을 수정하고 싶을 때 사용한다.

하지만 해당 과정에서 무조건 commit의 Hash 값이 바뀌기 때문에 중간에 있는 커밋을 삭제하거나 수정하면 다른 사람들의 git history와 충돌난다. 따라서 중간 커밋을 수정하는 것은 좋지 않다.

커밋을 취소하고 싶을 때는 Amend로 수정하는 것이 아니라 git revert를 사용하자.

 

사용 방법

1. 수정본을 따로 commit하지 않고 이전 커밋과 합치고 싶을 때

  - 수정본을 add하고 commit —amend를 하면 변경분은 가장 최신 commit 블록에 흡수된다.

  - 그냥 commit하면 새로운 commit 블록이 생성된다.

2. commit log message만 변경하고자 할 때

  - git add없이 그냥 git commt —amend하면 commit log message만 수정할 수 있다.

  - Amend시 수정 시간도 commit에 반영되기 때문에 아무런 변경 없어도 commit의 HASH 값이 바뀐다.

  - git commit --amend --no-edit --date "Mon 20 Aug 2018 20:19:19 KST” 등을 통해 마지막 commit의 날짜만 변경하는 것도 가능하다.

 

잘 쓰면 유용한 기능이지만, 한계점도 명확하다. 바로 최신 commit만 수정이 가능하다는 점이다.

하지만 또 하라면 하는게, 위의 rebase를 이용해서 rewind한 뒤, amend시 중간에 있는 commit을 수정/삭제/추가할 수 있다.

 

이제 2일차의 마지막 blame이다.

 

 

Blame


Blame은 record 파일을 열어주는 명령어이다.

특정 파일을 지정하면, 해당 파일에서 어떤 line이 탄생한 commit의 Hash와 log message를 보여준다. (때문에 commit message가 또 중요해진다.)

여기서 찾은 commit id를 통해서 git show {id}를 통해 해당 커밋 내용을 확인할 수 있다.

source reading을 하는 과정에서 blame을 적절히 사용할 수 있다.

(commit message를 통해서 해당 line이 어떤 목적으로 만들어졌는지 확인할 수 있음, 이름만 보면 누가 만들었는지 찾아서 따지려는 목적의 명령어..)

 

 

마치며...


사실 3일차는 팀프로젝트와 2일차의 실습을 위주로 진행했기 때문에 따로 정리한 것은 크게 없어 이번이 마지막 게시글이다. 깃에 대해서 15시간에 걸쳐 이론과 사용법을 자세하게 배우고, 실시간으로 문답하며 실습까지 진행해볼 수 있었던 교육이었다. 나는 만족도가 상당했는데, 반면 Git을 좀 써봤거나, 혹은 팀프로젝트를 따로 해볼 일이 없어 git 명령어에 대한 교육욕이 적은 학우들에게 하루 5시간 연강은 조금 빡셀 수도 있겠다는 생각이 들었다.

 

혹시 추후에도 열린다면, 관심이 있는 성대 학우들은 git에 관심이 없더라도 꼭 참여해서 열심히 들어보자. git을 이용한 버전관리는 개발자라면 평생 해야만 하는 일이니까...

 

참고로 수료증은 2주가 되어가는 지금, 아직 나오지 않아 기다리고 있다.

 

댓글