지난 시간 오픈소스 컨트리뷰션 멘티로 합격하고 1차 교육을 받아봤다.
협업을 위한 github사용법에 대해 하루에 4시간씩 총 8시간 교육을 진행하였는데 개인프로젝트를 주로하던 나에게 생소한 명령어들이 많았다. 다시 복습할 겸 이번에 글을 작성해보고자 한다.
개인프로젝트할 때는
git add
git commit -m "대충 적음"
git push origin master(or main)
위 3줄로만 사용하고 commit을 잘못 작성할 경우 그냥 무시하고 진행한 경우가 대다수다.
그러나 오픈소스 프로젝트를 진행할 경우 위처럼하면 싸대기 맞는다.
그럼 협업을 위한 github는 어떻게 사용할까?
여태까지 commit을 왜 작성하는지, 그냥 대충쓰면 되는거 아니야? 이런 생각으로 github에 업로드를 하였는데 이는 굉장히 잘못된 사고방식이다. commit에 내 작업에 대한 모든 정보가 담겨있고, reviewer 또는 operator가 merge를 할 때 내 커밋을 위주로 결정을 하고, 다른 개발자 또한 내 커밋을 보고 작업을 할 수도 있기 때문이다. 따라서 대충 commit을 작성하면 다른 개발자한테 싸대기 맞을 수 있다는 것이다!!
그렇다면 commit을 어떻게 작성해야 할까??
보통 commit은 한줄로 요약해서 적는다. 따라서 단어 하나하나에 의미를 담아야된다. 예를 들어 다음과 같이 commit을 작성해봤다고 가정하자
README.md 파일
~~~
Uchan Lee(python) <- 추가
해당 파일을 add후..
git commit -m "update"
위처럼 commit을 한 후에 push를 하고 PR(pull&request)을 했다면??
reviewer가 보기엔 무슨파일에 어떻게 수정하였는지 모를수 있다. 따라서 내가 reviewer or operator라면 절대 merge하지 않을 것이다. 따라서 보다 구체적으로 해석할 수 있도록 아래와 같이 수정하자
git commit -m "Add UchanLee in README.md"
위와 같이 commit을 작성한다면 누가봐도 쉽게 해석이 가능하고 코드를 참고할 수 있다.
git log --oneline
위 커맨드를 입력하면 다음과 같이 나온다.
commit ID, commit 내용
위와 같이 출력이 되는데 이를 통해 commit ID를 확인할 수 있다. 추가로 옵션을 달아서 로그를 확인할 수 있다
예를 들어, git log --oneline | wc -l 를 친다면 log 개수가 나올것이다.
또, wc -l 대신 head -10 를 친다면 위에서부터 10개만 출력된다.
여기서 중요한 점은 위에서부터 최근기록이라는 점이다. 즉, 위에 있을수록 최근 커밋이라는 뜻이다. 따라서 log를 오래된 순으로 보고싶다면 아래와 같이 입력하면 된다.
git log --oneline --reverse
여기서 oneline 옵션이 궁금할 수 있다.
oneline 옵션을 뺀다면 어떻게 출력될까?
위와 같이 commit을 작성한 사람의 정보와 날짜가 출력된다. 따라서 어느 code를 누가 작성했는지 해당 commit에 대한 정보를 이용하여 알 수 있다. 만약 내가 어느 code에 몇번째 line을 보고 궁금점이 생긴다면 해당 commit을 추적하여 작성자에게 물어볼 수 있는 것이다(굉장히 유용할 듯)
인터넷에 치면 git reset --soft HEAD~2 이런식으로 삭제하면 된다고 한다. 이를 분석하자면 위에서부터 2개를 지우는 대신 파일을 그대로 둔다는 뜻으로 soft 대신 hard를 입력한다면 모두 삭제한다는 뜻이다. 여기서 중요한 점은 위에서부터 지운다는 것이다. 중간 commit 기록을 지울라면??
rewind는 되감는다는 뜻으로 일정 지점을 최근기록으로 둔다는 점이다. 왜 이렇게까지 해야되는가? 앞서 언급한 듯이 commit은 최근기록을 중심으로 작업을 진행할 수 있다. 따라서 중간으로 바로 접근이 불가능하다!!(advance skill을 쓴다면 가능할지도). 그래서 지우고 싶은 commit 지점으로 되돌아가고 삭제해야된다.
이런 log가 있다고 가정하자.
여기서
git rebase -i --root
를 치면 다음과 같이 나온다.
(참고로 필자는 vim editor가 default이므로 nano 등을 사용하는 사람과 다르게 나올 수 있다)
그럼 3번째 commit부분에 pick을 edit으로 바꿔주고 wq를 하면
conflict가 발생했다고 뜨는데 이는 당연하다. 왜냐하면 해당 커밋을 삭제하면서 전에 있던 파일들과 충돌이 일어났기 때문이다. git diff를 치면 더욱 자세히 나온다.
이 상태에서 README.md를 고치고 새로 commit을 추가하여 push를 하면?
흔히들 겪는 push error이다. 이 또한 일어나는 것이 당연하다. 왜냐하면 commit을 수정하였기 때문에 git에 올라가 있는 파일과 다르고 따라서 충돌이 일어난 것이다. 따라서 다음과 같이 명령어를 쳐서 강제로 push해버린다.
git push origin master -f
흔히들 -f 옵션을 권고하지 않는다. 이는 프로젝트에 수정된 코드를 올림으로써 충돌이 일어날 수 있기 때문이다. 그러나 해당 과정에서 충돌은 당연한거고 이를 올릴라면 어쩔수 없이 -force 옵션을 넣어줘야한다. -f를 붙인다고 부정적이라고 생각하면 안된다.
위와 같이 성공적으로 push를 했다. 그리고 log 또한 다음과 같이 변경되었다.
이를 활용하여 rebase를 하고 conflict가 나지 않는 시점으로 돌아가 파일을 수정할 수 있다.
그러면 commit 수정하는 방법은 다음과 같이 할 수 있겠다.
과거시점으로 돌아가고 -> 해당 커밋 삭제 및 수정 -> rewind
즉,
1. git rebase -i --root를 사용해서 해당 지점을 edit으로 설정
2. git reset --soft HEAD~1
3. git commit -m "수정 내용"
4. git rebase --continue
위와 같이 하면 수정된 것을 볼 수 있을 것이다. 다음 방법으로 drop과 reword 등을 사용할 수 있는데 이는 생략하겠다.
위에서 계속 commit 얘기만 했는데, 그만큼 commit의 중요성을 강조하고 싶었다. commit이 내 작업코드를 대표하기 때문에 이를 작성하는 것, 수정하는 것 등 하나하나 조심히 작업을 해야된다. 또한 opensource에서는 여러명이 작업하기 때문에 내가 작업한 것과 누군가가 작업한 것이 충돌이 일어날 수 있다. 따라서 rebase 명령어를 사용하여 충돌이 안나는 시점으로 돌아가는 스킬도 필요하다.
만약 PR를 하였는데 다른 사람의 코드를 merge하여 내 코드가 merge가 안될 수 있다. 이때 rebase를 통해 해결을 해야된다는 점을 명시해야겠다!!