티스토리 뷰

Git

Git 기초

J-Mandu 2023. 3. 6. 09:40

설정

config

$ git config --global user.name "{사용자 이름}"
$ git config --global user.email {이메일}

Git을 설치하고 나서 가장 먼저 해야 하는 것은 사용자이름과 이메일 주소를 설정해야 합니다.
Git은 커밋할 때마다 이 정보를 사용하고 한 번 커밋한 후에는 정보를 변경할 수 없습니다.

$ git config --list
credential.helper=osxkeychain
core.excludesfile=/Users/{유저}/.gitignore_global
core.editor=vim
user.name={사용자 이름}
user.email={이메일}
init.defaultbranch=main
filter.lfs.process=git-lfs filter-process
filter.lfs.required=true
filter.lfs.clean=git-lfs clean -- %f
filter.lfs.smudge=git-lfs smudge -- %f
commit.template=/Users/minkyujin/.stCommitMsg
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
core.ignorecase=true
core.precomposeunicode=true

$ git config user.name
jin

설정한 정보를 확인하고 싶을 때 --list 옵션을 줍니다.
git config 명령으로 특정 key에 대한 값을 확인할 수도 있습니다.

저장소 만들기

init

$ cd {디렉토리}

$ git init
{디렉토리} 안의 빈 깃 저장소를 다시 초기화했습니다

기존 디렉토리를 Git 저장소로 만들때 쓰는 명령어이고 해당 디렉토리에 .git 하위 디렉토리를 만듭니다.
.git 디렉토리에는 저장소에 필요한 뼈대 파일이 들어있습니다.

clone

// 디렉토리 명을 생략시 가져올 저장소 프로젝트 명으로 디렉토리가 생성됩니다.
$ git clone {저장소 주소}

$ git clone {저장소 주소} {디렉토리 명}

git 저장소를 복사하고 싶을 때 쓰는 명령어이고 프로젝트의 모든 데이터를 가져옵니다.

저장소에 저장하기

git life cycle

status

$ git status 
현재 브랜치 main

아직 커밋이 없습니다

추적하지 않는 파일:
  (커밋할 사항에 포함하려면 "git add <파일>..."을 사용하십시오)
    f1.txt

커밋할 사항을 추가하지 않았지만 추적하지 않는 파일이 있습니다 (추적하려면 "git add"를 사용하십시오)

파일의 상태를 확인하고 싶을 때 쓰는 명령어 입니다.
Untracked, Modified, Staged 상태들의 파일들을 보여줍니다.

status 내부 동작 원리

  • 커밋할 사항이 없는 경우(clean) : Warking Directory, Staging Area(index), Local Repository(최신 Commit 개체의 Tree 개체)
    내용이 모두 같을 경우
  • 추적하지 않는 상태(Untracked) : StagingArea(index)에 Warking Directory의 파일들이 없는 경우
  • 커밋하도록 정하지 않은 변경사항(Modified) : Stagin gArea(index)과 Warking Directory의 파일 내용들이 다른 경우
  • 커밋할 변경 사항이 있는 경우(Staged) : Warking Directory, Staging Area(index)의 파일내용은 같지만
    Local Repository(최신 Commit 개체의 Tree 개체)의 파일 내용이 다를 경우

add

$ git add {파일명}
현재 브랜치 main

아직 커밋이 없습니다

커밋할 변경 사항:
  (스테이지 해제하려면 "git rm --cached <파일>..."을 사용하십시오)
    새 파일:       f1.txt

파일을 새로 추적하고 싶을 때 쓰는 명령이고 commit에 추가될 Staged 상태입니다.
이미 Tracked 상태이지만 수정했을 경우 Staged 상태로 만들때도 사용합니다.
상태를 확인하는 명령어(status)를 사용하여 추적 상태를 볼수 있습니다.
Staged 상태 : Staging Area에 넣은 상태

add 내부 예상 동작 순서

// object 파일들
$ find .git/objects -type f
.git/objects/b6/8025345d5301abad4d9ec9166f455243a0d746
.git/objects/78/981922613b2afb6025042ff6bd878ac1994e85

// object 내용
$ git cat-file -p 78981922613b2afb6025042ff6bd878ac1994e85
a

// 인덱스
$ git ls-files -s
100644 78981922613b2afb6025042ff6bd878ac1994e85 0    f1.txt
100644 b68025345d5301abad4d9ec9166f455243a0d746 0    f2.txt
100644 78981922613b2afb6025042ff6bd878ac1994e85 0    f3.txt
  1. 파일 내용과 몇가지 부가적인 정보를 압축하여 그 결과를 해쉬 알고리즘(sha1) 통하여 해쉬 값을 얻습니다.
  2. .git/objects/{해쉬 값 앞자리 2개}/{나머지 해쉬 값} 디렉토리와 파일을 만들고 파일내용을 저장합니다.
  3. .git/index 파일에 object 파일명과 실제 파일명(add 한 파일명) 적어둡니다.

