좋은 커밋 메시지 작성하기



좋은 커밋 메시지는 다음 세가지 중요한 목적이 있다:

  • 리뷰 프로세스를 빠르게 만든다.
  • 좋은 릴리즈 노트를 작성하게 돕는다.
  • 미래의 코드 메인테이너를 돕는다. (그 메인테이너가 당신일 수도 있다!) 어떤 코드 변경이 일어났는지, 왜 이 특정한 기능이 추가되었는지 수년 후에 이야기 해도 알 수 있도록 말이다.

커밋 메시지의 구조는 다음과 같다. 이 내용은 git scm에서 자세하게 확인할 수 있다:

(50자 미만의) 변경에 대한 짧은 요약
필요하다면 상세한 설명을 첨가한다. 행 당 72자가 넘지 않도록 유의한다. 맥락에 따라 첫 줄은 이메일의 제목처럼, 나머지는 본문처럼 다뤄지는 경우가 있다. 요약과 본문을 구분하는 빈 행은 본문을 생략하지 않는 이상 필수적이다. rebase와 같은 도구를 사용하면 혼란을 줄 수 있기 때문이다.
추가적인 문단은 빈 행 다음에 작성한다.
- 개조식 서술 또한 괜찮음 - 블릿(bullet)으로 하이픈(-)이나 별표(*)를 사용하고, 한 칸의 공간을 띄고 각 항목 사이 빈 행을 넣는 방식이 일반적이나 다양한 관례가 있음.

해야 할 일

  • 요약과 설명을 작성할 때는 자신이 무엇을 했는지를 명령형으로 작성한다. 즉 다른 사람에게 이 일을 지시하듯 작성한다. “고쳤다 fixed”, “추가했다 added”, “변경했다 changed” 대신 “고치다 fix”, “추가하다 add”, “변경하다 change” 식으로 작성한다.
  • 항상 두번째 빈 행을 추가한다.
  • 커밋 메시지에서 줄 바꿈을 한다. (gitk등 커맨드 환경에서 커밋 메시지를 수평 스크롤 없이 쉽게 읽을 수 있는데 도움이 된다.)

하지 말아야 할 일

  • 요약 끝에 마침표를 찍지 않는다. 요약은 제목이다. 제목은 마침표로 끝나지 않는다.

  • 커밋을 요약하는데 어려움을 느낀다면 커밋 안에 여러 로직의 변화 또는 버그 수정이 있기 때문일 것이다. 이럴땐 git add -p 명령어를 사용해 여러 커밋으로 분리하는 것이 낫다.

레퍼런스

커밋 메시지에 대한 좋은 논의를 다음 블로그 포스트에서 확인할 수 있다.


+커밋 메시지에 대해


지난 몇 주 동안 놀랄 만큼 많은, 커밋 메시지에 대한 토론을 읽게 되었다. 그 중에는 개발자와 함께 막 새 프로젝트를 시작하려는 사람들도 많았다. 그래서 그들을 돕기 위해 커밋을 할 때 해야 할 일과 그 일을 왜 해야 하는지에 대한 목록을 작성해봤다. (힌트: 리눅스 커널 메일링 리스트는 이 일을 아주 바람직하게 하고 있다. 그곳에서 배우자.)

모든 소프트웨어 프로젝트는 협동 프로젝트다. 적어도 프로젝트엔 두 명의 개발자가 일하게 되어 있다. 나 혼자 최초 개발자로 스스로 개발을 한다고 해도 몇 주, 몇 달이 지난 후에 작성한 코드가 무엇인지 생각해내야 하는 미래의 내가 존재한다. 미래의 나는 새로운 버그가 발생하거나 새로운 기능을 추가해야 할 때마다 매번 특정 부분의 코드에 대한 맥락을 다시 파악해야만 한다.1

코드 조각의 맥락을 다시 파악하는 일은 정말 낭비일 수밖에 없다. 물론 이 일을 완전히 회피할 수는 없겠지만, 이 시간을 최소화할 수 있도록 노력해야 한다. 바로 커밋 메시지가 그 역할을 담당한다. 그렇기 때문에 커밋 메시지를 보면 그 개발자가 좋은 협력자인지 아닌지를 알 수 있게 된다.

