[Git] Git 명령어

chaeny·2024년 12월 21일

git에서 commit, branch, fetch, merge, rebase 개념에 대해 공부해보세요.

git commit

https://git-scm.com/docs/git-commit

git-commit - Record changes to the repository

  • 저장소에 변경 사항 기록
  • 현재 인덱스의 내용을 사용해 새 커밋을 생성하며, 변경 사항을 설명하는 로그 메시지를 포함합니다.
  • 새 커밋은 HEAD의 자식이며, 일반적으로 현재 브랜치의 끝(tip)에 위치합니다.
  • 커밋 작성자는 GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, user.name, user.email 등의 환경 변수 또는 설정에서 가져옵니다.
-a, --all: 수정되거나 삭제된 파일을 자동으로 스테이징.
수정된 모든 파일 커밋
git commit -a -m "Update all files"

-m <msg>, --message=<msg>: 커밋 메시지를 명령줄에서 지정.
git commit -m "Add file.txt"

--amend: 마지막 커밋을 수정.
git commit --amend -m "Fix typo"

- --allow-empty: 변경 사항이 없는 빈 커밋 생성.

git branch

https://git-scm.com/docs/git-branch

git-branch - List, create, or delete branches

  • branches 나열, 생성 또는 삭제

브랜치 목록

--list: 브랜치 목록을 출력 (현재 브랜치는 초록색과 *로 표시)
-r: 원격 추적 브랜치 표시
-a: 로컬 및 원격 브랜치 모두 표시
<pattern>: 와일드카드 패턴으로 특정 브랜치만 표시

특정 원격에서 브랜치 목록 확인
git branch -r -l '<remote>/<pattern>'

특정 커밋 관련 필터

--contains <commit>: 해당 커밋을 포함하는 브랜치만 표시
--no-contains <commit>: 해당 커밋을 포함하지 않는 브랜치만 표시
--merged [<commit>]: 병합된 브랜치만 표시
--no-merged [<commit>]: 병합되지 않은 브랜치만 표시

새로운 브랜치 생성

<branchname>: 현재 HEAD를 기준으로 새 브랜치 생성
<start-point>: 특정 시작 지점을 기준으로 생성

태그를 기준으로 브랜치 생성 및 전환
git branch my2.6.14 v2.6.14
git switch my2.6.14

브랜치를 생성하고 즉시 전환하려면 아래 명령을 사용하는 것이 더 간단
git switch -c 

브랜치 이름 변경 및 복사

-m | -M: 기존 브랜치 이름 변경
-c | -C: 기존 브랜치 복사

브랜치 삭제

-d | -D: 브랜치 삭제 (강제 삭제는 -D)
-r: 원격 추적 브랜치 삭제

브랜치 삭제
git branch -d -r origin/todo origin/html origin/man
git branch -D test

git fetch

https://git-scm.com/docs/git-fetch

git-fetch - Download objects and refs from another repository

  • 다른 저장소에서 객체 및 참조 다운로드

    git pull은 fetch + merge를 결합한 명령어지만, fetch는 안전하게 가져오기만 하기 때문에 충돌 위험 없이 원격 상태를 확인하고 싶은 경우 유용하다

기본 사용 형식: git fetch [<options>] [<repository> [<refspec>…​]]
여러 리포지토리 가져오기: git fetch --multiple [<options>] [(<repository> | <group>)…​]
모든 원격 가져오기: git fetch --all [<options>]
DESCRIPTION

기본 원격 트래킹 브랜치 업데이트
git fetch origin

특정 리포지토리 브랜치 확인
git fetch git://git.kernel.org/pub/scm/git/git.git maint
git log FETCH_HEAD

가져오기 범위 제한

--depth=<depth>: 가져오는 커밋 이력을 지정한 깊이로 제한.
--shallow-since=<date>: 특정 날짜 이후 커밋만 포함.
--unshallow: 얕은 리포지토리를 완전한 리포지토리로 변환.

특정 브랜치 가져오기
git fetch origin +seen:seen maint:tmp

관리 옵션

--force: 지역 브랜치 덮어쓰기 강제.
--prune: 원격에 없는 로컬 참조 제거.
--tags: 모든 태그 가져오기.

출력 및 디버깅

--dry-run: 실제로 변경하지 않고 가져오기 과정을 시뮬레이션.
--verbose: 자세한 출력.
--progress: 가져오는 진행 상태 표시.

git merge

https://git-scm.com/docs/git-merge

git-merge - Join two or more development histories together

  • 두 개 이상의 개발 내역을 함께 결합
  • 지정된 커밋(보통 다른 브랜치의 헤드)으로부터의 변경 사항을 현재 브랜치에 통합
  • 병합 결과는 새로운 커밋으로 기록되며, 병합된 부모 커밋들의 이름과 사용자 정의 메시지가 포함됨.

