git을 사용하고 있지만 평소에 궁금했던 또는 사용하지 못했던 기능이 있었을까? 리마인드 한다는 마음으로 git에 대한 내용 용어 및 내용 정리. 순서는 무의미함
merge
1
$ git merge <branchname> # 현재 작업 중인 브랜치에 <branchname>의 브랜치를 끌어와 병합
git add
git에서 파일 기록을 추적하도록 추가
.gitignore
- gitignore guide
- gitignore generator
- 언어, OS, IDE를 입력하면
.gitignore
파일을 자동으로 생성
- 언어, OS, IDE를 입력하면
conflict
- git이 해당 행이 어떤 의미를 지니고 있는지 알 수 없으므로 어떤 수정 사항을 선택할 것인지 개발자가 선택
- 두 브랜치 내용 중에 하나를 선택
- 두 수정 내역을 합침
1
CONFLICT (content): Merge conflict in .py Automatic merge failed: fix conflicts and then commit the result
$ git commit -m conflict resolved
로 conflict을 해결한 이후에 commit을 하자. (commit 할때는 항상 메시지가 고민)
git log
- 어떤 작업 후에 커밋했는지 확인
- git log 명령어 옵션
-p
: 각 커밋에 적용된 실제 변경 내용을 확인--word-diff
: diff 명령의 실행 결과를 단어 단위 확인--stat
: 각 커밋에서 수정된 파일의 통계 정보를 확인--name-only
: 커밋 정보 중에서 수정된 파일의 목록만 확인--relative-date
: 상대적인 시간을 비교해서 확인 (1일전, 1주일전))--graph
: 브랜치 분기와 변합 내역을 그래프 형태로 확인 (브랜치 확인시 유용)
Github
- github guides
- github flow, github pages, git handbook 등에 대해서 설명
좋은 코드를 작성하는 방법
- 다른 사람의 코드를 읽어보고
- 코드를 많이 작성하고
- 내 코드와 다른 사람의 코드를 비교해서 생각해보고
원격
git fetch
- 로컬 저장소와 원격 저장소의 변경사항이 다를때 이를 비교 대조하고, git merge 명령어와 함께 최신 데이터를 반영하거나 충돌 문제 등을 해결
- 내가 로컬에서 작업하고, 다른 협업자가 원격 저장소를 먼저 변경하면 push를 허용하지 않음, 이때 로컬 저장소의 커밋들을 원격 저장소와 맞춰야 하는데 이때 하는게 fetch
- vs
$ git pull
- pull은 원격 저장소의 정보를 가져오면서 자동으로 로컬 브랜치에 병합까지 수행 (어떤 내용이 변경되었는지 알수 없음)
- fetch를 통해 정보 가져오고 수동으로 병합하는 방법을 추천
- fetch 하는 순서
- push fail
- fetch
- branch -a
- git merge origin/master
- 로컬 master와 remote의 master를 병합
- git diff <– pull을 했다면 병합을 자동으로 하기 때문에 어떤 변경이 있는지 모른다.
- git commit
- git push
고급
- 명령어
git tag
: 커밋을 참조하기 쉽도록 알기 쉬운 이름을 붙인다.git commit --amend
: 같은 브랜치 상에 있는 최종 커밋을 취소하고 새로운 내용을 추가하거나 설명을 덧붙인 커밋을 할 수 있다. (예: author 변경)git revert
: 이전에 작성한 커밋을 지운다. (특정 커밋의 내용을 지우는 새로운 커밋을 만들어 지운 내역을 모든 사람이 알 수 있도록)git reset
: 어떤 커밋을 버리고 이전의 특정 버전으로 다시 되돌릴 때 사용한다.git revert
와 다른 점은 지운 커밋 내역을 남기지 않는다는 점git checkout HEAD --filename
: 아직 커밋하지 않은 변경 내역을 취소한다.git rebase
: git merge 처럼 병합할때 사용한다. 하지만 브랜치가 많을 경우 브랜치 이력을 확인하면서 병합git rebase -i
: 서로 다른 두개의 커밋 내역을 합친다.
tag
- x,y,z
- x는 기존과 호환 되지 않는 변경이 발생할때 증가
- y는 기존과 호환 되며, 새로운 기능이 추가될 때 증가
- z는 기존과 호환 되며, 버그 수정 등이 될 때 증가
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# tag 추가하기
$ git tag <tagname>
$ git tag -a <tagname> # 최근 커밋에 tag +annotated
$ git tag -a <taganame> <checksum> # checksum에 tag +annotated
# 확인
$ git show <tagname>
$ git log --decorate -1
# 태그 리스트 확인
$ git tag -l
# tag와 커밋 checksum 확인
$ git show-ref --tags
# 특정 커밋에 태그를 붙이는 방법 (커밋 checksum 값 필요)
$ git log -2 # checksum의 값을 확인
$ git tag 0.9 <checksum>
$ git show-ref --tags # 태그 붙은것을 확인
git commit –amend
- 마지막 커밋 메시지를 수정하는 방법
1
$ git commit --amend
- 마지막 커밋과 커밋하지 않은 상태에 있는 변경 내역이 서로 합쳐진 새 커밋 생성
- 아무런 변경 내역을 만들지 않고 명령어를 실행하면 커밋 메시지만 변경하는 효과
- 최종 커밋을 수정하는 것이 아니라 최종 커밋을 대체하는 새로운 커밋을 생성
git revert
- 공개된 커밋 내역을 수정 (되도록이면 안하는게)
- 커밋으로 발생한 변경 내역의 반대 커밋을 한다. (추가한 코드 제거, 제거한 코드 추가)
- 되돌리는 것이 아니라 되돌리는 것 같은 효과를 내는 것
1
2
3
4
$ git revert <commit checksum>
# 최근 변경 이력 확인
$ git log -5
git revert
를 실행한 시점부터 대상 커밋(checksum으로 넣는 커밋)까지 변경 내역을 거꾸로 적용하는 새 커밋을 생성
git reset
- 이전 작업 결과를 저장한 상태로 되돌리기
- 어떤 특정 커밋을 사용하지 않게 되어 다시 되돌릴 때 사용
vs revert
revert
이전 커밋을 남겨두는 명령어reset
이전 커밋을 남기지 않고 새로운 커밋을 남긴다는 차이
- 커밋인 HEAD의 위치, 인덱스(실제 커밋 전 변경 내역을 담는 준비 영역, git add 명령시에 이 영역으로 이동), 작업하는 저장소 디렉터리 등도 함께 되돌릴지 선택하기 위한 모드를 지정가능
- hard: 완전히 되돌림
- mixed: 인덱스의 상태를 되돌림. (default)
- soft: 커밋만 되돌림
- 명령어 옵션
^ 혹은 ~
:~
은 커밋 내역 하나를 의미, 표시한 수 만큼 되돌린다.ORIG_HEAD
: 지운 커밋 내역을 보관, 해당 명령을 통해git reset
명령으로 지운 커밋을 되돌릴 수 있다.
1
2
3
4
5
$ git reset --soft HEAD~~~
$ git reset --soft ORIG_HEAD # 원래 상태로 되돌리기
$ git reset --hard HEAD~~~
$ git reset --hard ORIG_HEAD
git checkout HEAD –filename
- 특정 파일을 최종 커밋 시점으로 되돌리기
- 파일 하나를 대상으로 변경 내역을 통째로 원래대로 (변경 직전의 최종 커밋 시점으로) 되돌릴 때 사용할 수 있는 명령어
1
$ git checksum HEAD --<filename>
vs git reset
reset
: hard모드가 아니라면 저장소 디렉토리 파일 내용은 명령을 실행한 시점 그대로 남는다. git reset 명령으로 되돌린 다음에 필요한 부분만 수정 작업하고 다시 커밋 가능, 커밋된 변경 내역이 파일에 그대로 남는다.checkout
: 파일을 완전하게 대상 커밋의 시점으로 돌린다. 이후 커밋된 변경 내역이 사라진다.
git rebase
- rebase(=re 다시, base를 정한다.)
- 브랜치 이력을 확인하면서 병합
- 푸시하기 전에는 로컬 저장소에 있던 커밋을 깔끔하게 정리해서 푸시
- 명령어 옵션
git rebase --continue
: 충돌 상태를 해결한 후 계속 작업을 진행git rebase --skip
: 병합 대상 브랜치의 내용으로 강제 병합을 실행, 즉 여기서 명령을 실행하면 master 브랜치를 강제로 병합한 상태가 된다. 또한 해당 브랜치에서는 다시git rebase
명령을 실행할 수 없다.git rebase --abort
: 명령을 취소
(hotfix) rebase (onto) master
- 현재 작업중인 브랜치의 base를 master로 다시 설정
git rebase
명령을 실행하면 무조건fast-forward
가 가능하지만, 이런 경우 병합 커밋을 남기는게 좋다. (master의 커밋 뒤에 rebase되는 커밋들이 붙음)- 병합 흔적을 명시적으로 커밋 그래프에 남기는게 좋다.
$ git checkout master; git merge hotfix --no--ff
명령을 실행
git rebase -i
- i, interactive
- 상호 작용하면서 rebase할 커밋을 선택
- 커맷 내역 합치기는 방법
1
$ git rebase -i HEAD~~~
- 원칙
- 남기는 커밋 메시지 앞에는 pick
- 없애는 커밋 메시지 앞에는 fixup
- checksum은 그대로
- 커밋 메시지를 새롭게 수정못함
- 여러개의 커밋 중에서 필요한 것을 고른 후에 새롭게 커밋
commit
- 커밋은 어떤 상황에서 해야 할까? 커밋은 프로젝트에서
의미
가 있는 최소한의 단위를 말하고,의미
를 가질 수 있게 되는 시기라면 언제든지 커밋을 권장한다. - 커밋 단위
- 여러 파일을 수정하더라도 그 의도는 단 하나여야 한다.
- 파일을 하나만 수정하더라도 두 개 이상의 의도가 있다면 하지 말아야 한다. (버그와 새기능 추가를 동시에 하지 않아야 한다.)
- 커밋 메시지 작성 규칙
- 메시지 작성 방식
- https://wiki.openstack.org/wiki/GitCommitMessages
1
2
[category] - [simple message]
[detailed description]
- category
- fix: 잘못된 부분 수정
- add: 기능 추가
- mod: 코드 수정
- rm : 기능 삭제
- message
- 커밋에 대한 간단한 한 줄 설명을 작성 (약 70자)
- detailed description
- 커밋의 자세한 내용을 기술 (왜 커밋 했는지, 버그 수정의 경우 원래 어떤 문제가 있었는지, 사용중인 이슈 트래커가 있다면 해당 이슈의 하이퍼링크를 포함)
branch
- 작업 흐름의 내용, 어떤 목적으로 브랜치를 만들었는지 바로 알수 있도록
- 이름 작성 규칙 #
- 이름 작성 규칙 (카테고리(=디렉토리))
- new: 새 기능 추가가 목적인 브랜치
- test: 무언가를 테스트하는 브랜치(새 라이브러리, 배포 환경, 실험 등)
- bug: 버그 수정이 목적인 브랜치
1
2
3
4
new/feat-foo
new/feat-bar
but/critical-thing
test/awesome-new-library
프로젝트 유형별 협업 흐름
- 어떤 브랜칭 생성 규칙을 선택할 것인가
- (데스크톱 앱)git-flow, (웹)github-flow, (모바일 앱)gitlab-flow
git-flow
- develop 브랜치를 중심으로 feature 브랜치들을 통해 기능 추가, release 브랜치를 통해 배포 준비와 코드의 버그 수정하며, master로 배포하고, hotfix로 배포된 버전의 버그를 수정해 master와 develop 브랜치에 반영하는 것을 반복
- 브랜치 종류
- develop: 하나만 존재, 여기서 모든 개발이 시작 (이 브랜치는 오직 병합만 커밋)
- feature: 여러개 존재 가능, develop 브랜치를 기반으로 새로운 기능 개발이나 버그 수정, 각각의 브랜치는 하나의 기능(의도)만을 맡는다.
- release: develop 브랜치에서 갈라져 나와 배포를 준비하는 브랜치 (오로지 버그만 수정), 배포본의 완성도를 높이는 브랜치
- master: 실제 배포되는 버전이 있는 브랜치 (release, hotfix 브랜치와만 관계, 오직 병합만 커밋)
- hotfix: 현재 배포 중인 코드에 버그가 있어 급히 수정하고 내용은 master와 develop 브랜치에만 반영
- 특징
- 작업 흐름은 주기적으로 작업 결과를 배포하는 프로젝트의 경우 적합
- 매우 견고한 코드를 생산하면서 배포 간격이 충분히 긴 프로그램이나 솔루션을 다루는 프로젝트에 적합
- 빠른 개발과 배포에는 알맞지 않음 (하루에도 몇번씩 작업 결과를 배포해야 하는 웹 서비스 등에는 알맞지 않다.)
github-flow
- git-flow의 단점을 해결하고자 github에서 사용하는 github-flow
- 브랜치 종류
- master: 언제나 배포할 수 있는 상태로 유지되는 브랜치 (보통 하나만 존재, 오직 병합 커밋만 할 수 있다.)
- feature: 여러개 존재가능, 새 기능을 추가하거나, 버그를 수정하거나, 그 외의 모든 코드 수정을 담당하는 브랜치 그룹. 단 한번에 하나의 의도만을 구현하는 브랜치 그룹이며 그에 따라 이름 짓기가 중요한 브랜치 그룹
- 특징
- 빠른 기능 추가와 수정이 필요한 분야에 적합
- 웹 애플리케이션 등이 이 작업 흐름을 적용하기에 적합
- 간단하고 기능의 추가 완료와 배포가 바로 연동되는 가볍고 작은 빠른 작업 흐름
gitlab-flow
- git-flow와 github-flow의 중간에 위치한 gitlab-flow
- 작업흐름들은 github-flow를 따르지만 배포 과정을 gitlab에서 개선한 작업 흐름
- github-flow의 부족한 점인 안정성과 배포 시기 조절 가능성을 추가 브랜치를 두어 보강하는 전략
- 브랜치 종류
- production: master 브랜치에서 production 브랜치로 병합, git-flow에서 release 브랜치와 비슷한 역할. gitlab-flow에서의 production 브랜치는 오직 배포만을 담당
- 특징
- 사용자의 의도대로 배포할 수 없는 환경
- 스토어에 앱을 배포하는 형태일때 적합 (배포 시기를 정할 수 없음)
- production 브랜치에 배포하고 외부 배포 승인을 대기