좋은 커밋 메시지는 패치에 관한 다음 세 가지 질문에 답을 할 수 있어야 한다:

  • 왜 이 코드가 필요한가? 코드는 버그 수정, 기능 추가, 성능 향상, 신뢰성, 안정성을 위한 변경일 수 있다. 물론 단순한 오·탈자 교정일 수도 있다.
  • 어떻게 이슈를 해결했는가? 짧아서 명백한 패치의 경우 이 부분을 생략해도 된다. 다만 깊은 수준의 묘사로 어떻게 문제에 접근했는지 나타내야 한다.
  • 패치가 어떤 영향을 만드는가? 명백한 부분을 포함해 벤치마크 결과, 부작용 등을 포함할 수 있다.

이 세 가지 질문으로 실제 코드 변경에 대한 맥락을 알 수 있게 된다. 또한 리뷰어와 다른 개발자가 그 맥락을 통해 차이점을 보고 적절한 방법을 선택해 문제에 접근했는지 확인하게 된다. 또한 좋은 커밋 메시지는 메인테이너에게 안정 브랜치에 포함해도 괜찮은지, 또는 배포에 포함해도 괜찮은지 결정하는데 도움된다.

이 세가지 질문에 대한 답이 없는 패치는 대부분 쓸모 없는 패치다. 이런 경우에는 이 패치가 어떤 일을 하고 어떻게 이슈를 해결했는지 직접 찾아야 하기 떄문에 리뷰어에게 부담만 될 뿐이다. 복잡할대로 복잡한 패치에 많은 수의 리뷰어가 필요한 상황. 그 의미는 결국 원 개발자가 좋은 커밋 메시지를 작성하지 않았다는 이유만으로 많은 인력 투입 시간(man-hours)이 낭비된다는 뜻이다. 거기에 만약 메인테이너가 프로젝트의 소스 컨트롤 관리 통제를 철저히 하고 있다면, 개발자가 제출한 패치는 거절 당할 것이고 개발자는 다시 시간을 소비해 패치를 다시 작성해야 하며, 리뷰어는 리뷰에 또 시간을 소비하게 되는, 최악의 경우도 발생할 수 있다. 이처럼 시간 낭비는 빠르게 늘어난다. 단지 몇 분 시간을 투자해서 커밋 메시지를 작성하는 것이 이런 비경제적인 시간 소비를 없앨 수도, 최악의 상황을 만들 수도 있는 것이다.

오픈소스가 아닌 일반 소프트웨어 회사도 이 내용을 충분히 고려해야 한다. 적당한 소스 컨트롤 관리 규칙이 없으면 결국 비용이 발생한다.

어떻게 해야 더 잘할 수 있을까

물론 이상적인 커밋 메시지는 이래야 한다는 엄격한 정의는 없다. 하지만 몇 가지 일반적인 규칙은 있다. 커밋은 정확히 하나의 로직 변경을 포함해야 한다. 로직 변경은 새로운 기능을 추가하거나 특정 버그를 수정하는 것 등을 의미한다. 몇개의 단어로 고수준의 변화를 묘사할 수 없다면 단일 커밋으로는 너무 복잡한 상태인 것이다. 변경은 가능한 한 그 스스로 이해할 수 있도록 간결해야 한다. 많은 패치에서 발생한 에러가 작은 패치에서 발생한 에러보다 낫다. 가장 우선이 되는 규칙으로, 커밋 메시지만 읽어도 다른 개발자가 납득할 만큼 비슷한 시간을 들여 같은 패치를 구현할 수 있어야 한다.

git을 사용한다면 git add -p (또는 -i)를 활용해 각각의 변경 사항에 따라 로직을 이해할 수 있는 수준의 단일 커밋 단위로 쪼개야 한다.

Git 커밋 양식