다른 브랜치의 변경 사항을 현재 브랜치에 통합하여 병합 커밋을 생성하거나, fast-forward로 브랜치를 업데이트하는 명령어

  • fast-forwared란?
    현재 브랜치가 병합 대상 브랜치에 뒤처져 있을 때, 추가 커밋 없이 브랜치를 최신 상태로 업데이트하는 방식 (새로운 병합 커밋을 만들지 않고 브랜치 포인터만 이동)
git merge [<options>] [<commit>…​]
git merge (--continue | --abort | --quit)
기본 브랜치 병합
git merge fixes enhancements

특정 전략을 사용한 병합
git merge -s ours obsolete

병합 후 커밋 보류
git merge --no-commit maint

병합 동작 설정

--commit / --no-commit: 병합 결과를 바로 커밋하거나 멈춤.
--ff / --no-ff / --ff-only: fast-forward 병합 허용 여부 지정.
--squash: 병합 커밋 없이 단일 커밋으로 변경 사항 적용.

병합 실패 시

git merge --abort: 병합 전 상태로 복구.
git merge --continue: 충돌을 해결한 후 병합을 완료.


충돌 시 파일에 <<<<<<<, =======, >>>>>>> 마커가 추가됨.
git merge --abort: 병합 전 상태로 돌아감.
git merge --continue: 충돌 해결 후 병합을 완료.
도구 사용: git mergetool, git diff, git log --merge.

충돌 해결 및 메시지

--edit / --no-edit: 병합 커밋 메시지 편집 여부 설정.
-m <msg>: 병합 커밋 메시지 지정.
--stat: 병합 후 변경 사항 통계 표시.

서명 및 검증

-S[<keyid>] / --gpg-sign: 병합 커밋에 GPG 서명 추가.
--verify-signatures: 병합 대상 브랜치의 서명을 검증.

기타

--abort: 병합 작업 중단 및 원래 상태 복구.
--allow-unrelated-histories: 공통 조상이 없는 히스토리 병합 허용.

git rebase

https://git-scm.com/docs/git-rebase

git-rebase - Reapply commits on top of another base tip

  • 다른 기본 팁 위에 커밋을 다시 적용
  • 현재 브랜치의 변경사항을 새로운 기반 브랜치 위로 재배치.

    현재 브랜치의 커밋 기록을 다른 브랜치 기반으로 재정렬하여 커밋 히스토리를 깔끔하게 만드는 명령어

<branch>가 명시되면 git switch로 해당 브랜치로 이동 후 진행.
<upstream>이 생략되면 브랜치 설정에 따라 자동 결정.

--onto: 특정 시작점을 지정하여 커밋을 재배치.
--interactive(-i): 대화형 모드에서 커밋 순서 변경, 삭제, 스쿼시 가능.
--continue: 충돌 해결 후 리베이스 계속.
--abort: 리베이스 취소, 원래 상태로 복원.
--skip: 충돌이 난 커밋 건너뛰기.
--edit-todo: 대화형 리베이스에서 TODO 리스트 수정.
--autosquash: 자동으로 "fixup!" 또는 "squash!" 커밋을 앞 커밋에 합치기.

충돌 시

충돌 난 파일 수정 후 git add로 해결 기록
git rebase --continue로 재시작
취소하려면 git rebase --abort
  • 리베이스 중에는 병합 커밋이 제거된다
  • 리베이스로 인해 다른 사용자의 작업 히스토리가 망가질 수 있다
  • 리베이스 도중 중단 시 .git/rebase-apply 폴더에서 작업 상태 확인이 가능하다.
master 브랜치 위에 subsystem 브랜치가 생성되고, subsystem 브랜치 위에 topic 브랜치가 있습니다

o---o---o---o---o---o---o---o  master
 \
  o---o---o---o---o  subsystem
			   	   \
			        *---*---*  topic

subsystem 브랜치를 master 브랜치 위로 Rebase
subsystem 브랜치가 master 브랜치 위로 rebase 되어 새로운 커밋이 생성됩니다.
이제 subsystem 브랜치는 o'로 표시된 새로운 커밋 시리즈를 포함합니다.

    o---o---o---o---o---o---o---o  master
	 \			                 \
	  o---o---o---o---o	  			o'--o'--o'--o'--o'  subsystem
			           \
			    		*---*---*  topic
     
topic 브랜치가 subsystem 위에서 계속 작업됨
topic 브랜치는 여전히 이전 subsystem 커밋 기반 위에 있으므로, 
나중에 subsystem과 병합하면 중복된 커밋이 발생합니다.

    o---o---o---o---o---o---o---o  master
	 \			 				 \
	  o---o---o---o---o	  		  o'--o'--o'--o'--o'--M	 subsystem
			   		   \			                /
			             *---*---*-..........-*--*  topic              

이 구조는 topic 브랜치를 subsystem의 새로운 커밋 기반 위로 rebase 하지 않으면 중복된 커밋 문제를 발생시키게 됩니다. 따라서 적절히 git rebase 명령어를 사용하여 커밋 히스토리를 정리하는 것이 중요합니다.