위와 같이 f1.txt와 f3.txt는 파일 내용이 같아서 인덱스에서 같은 obejct를 가르킵니다.

commit

// 쉘의 EDITOR 환경 변수에 등록된 편집기로 편집기가 실행되며 아래와 같은 메세지가 포함됩니다.
// git config --global core.editor 명령으로 어떤 편집기를 사용할지 설정할 수 있습니다.
$ git commit
# 변경 사항에 대한 커밋 메시지를 입력하십시오. '#' 문자로 시작하는
# 줄은 무시되고, 메시지를 입력하지 않으면 커밋이 중지됩니다.
#
# 현재 브랜치 main
# 커밋할 변경 사항:
#       수정함:        f1.txt
#

$ git commit -m {커밋 메세지}
[main (최상위-커밋) 0db3db0] 1
 1 file changed, 1 insertion(+)
 create mode 100644 f1.txt

$ git commit -am {커밋 메세지}

$ git commit --amend

Staging Area에 있는 변경사항에 대하여 버전을 만들고 local 저장소에 저장하고 싶을 때 쓰는 명령입니다.
커밋 메세지는 Angular 커밋 메세지 규약을 보고 작성합니다.
-a 옵션을 추가하여 Tracked 상태인 파일들을 자동으로 Staging Area에 넣어줍니다.
-m 옵션을 추가하여 인라인으로 메세지를 첨부할 수 있습니다.
--amend 옵션을 추가하여 이전 커밋을 덮어쓸 수 있습니다.

commit 내부 예상 동작 순서

Git 저장소 내의 모든 개체.

// 현재 최신 커밋의 tree 개체 내용보기
$ git cat-file -p main^{tree}
100644 blob 78981922613b2afb6025042ff6bd878ac1994e85    f1.txt
100644 blob 2795c87096b42d4b7b8fda82a67dabded5c72c97    f2.txt
100644 blob 78981922613b2afb6025042ff6bd878ac1994e85    f3.txt
100644 blob 8baef1b4abc478178b004d62031cf7fe6db6f903    f4.txt

// 커밋 개체 내용보기
$ git cat-file -p 95d8893506c3c7c50d48b645e7a1f0bec74f1cb1
tree 1f1862a4f1875b673a186e10d99ac4b7044dc852
parent 527f5c509de3b26f3dee8eb432db618cbfa32cfb
author road-jin <rjswmtk@gmail.com> 1677822895 +0900
committer road-jin <rjswmtk@gmail.com> 1677822895 +0900

3

// 위의 커밋메시지에 있는 tree 개체 내용 보기
$ git cat-file -p 1f1862a4f1875b673a186e10d99ac4b7044dc852
100644 blob 78981922613b2afb6025042ff6bd878ac1994e85    f1.txt
100644 blob 2795c87096b42d4b7b8fda82a67dabded5c72c97    f2.txt
100644 blob 78981922613b2afb6025042ff6bd878ac1994e85    f3.txt
100644 blob 8baef1b4abc478178b004d62031cf7fe6db6f903    f4.txt
  1. .git/objects/ 디렉토리에 Staging Area(index)의 상태대로 Tree object를 만듭니다.
  2. .git/objects/ 디렉토리에 1번의 Tree 개체와 이전 Commit 개체와 Author/Committer 정보, 커밋 메시지를 토대로 Commit 개체를 만듭니다.

Tree 개체 : SHA-1 포인터, 파일 모드, 개체 타입, 파일 이름 순으로 작성되어 있고 Tree 개체를 통해서 커밋 시점의 파일들을 알 수 있습니다.
그리고 해당 시점을 찍어서 나타낸다는 의미로 스냅샷이라고 하고 스냅샷을 가지고 있는 구조를 Tree 개체라고 합니다.

Commit 개체 : Tree 개체, parent(이전 Commit 개체이며 없으면 생략), Author/Committer 정보, 줄바꿈,
commit message 순으로 작성되어 있습니다.

Author/Committer 정보 : Git 설정에서 했던 user.name과 user.email 정보를 가져옵니다.

Object 파일 종류

  • blob : 파일의 내용을 가지고 있습니다.
  • Tree 개체
  • Commit 개체

되돌리기

reset

// 원본 파일 생성
$ vi f1.txt
init

$ git add f1.txt

$ git commit 1

// 로컬 저장소에 저장할 파일
$ vi f1.txt
repository

$ git commit -am 2

// Staging Area(index)에 저장할 파일
$ vi f1.txt
index

$ git add f1.txt