만약 패치를 git으로 제출한다면, 그 양식은 거의 표준화 되어 있다. 첫 행은 변경에 대한 요약이다. (행의 최대 길이는 프로젝트마다 다르지만 일반적으로 행 당 50자에서 78자 사이다.) 이 첫 줄을 가장 많이 보게 되고 그만큼 중요하다. 많은 git 도구가 이 방식으로 동작하거나 이 양식에 최적화되어 있다. 첫 행 요약 다음으로 빈 행을 입력하고 그 뒤로 필요에 따라 패치에 대한 상세 내역을 여러 문단으로 작성한다. 코드를 설명하지 말고 의도와 접근 방식을 설명한다. 로그는 현재형으로 작성한다.

로그를 사랑하는 방법을 배울 것

나는 과거에 CVS를 사용했는데 (SVN도 조금) 이 도구는 정말 사용하기가 쉽지 않았다. 거의 쓸모가 없었는데 도구도 그랬고 사용 가능한 정보도 그랬다. 현재는 코드를 들여다 보는 것 보다 git의 로그를 더 자주 본다. git 로그 도구는 일하고 있는 프로젝트에서 CVS의 로그나 커밋 규칙에 비해 대단히 뛰어나기 때문에 훨씬 편리하다. 코드보다 git 로그를 더 많이 붙잡고 왜 이 코드가 이런 방법으로 작성되었는지 git을 통해 살펴보는데 대부분의 시간을 쓴다. 이 방법은 확실히 많은 시간과 노력을 아끼게 해준다. X 서버 버그에서 가장 짜증나는 점은 코드가 XFree86에서 넘어오는 과정에 git 히스토리가 남아있지 않은 곳에서 나타난다는 점이다. 만약 아직 소스 컨트롤 관리의 로그 도구를 사용하고 있지 않다면 이 도구와 더 친해지길 추천한다.

하면 안되는 것

커밋을 할 때 평균적으로 나타나는 몇 가지 일반적인 죄악이 있다. (그렇다. 읔.)

  • 소스 컨트롤 관리는 백업 시스템이 아니다! 개인적으로 정말 싫어하는 유형이다. 개발자 중에는 이 도구를 퇴근용 커밋 즉, 퇴근하기 직전에 변경한 모든 코드를 커밋하는 사람이 있다. 그 결과는 아무짝에 쓸모가 없다. 코드 이곳 저곳에서 확인되는 변경점은 몇개월이 지나면 그 누구도 이해할 수가 없다. 실제 코드 작성자를 포함해서 말이다. (덧붙여: 대학교는 절대 이런 쓰레기 방식으로 가르치지 말 것.)
  • 파일 당 커밋. 파일 하나 이상에서 로직 변경이 실제로 발생하지 않았는데도 커밋하는 경우가 있는데 지나치게 분리해서 커밋하면 안된다.
  • 게으른 커밋 메시지, “여러가지 고치고 정리했음” 또는 이와 비슷하게 작성한 모든 커밋을 의미한다. 이런 경우를 비FOSS 프로젝트에서 종종 본 적이 있었는데 이런 커밋은 결국 당신에게 되돌아와 상처를 입힌다. 알려진 버그인지 알아내는 것은 불가능에 가깝고 문제를 분리하기도 어려울 뿐더러 그 누구도 프로젝트에서 무슨 일이 일어나고 있는지 따라가기 어렵게 만든다.
  • 하나의 패치 안에 두 가지 변경. 예를 들면 “버그 2345를 수정했고 모든 foo를 bar로 수정했음”과 같은 커밋이다. 버그 2345에서 명칭 변경이 요구되고 있다 하더라도 이런 커밋은 여러개의 패치로 분리해야 한다. 이 버그 픽스를 안정 브랜치에 적용해야 하는 상황일 때 다른 내용이 함께 있기 때문에 적용할 수가 없다. 잘못된 패치를 유용한 덩어리에 넣는 일은 누군가 직접 처리하기 전까진 프로젝트에 아무런 가치를 더해주지 못하는 일이라 가장 시간 소모적이고 짜증나는 일 중 하나다.
  • 코드 변경에 공백 변경을 함께 넣는 경우. 사막에서 바늘 찾는건 재미있는 게임이지만 패치를 들여다보고 있을 때는 전혀 아니다. 이 방법은 분명 버그를 소개하는 가장 강력한 방법이긴 하다. 비록 수백 줄의 코드에 들여쓰기를 변경해 모든 코드가 변경된 상태로 표시되고 있으니 말이다. 재미로 한건지 장점이 있어서 한 것인지는 둘째치고 어느 위치에 버그가 있었고 그 버그를 어떻게 수정했는지 거의 아무도 찾을 수 없다.
  • 너무나도 사랑스러운 코드 누락. 새로운 기능을 추가하기 위해 수백 줄 코드 패치를 작성하는 동시에 이 기능을 위해 기존에 있던 인프라 구조를 절반 이상 재작성을 한 경우다. 그 결과로 수백 줄의 코드를 리뷰해야 하고 매번 이 영역에 있던 코드와 관련된 버그를 발견하게 된다.인프라 구조를 한번에 한 조각씩 수정하는 것으로 시작하고 그 작업을 하고서 맨 위에 새로운 기능을 꼽았으면 훨씬 쉽고 적은 시간을 사용했을 것이다. 위와 같은 방법을 자주 사용해서, 즉 빈번하게 코드 덤프를 통채로 적용하는 프로젝트가 있다면 이는 외부 개발자들의 사기를 떨어뜨린다. 당신이라면 코드를 기여하는 프로젝트가 아니라 지독한 잡음에서 신호를 골라내는 일에 시간을 쓰는 프로젝트에 참여하겠는가?
  • 패치와 관계 없는 공백 변경. 리뷰어는 패치에 관한 큰 그림을 생각해야 한다. 공백만 있는 덩어리는 혼란스럽다. 리뷰어는 그 공백이 실제 변경인지 무시해도 되는지 확인하기 위해 더 추가적인 노력을 기울이게 된다. 빈 행이 추가되거나 제거되는 경우는 그렇게 나쁘지 않다. 정말 나쁜 경우는 들여쓰기 변경이다.