정리

Commit

  • 변경된 코드를 저장소에 기록하여 이력을 남기고 추적 가능하게 만든다
  • 프로젝트의 상태를 저장하고 히스토리를 남기기 위한 단위 작업이다

Branch

  • 독립적인 작업 공간을 제공하여 여러 작업을 병렬적으로 진행할 수 있게 한다
  • 코드 변경 작업을 분리해 관리할 수 있는 독립적인 작업 공간이다

Fetch

  • 원격 저장소의 최신 상태를 로컬로 가져와 업데이트 확인한다
  • 원격 저장소의 변경 사항을 로컬 저장소로 가져오는 작업이다

Merge

  • 여러 브랜치에서 작업한 내용을 병합하여 하나로 통합한다
  • 브랜치 간의 작업 내용을 합치기 위한 작업이다

Rebase

  • 브랜치를 다른 브랜치의 최신 상태로 정렬하거나 커밋 히스토리를 깔끔하게 정리한다
  • 브랜치 기반을 재배치하거나 커밋 히스토리를 정리하기 위한 작업이다

merge와 rebase의 차이

git push 시 conflict가 나서 merge와 rebase를 해보았다.
차이를 알아보자

merge

  • Change hint 이후 충돌 → Merge
  • 두 브랜치를 Merge하여 하나로 합친다
  • 기존의 커밋 내역은 그대로 보존되며, 새로운 병합 커밋이 생성된다

rebase

  • Enter plants2 이후 충돌 → Rebase
  • 현재 브랜치의 커밋들이 대상 브랜치의 커밋들 다음으로 재배치되어, 두 브랜치가 시간 순서대로 개발된 것처럼 히스토리를 단순화한다
  • 히스토리를 선형적으로 만들어 커밋 로그를 깔끔하게 정리할 수 있다.
  • 하지만 커밋의 해시값이 변경되므로, 공유하는 브랜치에 Rebase를 사용할 경우 주의해야한다.

Rebase는 커밋 히스토리를 재작성하므로, 이미 공유된 브랜치에서 사용할 경우 협업에 혼란을 줄 수 있습니다. 따라서 공개 저장소의 브랜치에서는 Merge를, 개인적인 로컬 브랜치에서는 Rebase를 사용하는 것이 일반적입니다.

merge는 분기와 병합이 명확히 드러나는 반면, rebase는 직선적인 히스토리를 만듭니다.
merge는 브랜치 간의 분기를 보존하지만, rebase는 분기를 제거합니다.
merge는 새로운 커밋을 생성하여 두 브랜치를 합치지만, rebase는 기존 커밋을 변경하여 브랜치를 합칩니다

https://theyim.tistory.com/49
https://jongtachi.tistory.com/150
https://ainayoon.tistory.com/15

커밋의 해시값

리베이스와 같은 작업에서 기존 커밋의 내용(부모, 시간, 수정 내용 등)이 변경되면서 새로운 해시값이 생성되는 것

협업 중인 동료는 기존 해시값을 참조하므로 충돌이 발생하거나 혼란을 초래할 수 있다

정리

Merge는 분기점과 병합 과정을 보존하며 기록하고, Rebase는 커밋을 재작성해 깔끔한 히스토리를 만든다

reset과 revert의 차이

reset

시간을 아예 과거의 특정 사건(commit)으로 되돌린다.

  • 아예 현재가 없었던 것 처럼 원하는 과거로 돌아갈 수 있다. 정말 말 그대로 '리셋'이다.
  • 이력을 남기지 않는다. 따라서 현재까지의 commit 이력을 남기지 않고 원하는 시점으로 완전히 되돌아가고 싶을 때 사용할 수 있다.
  • 커밋 히스토리를 깔끔하게 유지할 수 있고, 혼자 작업할 때 편하게 되돌아갈 수 있다는 장점이 있다. 그러나 타인과 같은 브랜치에서 함께 작업할 때 커밋이 뒤섞여버릴 수 있다는 위험한 단점이 있다.

revert

현재에 있으면서 과거의 특정 사건(commit)들만 없던 일로 만든다.

  • 과거로 돌아가겠다는 이력을 남겨두고 원하는 시점으로 돌아간다.
  • 즉, 이전의 commit 내역을 남겨두고 새로운 commit을 생성하면서 과거로 돌아가게 된다.
  • 중간에 무슨 문제가 있었는지, 왜 돌아갔는지 등의 기록이 가능하다는 장점이 있다. 또한 다른 사람과 같은 브랜치에서 함께 작업할 때 코드 충돌을 최소화할 수 있다.

협업프로젝트에서 다른 팀원과 같은 branch를 공유하는 상황일때, 가급적 revert를 사용한다.

https://velog.io/@njs04210/Git-reset

0개의 댓글