// working directory에 저장할 파일
$ vi f1.txt
working directory

// 로컬 저장소의 f1.txt 내용 보기
$ git cat-file -p HEAD                                           
tree 7b60d3bfdfa15b16c74154cd889a52fd089c5117
author road-jin <rjswmtk@gmail.com> 1677997501 +0900
committer road-jin <rjswmtk@gmail.com> 1677997501 +0900

1

$ git cat-file -p 7b60d3bfdfa15b16c74154cd889a52fd089c5117
100644 blob 09d06c8f2087539716887077f2c0f8df5ab0ee24    f1.txt

$ git cat-file -p 09d06c8f2087539716887077f2c0f8df5ab0ee24
repository

// Staging Area(index)의 f1.txt 내용 보기
$ git ls-files -s
100644 9015a7a32ca0681be64471d3ac2f8c1f24c1040d 0    f1.txt

$ git cat-file -p 9015a7a32ca0681be64471d3ac2f8c1f24c1040d 
index

// working directory의 f1.txt 파일 내용 보기
$ cat f1.txt
working directory

$ git log
commit 1290e14f1e6d56a93f3e3e0e7c403ad15b5c4ca2 (HEAD -> main)
Author: road-jin <rjswmtk@gmail.com>
Date:   Sun Mar 5 15:38:06 2023 +0900

    2

commit 6df57e7dd878e6e0c08b93cda9ca733b4e882591
Author: road-jin <rjswmtk@gmail.com>
Date:   Sun Mar 5 15:37:50 2023 +0900

        1

// HEAD가 참조하고 있는 브랜치 파일내용을 해당 커밋개체로 수정합니다.
$ git reset --soft 6df57e7dd878e6e0c08b93cda9ca733b4e882591

$ cat .git/refs/heads/main
6df57e7dd878e6e0c08b93cda9ca733b4e882591

$ git diff
diff --git a/f1.txt b/f1.txt
index 9015a7a..31e5f9a 100644
--- a/f1.txt
+++ b/f1.txt
@@ -1 +1 @@
-index
+working directory

// repository에 reset 하기 전의 커밋개체로 수정(원상 복구)
$ git reset --soft ORIG_HEAD

// soft 옵션 + index 파일내용을 해당 커밋개체의 tree 개체를 기반으로 수정합니다.
$ git reset --mixed 6df57e7dd878e6e0c08b93cda9ca733b4e882591

$ git diff
diff --git a/f1.txt b/f1.txt
index b1b7161..31e5f9a 100644
--- a/f1.txt
+++ b/f1.txt
@@ -1 +1 @@
-init
+working directory

// working directory, index, repository 전부 f1.txt 파일내용이 repository로 변경
git reset --hard ORIG_HEAD

reset mode

이전으로 돌아가고 싶을 때 쓰는 명령 입니다.
reset을 할 경우 .git/ORIG_HEAD 파일이 생성되고 내용에 reset 하기전의 커밋개체가 작성 되어있습니다.

Mode 옵션

기본값은 --mixed 입니다.

  • --soft {커밋 개체 해쉬 값} : HEAD가 참조하고 있는 브랜치 파일내용을 해당 커밋개체 해쉬 값으로 수정합니다.
    ex) working directory와 staging area에는 남기고 다시 작업하고 싶을경우(커밋 취소)
  • -- mixed {커밋 개체 해쉬 값} : soft 옵션 + index 파일내용을 해당 커밋개체의 tree 개체를 기반으로 수정합니다.
    ex) working directory 남기고 다시 작업하고 싶을 경우(Add 취소)
  • -- hard {커밋 개체 해쉬 값} : soft 옵션 + mixed 옵션 + 실제 파일 내용을 해당 커밋개체의 내용으로 수정합니다.
    ex) 커밋 후 작업했던 내용들을 전부 날리고 다시하고 싶을 경우

revert

$ vi f1.txt
init

$ git add f1.txt

$ git commit -m 1

$ vi f1.txt
init
test

$ git commit -am 2

$ git log
commit 80d55e3a5c929264244ae89dfa5877f4c0289705
Author: road-jin <rjswmtk@gmail.com>
Date:   Sun Mar 5 20:56:49 2023 +0900

    2

commit 47d63f089cf93d4218630191609372326cf06a6b
Author: road-jin <rjswmtk@gmail.com>
Date:   Sun Mar 5 20:56:34 2023 +0900

    1

$ git revert 80d55e3a5c929264244ae89dfa5877f4c0289705
[main ebc07f9] Revert "2"
 1 file changed, 1 deletion(-)

$ cat f1.txt
init