위와 같은 상황에는 수많은 변명도 존재하는데 대부분 다음과 같이 대답하기를 좋아한다. “그래도 동작하잖아요!” 물론 동작은 한다. 하지만 코드는 정적이지 않다. 얼마 간의 시간 내에 코드는 아마 이동하고, 다시 작성될 것이며, 다른 방법으로 호출되거나 버그가 포함되어 있다는 사실이 발견될 수도 있다. 동시에 최초의 개발자는 코드를 움직이고 누구도 왜 그 코드가 그렇게 움직였는지 모를 수도 있다. 최악의 경우는 모든 사람이 코드를 만지는 것을 두려워하는 상황인데 누구도 어떻게 실제로 동작하는지 알 수 없기 때문이다.

또 다른 일반적인 변명은 다음과 같다. “하지만 나는 이 프로젝트에 참여하는 유일한 사람입니다.” 사실이 아니다. 모든 소프트웨어 프로젝트는 (위에서 보는 것과 같이) 협동 프로젝트다. 누구도 단순히 근시안적으로 생각하지 않는다. 특히 FOSS 프로젝트는 외부의 기여자 즉, 테스터, 개발자, 우선순위를 정하는 사람, 사용자 등에 의존적이다. 그들이 참여하게 만드는 게 어렵다면 그 프로젝트는 더 쉽게 망할 것이다.

좀 덜 일반적이지만 최근에 자주 보이는 또 다른 변명은 소스 컨트롤 관리가 너무 느리다는 불평이다. 분산 소스 컨트롤 관리는 이 이슈를 해결했기 때문에 시간도 절약하고 돈 절약에도 아마 보탬이 될 것이다.


번역: By Haruair 

http://www.haruair.com/blog/2738

원문

https://github.com/erlang/otp/wiki/Writing-good-commit-messages





Scenario: 집에서 Git Remote 올려놓은 Docs파일을 학원에 로컬내에 있는 저장소에서 다운받으려는데 항상 그러던것처럼 생각처럼 잘 되지 않았다. 

그래서 어떻게 하면 할수 있을지 고민하다가 Overwrite 라는 명령어를 통해 해결했다.




Solution:(아래)