$ git log
commit ebc07f90ef14f3c3a4218424e641e1b36d9b7bf3 (HEAD -> main)
Author: road-jin <rjswmtk@gmail.com>
Date:   Sun Mar 5 21:09:19 2023 +0900

    Revert "2"

    This reverts commit 80d55e3a5c929264244ae89dfa5877f4c0289705.

commit 80d55e3a5c929264244ae89dfa5877f4c0289705
Author: road-jin <rjswmtk@gmail.com>
Date:   Sun Mar 5 20:56:49 2023 +0900

    2

commit 47d63f089cf93d4218630191609372326cf06a6b
Author: road-jin <rjswmtk@gmail.com>
Date:   Sun Mar 5 20:56:34 2023 +0900

    1

해당 커밋 개체의 변화만 되돌리고 싶을 때 쓰는 명령어 입니다.
해당 커밋 개체의 변화만 되돌리고 커밋개체를 새로 생성합니다.
만약 47d63f089 커밋 개체로 revert를 할 경우
47d63f089 커밋 이후에 생긴 커밋 개체들의 변화들은 git이 처리하지 못하기 때문에 충돌현상 납니다.
그래서 사용자가 직접 충돌현상을 작업해야 하기 때문에 만약에 47d63f089 revert를 하고 싶으면
최상위 커밋 개체부터 차근차근 revert를 해야합니다.

브랜치 만들기

branch

// 브랜치 보기
$ git brach
* main

// 브랜치 생성
// 커밋 개체 해쉬 값이 없는 경우 최신 커밋 개체로 됨
$ git branch {브랜치 명} [{커밋 개체 해쉬 값}]

// 브랜치 보기
$ git branch
  exp
* main

// 브랜치 삭제
$ git branch -d {브랜치 명}

코드를 통째로 복사하고 나서 원래 코드와는 상관없이 독립적으로 개발하는 것이 브랜치입니다.
현재 브랜치를 모두 보여주는 명령어 입니다.
{브랜치 명} 옵션을 추가하면 브랜치를 생성해 줍니다.
-d {브랜치 명} 옵션을 추가하면 브랜치를 삭제합니다.

branch 내부 동작 원리

// 처음 깃 저장소를 만들시에 생성되는 HEAD
$ cat .git/HEAD
ref: refs/heads/main

// 파일 생성 후 내용 저장
$ vi f1.txt

// Staging Area 추가
$ git add f1.txt

// commit
$ git commit -m 1
[main (최상위-커밋) 07062c5] 1
 1 file changed, 1 insertion(+)
 create mode 100644 f1.txt

// main 브랜치가 어떤 커밋 개체를 가르키는지 확인
$ cat .git/refs/heads/main
07062c5e54b022fecdf6043226d73696f899527e
  • HEAD 파일은 git 저장소를 만들시에 생성되며 현재 브랜치를 나타내는 파일입니다.
  • 브랜치들은 .git/refs/heads/{브랜치 명} 파일을 갖게 되고 커밋개체를 가르킵니다.
    main 브랜치는 커밋을 하고난 후에 파일이 생기며 그 후에 생성되는 브랜치들은
    main 커밋개체를 가르키기 때문에 바로 파일이 생성 됩니다.
  • 해당 브랜치를 이동할 때 HEAD 파일 내용에 이동할 Branch 파일 디렉토리로 수정됩니다.
  • 브랜치에서 커밋할 경우 Branch 파일 내용에 해당 커밋 개체 해쉬 값로 수정됩니다.

switch

// 브랜치 변경
$ git switch exp
'exp' 브랜치로 전환합니다

// 브랜치 생성 후 해당 브랜치로 변경
// 커밋 개체 해쉬 값이 없는 경우 최신 커밋 개체로 됨
$ git switch -c {브랜치 명} [{커밋 개체 해쉬 값}]

브랜치를 변경할 때 쓰는 명령어 입니다.
-c {브랜치 명} 옵션을 추가하여 브랜치를 생성할 수 있고 {커밋 개체 해쉬 값} 옵션을 주어
브랜치가 원하는 시점의 파일들을 가질 수 있게 해줍니다.

브랜치 정보확인

log

// 현재 브랜치의 커밋 목록
$ git log
commit b1a15fcf0dde684c19d8402c24316de2601e8b6f (HEAD -> main)
Author: road-jin <rjswmtk@gmail.com>
Date:   Sat Mar 4 00:05:06 2023 +0900

    4

commit 5a6fc468c7e6187d983e3a43a63dc337ea0aea67
Author: road-jin <rjswmtk@gmail.com>
Date:   Fri Mar 3 19:54:02 2023 +0900

    2

commit 013c5f61c7d303eb3e8ee1f28035747c460099d0
Author: road-jin <rjswmtk@gmail.com>
Date:   Fri Mar 3 19:53:43 2023 +0900

    1

// 모든 브랜치의 커밋 목록
$ git log --branches
commit b1a15fcf0dde684c19d8402c24316de2601e8b6f (HEAD -> main)
Author: road-jin <rjswmtk@gmail.com>
Date:   Sat Mar 4 00:05:06 2023 +0900

    4

commit 9f01c304fd6e1b7a9dafd296383ad1eeea54dd22 (exp)
Author: road-jin <rjswmtk@gmail.com>
Date:   Fri Mar 3 23:26:15 2023 +0900

    3

commit 5a6fc468c7e6187d983e3a43a63dc337ea0aea67
Author: road-jin <rjswmtk@gmail.com>
Date:   Fri Mar 3 19:54:02 2023 +0900

    2

commit 013c5f61c7d303eb3e8ee1f28035747c460099d0
Author: road-jin <rjswmtk@gmail.com>
Date:   Fri Mar 3 19:53:43 2023 +0900

    1

// 모든 브랜치의 커밋 목록을 간략하게 그래프 표시    
$ git log --branches --graph --oneline
* b1a15fc (HEAD -> main) 4
| * 9f01c30 (exp) 3
|/
* 5a6fc46 2
* 013c5f6 1

// 브랜치1에 없고 브랜치2에만 있는 커밋 내용 표시
$git log -p {브랜치1}..{브랜치2}
commit 9f01c304fd6e1b7a9dafd296383ad1eeea54dd22 (exp)
Author: road-jin <rjswmtk@gmail.com>
Date:   Fri Mar 3 23:26:15 2023 +0900

    3

diff --git a/f1.txt b/f1.txt
index 422c2b7..de98044 100644
--- a/f1.txt
+++ b/f1.txt
@@ -1,2 +1,3 @@
 a
 b
+c

브랜치에 대한 커밋 목록을 보고 싶을 때 쓰는 명령어 입니다.
--branches 옵션을 추가하면 모든 브랜치에 대한 커밋 목록을 보여줍니다.
-- graph -- oneline 옵션을 추가하면 모든 브랜치에 대한 커밋 목록을 그래프로 간략하게 표시해줍니다.
-p {브랜치1}..{브랜치2} 옵션을 추가하면 브랜치1에는 없고 브랜치2에는 있는 커밋한 파일들의 내용들을 비교해서 보여줍니다.

diff

$ git diff {브랜치1}..{브랜치2}
diff --git a/f1.txt b/f1.txt
index 422c2b7..de98044 100644
--- a/f1.txt
+++ b/f1.txt
@@ -1,2 +1,3 @@
 a
 b
+c
diff --git a/f2.txt b/f2.txt
deleted file mode 100644
index b0f6d94..0000000
--- a/f2.txt
+++ /dev/null
@@ -1 +0,0 @@
-4444

각각 브랜치에 대한 현재의 커밋 내용을 비교할 때 쓰는 명령어 입니다.

브랜치 합치기

merge

$ git merge {브랜치}
Merge made by the 'ort' strategy.
 f1.txt | 1 +
 1 file changed, 1 insertion(+)

// Fast-forward 전략을 사용하지 않고 merge
$ git merge {브랜치} --no-ff

현재 브랜치에서 {브랜치}의 내용들을 병합할 때 쓰는 명령어 입니다.
merge 전략에 따라 새로운 커밋 개체가 생성되고 커밋 메시지는 자동적으로 쓰여집니다.

merge 전략

  • Fast forward : 현재 브랜치 Head를 merge할 브랜치 Head로 변경하는 전략입니다.
    어떤 브랜치를 사용했고 언제 병합했는지 기록이 남지않습니다.

  • 3-way merge : Fast forward로 merge를 못할 경우 두 브랜치의 공통 조상이 되는 커밋과 두 브랜치의 커밋들을 비교하여
    병합에 반영하고 충돌이 있는 내용은 사용자에게 해결을 맡기고 결과로 새로운 커밋을 생성합니다.

충돌 해결

$ git merge {브랜치}
자동 병합: common.txt
충돌 (내용): common.txt에 병합 충돌
자동 병합이 실패했습니다. 충돌을 바로잡고 결과물을 커밋하십시오.

$ git status
현재 브랜치 main
병합하지 않은 경로가 있습니다.
  (충돌을 바로잡고 "git commit"을 실행하십시오)
  (병합을 중단하려면 "git merge --abort"를 사용하십시오)

병합하지 않은 경로:
  (해결했다고 표시하려면 "git add <파일>..."을 사용하십시오)
    양쪽에서 수정:  common.txt

커밋할 변경 사항을 추가하지 않았습니다 ("git add" 및/또는 "git commit -a"를
사용하십시오)