1.Local 내 프로젝트를 우클릭후 Synchronize Workspace를 클릭한다.





2.그러면 Rmote repo에 있는 파일 목록이나오는데, 일치하지 않는 파일은 알아서 표시가 뜬다. 그러면 파일을 우클릭후 Overwirte를 누른다

(무분별한 Overwrite는 파일의 손실을 유발할 수 있으니 주의 하자)




3.(로컬 프로젝트 내에 * 표시(Unstage) 가 뜬다 그러면 순서대로 stage 후 commit을 해주자. 






4. 참고로 History(커밋내역)는 Tmea-> Show in history에서 멘트와 누가 했는지 볼수 있다.


scenario: 이제 본격적으로 웹으로 프로젝트를 시작하려니 참고할 소스도 많아지고, 기능별로 브랜치를 만들어야 될것 같았다.

그래서 브랜치를 써본적이 없지만 하나하나 브랜치를 추가하고 변경하고자 준비를 시작함.


solution: 아래



Bash 0.60 KB
  1. //리모트 저장소 보기
  2. git remote show
  3. origin
  4.  
  5. //리모트 저장소 이름바꾸기
  6. git remote rename origin remote/projects
  7.  
  8. //전체 브랜치 목록보기
  9. git branch -a
  10. * dev-UsingMyBatis
  11.   master
  12.   remotes/origin/dev-UsingMyBatis
  13.   remotes/origin/master
  14.  
  15. //현재 브랜치는 (dev-UsingMyBatis) 이런식으로 써져있다.
  16. //그리고 전체목록을 보면 별표로 되있는게 현재 브랜치이다.
  17. //다른 브랜치로 전환
  18. git checkout [branch name]                              
  19.  
  20.  
  21. //리모트 저장소에 브랜치 추가
  22. git push origin dev-UsingMyBatis


Scenario: Git hub는 오픈기반이라서 내가 의도하지 않아도 Repo를 공개해야하고 검색이 되는 것이다. 그래서 나는 BitBuckets으로 옮기고 난뒤 remote repo의 내용을 삭제하고 싶엇는데, repo를 단순히 삭제하면 Github위키에서는 검색이 된다는 이야기가 있어서, 저장소의 내용들을 깨끗히 삭제하고싶었다.


Solution:(아래)




git 기본 로컬 폴더 등록부터 


gitHub,bitbucket  같은 리모트 서버의 Repository와 연동까지

 

한 2시간 삽질하면서 해본것같다.


  1. /************* Github 내에 소스코드 삭제방법*********************/
  2. /*문제점: 깃허브에 저장된 폴더나 소스를 삭제할 방법을 몰라**/
  3. /*폴더를삭제하고 commit 했더니 remote와 mach가 안되서 오류가남******/
  4. /*새롭게 로컬에 똑같은 이름폴더를만들고 Merge를 하니까 해결됨****/
  5. /****************************************************************/
  6.  
  7.  
  8. /**************** github 다운받고 초기설정 방법******************/
  9.  
  10. Administrator**** MINGW64 ~/gittemp (master)
  11. git config --global user.name "*******"
  12.  
  13. Administrator**** MINGW64 ~/gittemp (master)
  14. git config --global user.email "******"
  15.  
  16. //글로벌네임 리네임 방법
  17. Administrator**** MINGW64 ~/gittemp (master)
  18. git config --global user.name *******
  19.  
  20. Administrator**** MINGW64 ~/gittemp (master)
  21. git config --list
  22. core.symlinks=false
  23. core.autocrlf=true
  24. core.fscache=true
  25. color.diff=auto
  26. color.status=auto
  27. color.branch=auto
  28. color.interactive=true
  29. help.format=html
  30. http.sslcainfo=C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt
  31. diff.astextplain.textconv=astextplain
  32. rebase.autosquash=true
  33. user.name=*****
  34. user.email=*********
  35.  
  36. Administrator**** MINGW64 ~
  37. mkdir gittemp
  38.  
  39. Administrator**** MINGW64 ~
  40. cd gittemp
  41.  
  42. Administrator**** MINGW64 ~/gittemp
  43. git init
  44. Initialized empty Git repository in C:/Users/Administrator/gittemp/.git/
  45.  
  46. Administrator**** MINGW64 ~/gittemp (master)
  47. touch Readme.txt
  48.  
  49. Administrator**** MINGW64 ~/gittemp (master)
  50. git status
  51. On branch master
  52.  
  53. Initial commit
  54.  
  55. Untracked files:
  56.   (use "git add <file>..." to include in what will be committed)
  57.  
  58.         Readme.txt
  59.  
  60. nothing added to commit but untracked files present (use "git add" to track)
  61.  
  62. Administrator**** MINGW64 ~/gittemp (master)
  63. git add Readme.txt
  64.  
  65. Administrator**** MINGW64 ~/gittemp (master)
  66. git commit -m "Add readme.txt"
  67.  
  68. Administrator**** MINGW64 ~/gittemp (master)
  69. git remote add origin https://github.com/****/projects.git
  70.  
  71. Administrator**** MINGW64 ~/gittemp (master)
  72. git remote -v
  73. origin  https://github.com/****/projects.git (fetch)
  74. origin  https://github.com/****/projects.git (push)
  75.  
  76. Administrator**** MINGW64 ~/gittemp (master)
  77. git remote show
  78. origin
  79.  
  80.  
  81.  
  82.  
  83. /**************************여기서부터 GitHub내 파일 삭제 완료******************************/
  84.  
  85.  
  86.  
  87. Administrator**** MINGW64 ~/gittemp (master)
  88. git push -u origin master
  89. Username for 'https://github.com': ****@gmail.com
  90. To https://github.com/****/projects.git
  91.  ! [rejected]        master -> master (non-fast-forward)
  92. error: failed to push some refs to 'https://github.com/****/projects.git'
  93. hint: Updates were rejected because the tip of your current branch is behind
  94. hint: its remote counterpart. Integrate the remote changes (e.g.
  95. hint: 'git pull ...') before pushing again.
  96. hint: See the 'Note about fast-forwards' in 'git push --help' for details.
  97.  
  98.  
  99. Administrator**** MINGW64 ~/gittemp (master)
  100. git push origin +some_branch
  101. error: src refspec some_branch does not match any.
  102. error: failed to push some refs to 'https://github.com/****/projects.git'
  103.  
  104. Administrator**** MINGW64 ~/gittemp (master)
  105. git push origin +master
  106. Username for 'https://github.com': ****@gmail.com
  107. Counting objects: 5, done.
  108. Delta compression using up to 4 threads.
  109. Compressing objects: 100% (3/3), done.
  110. Writing objects: 100% (5/5)479 bytes | 0 bytes/s, done.
  111. Total 5 (delta 1), reused 0 (delta 0)
  112. remote: Resolving deltas: 100% (1/1), done.
  113. To https://github.com/****/projects.git
  114.  + 4ebba1a...b180f2e master -> master (forced update)
  115.  



소스코드 공유시 틀 사이트는 : http://pastebin.com/index.php

여기 좋은것 같음



Scenario:집에서 예전 롯데면접관련 소스를 수정하다가, Create Table에 관련한 Sql문을 Bitbucket(Remote Repo) 에 저장을 해두었음, 학원에서 DOCS 폴더(로컬에 없음)을 Repo로부터 불러올려고하니 잘안되는 것이었다.


Solution:Overwrite를 통해 해결하였다.



[세부 설명]


1.Git 된 프로젝트를 클릭하고 싱크로나이즈드 워크스페이스 클릭.





2.(1)에서 싱크로나이즈드를 눌렀다면 Repo 저장소의 파일들이 보일것이다. (그냥 프로젝트 전체로 잡고 overwrite 해주자)





3.다시 Spring 뷰어로 돌아와서 프로젝트를 보면 눈꽃모양 (*) 모양이 되어있을 것이다. Commit를 한다.





4.Commit을 해주면 최종적으로 로컬에도 변경내용을 확인 할 수있다.




5.히스토리를 클릭하면 커밋한 내용들 (프로젝트가 변경된 내용들을 Comment와 함께) 확인 할 수있다.







+ Recent posts