$ vi common.txt
function b(){
}
<<<<<<< HEAD
function a(master, exp){
=======
function exp(){
>>>>>>> exp
}
function c(){
}

$ git add common.txt

$ git commit

충돌된 파일에서 <<<<<<< HEAD 아래 코드가 현재 브랜치 코드입니다.
======= 구분되어 있으며 구분 문자 바로 아래는 merge할 브랜치(exp)의 코드입니다.
충돌된 파일을 사용자가 직접 수정한 다음 커밋하면 정상적으로 merge가 됩니다.

rebase

$ git rebase {브랜치}
Successfully rebased and updated refs/heads/rb.

C3 에서 변경된 사항을 Patch로 만들고 이를 다시 C4 에 적용시키는 방법이 있다. Git에서는 이런 방식을 Rebase 라고 합니다.
커밋 히스토리를 나란히 만들면서 병합할 때 쓰는 명령어 입니다.
Rebase 할 브랜치에서 명령어 실행하고 {브랜치}는 합칠 브랜치입니다.

공개 저장소에 Push 한 커밋을 Rebase 하지말아야 합니다

충돌 해결

$ git rebase {브랜치}
자동 병합: f1.txt
충돌 (내용): f1.txt에 병합 충돌
error: 다음을 적용할(apply) 수 없습니다: 82aebb4... R1
힌트: Resolve all conflicts manually, mark them as resolved with
힌트: "git add/rm <conflicted_files>", then run "git rebase --continue".
힌트: You can instead skip this commit: run "git rebase --skip".
힌트: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 82aebb4... R1

$ git status
대화형 리베이스 진행 중. 갈 위치는 bf1987c
Last command done (1 command done):
   pick 82aebb4 R1
Next commands to do (2 remaining commands):
   pick eabced7 R2
   pick 0469d04 R3
  (보고 편집하려면 "git rebase --edit-todo"를 사용하십시오)
현재 'rb' 브랜치를 'bf1987c' 위로 리베이스하는 중입니다.
  (충돌을 바로잡고 "git rebase --continue"를 사용하십시오)
  (이 패치를 건너뛰려면 "git rebase --skip"을 사용하십시오)
  (원본 브랜치를 가져오려면 "git rebase --abort"를 사용하십시오)

병합하지 않은 경로:
  (use "git restore --staged <file>..." to unstage)
  (해결했다고 표시하려면 "git add <파일>..."을 사용하십시오)
A
    양쪽에서 수정:  f1.txt

커밋할 변경 사항을 추가하지 않았습니다 ("git add" 및/또는 "git commit -a"를
사용하십시오)
R2

$ vi f1.txt
충돌 수정

$ git add f1.txt

$ git rebase --continue
[HEAD 분리됨 e2e7796] R3
 1 file changed, 1 insertion(+), 1 deletion(-)
Successfully rebased and updated refs/heads/rb.

충돌된 파일에서 <<<<<<< HEAD 아래 코드가 현재 브랜치 코드입니다.
======= 구분되어 있으며 구분 문자 바로 아래는 rebase할 브랜치의 코드입니다.
충돌된 파일을 사용자가 직접 수정한 다음 rebase --continue 명령어를 실행합니다.

브랜치 작업 도중 다른 브랜치 이동

stash

// 임시 저장
$ git stash [push]
Saved working directory and index state WIP on exp: 3f440f9 1

// 최근 stash 적용
$ git stash apply
현재 브랜치 exp
커밋하도록 정하지 않은 변경 사항:
  (무엇을 커밋할지 바꾸려면 "git add <파일>..."을 사용하십시오)
  (use "git restore <file>..." to discard changes in working directory)
    수정함:        f1.txt

커밋할 변경 사항을 추가하지 않았습니다 ("git add" 및/또는 "git commit -a"를
사용하십시오)

// stash 조회
$ git stash list
stash@{0}: WIP on exp: 3f440f9 1

// 최근 stash 삭제
$ git stash drop
Dropped refs/stash@{0} (046135fef28ff0b48373d9421c570c3598a62768)

// apply와 drop을 합친 명령어
$ git stash pop

현재 브랜치에서 작업을 하던 도중에 커밋하지 않고 다른 브랜치로 이동할 경우 작업한 데이터들이 이동한 브랜치까지 영향을 줍니다.
현재 브랜치에서 작업을 임시로 저장할 때 쓰는 명령어 입니다.
push 옵션을 추가하면 Modified이면서 Tracked 상태인 파일과 Staging Area에 있는 파일들을 보관하고
Working Directory의 변경사항을 감춥니다.
apply 옵션을 추가하면 최근 stash에 저장해 두었던 작업들을 다시 불러옵니다.
list 옵션을 추가하면 stash들을 보여줍니다.
drop 옵션을 추가하면 최근 stash를 삭제 합니다.
pop 옵션을 추가하면 최근 stash에 저장해 두었던 작업들을 불러오고 해당 stash를 삭제합니다.

원격 저장소 만들기

remote

$ git remote add [-t {브랜치}] {원격 저장소 이름} {원격저장소 주소}

$ git remote -v

$ git remote remove {원격 저장소 이름}

기존 로컬 저장소와 원격 저장소를 연결할 때 쓴느 명령어 입니다.
add -t {브랜치 명}] {원격저장소 이름} {원격저장소 주소} 옵션을 추가하면 원격저장소와 연결이 됩니다.
-v 옵션을 추가하면 현재 연결된 원격 저장소들을 보여줍니다.
remove {원격저장소 이름} 옵션을 추가하면 원격 저장소를 연결 해제합니다.

내부 동작 원리

$ cat .git/config
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
        ignorecase = true
        precomposeunicode = true
[remote "origin"]
        url = {원격 저장소 주소}
        fetch = +refs/heads/*:refs/remotes/origin/*
[remote "upstream"]
        url = {원격 저장소 주소}
        fetch = +refs/heads/만두:refs/remotes/upstream/만두

remote add시 .git/config 파일에 remote 정보가 추가됩니다.

clone

$ git clone {원격 저장소 주소} [디렉토리 명]

명령어를 실행한 디렉토리에 원격 저장소의 작업들을 복사하여 로컬저장소로 만듭니다.
기본적으로 remote 원격 저장소와 연결이 되어있으며 원격 저장소 이름은 origin으로 되어있습니다.

원격 저장소 동기화

push

$ git push {원격 저장소 이름} {브랜치}

// push 기본 원격 저장소 브랜치 설정
$ git push -u {원격 저장소 이름} {브랜치}

// 기본 원격 저장소 설정값으로 push하여 생략 가능합니다.
$ git push

로컬 저장소에 있는 작업들을 원격 저장소로 보낼때 쓰는 명령어 입니다.
{원격저장소 이름} {브랜치} 옵션을 추가하여 해당 원격 저장소의 브랜치에 작업들을 보냅니다.
-u {원격저장소 이름} {브랜치} 옵션을 추가하여 push 할 떄 기본 원격 저장소의 브랜치를 설정하여
다음 push할 때 부터 원격 저장소와 브랜치를 생략가능합니다.
설정 할때도 push 동작이 됩니다.

내부 동작 원리

$ git push --set-updatream orgin 만두

$ cat .git/config
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
        ignorecase = true
        precomposeunicode = true
[remote "origin"]
        url = {원격 저장소 주소}
        fetch = +refs/heads/*:refs/remotes/origin/*
[branch "만두"]
        url = origin
        fetch = refs/heads/만두 
[remote "upstream"]
        url = {원격 저장소 주소}
        fetch = +refs/heads/만두:refs/remotes/upstream/만두

$ cat .git/refs/remotes/origin/만두
36db20f74f1130c97f412693e65cadcc2a48051a

$ cat .git/refs/heads/만두
36db20f74f1130c97f412693e65cadcc2a48051a

push를 할 경우 .git/refs/remotes/{원격 저장소 이름}/{브랜치} 파일 내용에 push 할 커밋개체가 쓰여집니다.
push --set-updatream {원격 저장소 이름} {브랜치} 옵션을 추가하면 .git/config에 해당 브랜치가 어떤 원격 저장소의 브랜치랑 연결되는지 추가됩니다.

fetch

$ git fetch [{원격 저장소 이름} {브랜치}]

원격 저장소에 있는 변경된 작업들을 가져오는것 까지만 해주는 명령어 입니다.
병합을 하기 전까지는 실제 로컬 저장소에는 영향을 미지치 않습니다.
변경된 작업을 가져온 경우 {원격 저장소 이름 } /{브랜치}로 새로운 브랜치가 만들어 집니다.
최신 커밋 개체들과 관련된 개체들을 다운받고 .git/refs/remotes/{원격 저장소 이름}/{브랜치} 파일 내용에 최신 커밋 개체 해쉬 값이 쓰여집니다.

pull

$ git pull [{원격 저장소 이름} {브랜치}]

원격 저장소에 있는 작업들을 가져오고 병합까지 해주는 명령어 입니다.
fetch + merge 명령어의 기능을 합친 명령어 입니다.
fetch 작업이 되고서 .git/refs/head/{브랜치} 파일 내용에 fast-forward인 경우
.git/refs/remotes/{원격 저장소 이름}/{브랜치} 파일의 커밋 개체 해쉬 값이 쓰여지게 됩니다.
3-way merge인 경우 충돌현상을 잡고서 새로운 커밋 개체가 생성이 되며 새로운 커밋 개체 해쉬 값이 쓰여지게 됩니다.

태그

tag

// Lightweight Tag
$ git tag {태그 이름} [{브랜치} | {커밋 개체 해쉬 값}]

// 태그 목록
$ git tag
1.0.0

// Annotated Tag
$ git tag -a {태그 이름} -m "{태그 메시지}" [{브랜치} | {커밋 개체 해쉬 값}]

$ git tag
1.0.0
1.1.0

// Annotated Tag 조회
$ git tag -v 1.1.0
object 5e4f4d28a075669c22e202b2ace4ec721f0ee19a
type commit
tag 1.1.0
tagger road-jin <rjswmtk@gmail.com> 1678020977 +0900

bug fix
error: no signature found

// Lightweight Tag 조회
$ git tag -v 1.0.0
error: 1.0.0: cannot verify a non-tag object of type commit.


$ git log
commit 5e4f4d28a075669c22e202b2ace4ec721f0ee19a (HEAD -> main, tag: 1.1.0)
Author: road-jin <rjswmtk@gmail.com>
Date:   Sun Mar 5 21:54:14 2023 +0900

    3

commit 392b8dd27c35a8e51a7cff1cfb81bbc98f179bea (tag: 1.0.0)
Author: road-jin <rjswmtk@gmail.com>
Date:   Sun Mar 5 21:52:46 2023 +0900

    2

commit e11f17504379addef52a0168160c4935a692d20e
Author: road-jin <rjswmtk@gmail.com>
Date:   Sun Mar 5 21:52:22 2023 +0900

    1

// 태그 삭제    
$ git tag -d {태그 이름}    

// 태그들 원격 저장소에 push
$ git push --tags

커밋 개체에 대한 태그를 붙일 때 쓰는 명령어 입니다.
Lightweight Tag는 커밋 개체에 대한 기본적인 태그정보만 저장합니다.
Annotated Tag는 태그 만든 사람, 언제 태그를 만들었는지, 태그 메시지를 저장합니다.
옵션을 추가하지 않으면 태그 목록들을 보여줍니다.
{태그 이름} [{브랜치} | {커밋 개체 해쉬 값}] 옵션을 추가하면 Lightweight Tag가 추가됩니다.
-a {태그 이름} -m "{태그 메시지}" [{브랜치} | {커밋 개체 해쉬 값}] 옵션을 추가하면 Annotated Tag가 추가됩니다.
-v {태그 이름} 옵션을 추가하면 해당 태그에 대한 정보를 보여줍니다.
-d {태그이름} 옵션을 추가하면 해당 태그를 삭제합니다.
push --tags 명령어를 사용해야만 원격 저장소에 태그들이 전송됩니다.

내부 동작 원리

$ cat .git/refs/tags/1.0.0
392b8dd27c35a8e51a7cff1cfb81bbc98f179bea

$ git cat-file -p 392b8dd27c35a8e51a7cff1cfb81bbc98f179bea
tree 36f609fa71850be13f5f97e4346cdf2488e7057c
parent e11f17504379addef52a0168160c4935a692d20e
author road-jin <rjswmtk@gmail.com> 1678020766 +0900
committer road-jin <rjswmtk@gmail.com> 1678020766 +0900

2

$ cat .git/refs/tags/1.1.0
ecf7866ccf4366341a90adc23febac09af4a6ff9

$ git cat-file -p ecf7866ccf4366341a90adc23febac09af4a6ff9
object 5e4f4d28a075669c22e202b2ace4ec721f0ee19a
type commit
tag 1.1.0
tagger road-jin <rjswmtk@gmail.com> 1678020977 +0900

bug fix

$ git cat-file -p 5e4f4d28a075669c22e202b2ace4ec721f0ee19a
tree 77aa31a93565e0c5809ff487b849af48ac7df624
parent 392b8dd27c35a8e51a7cff1cfb81bbc98f179bea
author road-jin <rjswmtk@gmail.com> 1678020854 +0900
committer road-jin <rjswmtk@gmail.com> 1678020854 +0900

3

Lightweight Tag인 경우 .git/refs/tags/{태그 이름}파일이 생성되며 내용에 커밋 개체 해쉬 값이 쓰여집니다.
Annotated Tag인 경우 objects 파일을 생성하고 내용에 태그 정보들과 커밋 개체 해쉬 값이 쓰여집니다.
그리고 .git/refs/tags/{태그 이름}파일이 생성되며 내용에 해당 objects 파일의 해쉬 값이 쓰여집니다.

참고

https://www.youtube.com/playlist?list=PLuHgQVnccGMA8iwZwrGyNXCGy2LAAsTXk

https://git-scm.com/book/ko/v2

https://www.inflearn.com/course/%EC%A0%9C%EB%8C%80%EB%A1%9C-%ED%8C%8C%EB%8A%94-%EA%B9%83