[Git] 로컬 저장소 사용법

식빵·2022년 2월 21일
0

git

목록 보기
2/5
post-thumbnail

🍀 개요

준비 과정이 좀 길었다.
이제는 정말 기본 명령어 실습을 해보자.

참고로 파일 내용 편집은 웬만해서는 다 git bash 가 제공하는 vim 에디터를 쓸 것이다.
vim 에디터 사용법을 잘 모르겠으면 검색해서 간단한 사용법 정도만 익히자.




🍀 실습 시작


👏 테스트 디렉토리, 파일 생성

일단 실습을 하고자 하는 디렉토리를 생성하겠다.
나는 D:\study\git_command\ 디렉토리를 생성하고, 3개의 파일을 생성했다.

$ ls -al
total 7
drwxr-xr-x 1 devToroko 197121  0 Feb 21 10:18 ./
drwxr-xr-x 1 devToroko 197121  0 Feb 21 07:39 ../
-rw-r--r-- 1 devToroko 197121 49 Feb 21 07:42 good01.txt
-rw-r--r-- 1 devToroko 197121 49 Feb 21 07:42 good02.txt
-rw-r--r-- 1 devToroko 197121 49 Feb 21 07:42 good03.txt

각 파일의 내용은 아래와 같다. (주석은 실제 내용에 없습니다)

$ cat good01.txt
good text 01 text file # 다른 파일들은 자기 이름에 맞게 02, 03

nice to meet you, No.1! # 다른 파일들은 자기 이름에 맞게 No.1, No.2




👏 Git 시작, 복구

> git init

git 초기화

$ git init
Initialized empty Git repository in D:/study/git_command/.git/

> git status

git 상태 확인

참고: 상태값의 의미


> git add

git 스테이징

$ git add . # git add {파일명} 도 가능

> git rm --cached {파일이름}

git un staging

$ git rm --cached . # git index 비우기

> git commit

git 커밋

$ git commit -m 'First Commit' # -m을 통해서 메세지 작성, 만약 생략하면 vim으로 작성
[main (root-commit) 1c7343a] First Commit
 3 files changed, 9 insertions(+)
 create mode 100644 good01.txt
 create mode 100644 good02.txt
 create mode 100644 good03.txt




연습01) good01.txt 수정 후 새로운 커밋 생성하기

$ vim good01.txt

$ cat good01.txt
good text 01 text file

nice to meet you, No.1!

i am changed!!!! # 추가

바로 이어서 git status 입력

$ git add good01.txt
$ git commit -m 'good01.txt changed'
[main 0e5962e] good01.txt changed
 1 file changed, 3 insertions(+), 1 deletion(-)


> git log

git 커밋 이력 조회

$ git log
commit 0e5962e1d6be4c6aed684f8465e52b29540e5135 (HEAD -> main)
Author: devToroko <blabla@gmail.com>
Date:   Mon Feb 21 11:07:08 2022 +0900

    good01.txt changed

commit 1c7343aee7e425e717171a3864e8d58031b62490
Author: devToroko <blabla@gmail.com>
Date:   Mon Feb 21 10:57:46 2022 +0900

    First Commit

참고로 여기서 git log의 내용이 너무 길면 j, k를 통해서 위아래로 움직일 수 있고,
:q 를 입력하면 빠져나온다.


좀 더 이쁘게 로그를 보려면 git log --all --decorate --oneline --graph
소스트리에서 보는 모양과 비슷하게 출력된다.


> git revert

git 특정 커밋 변동 사항을 거꾸로 한 커밋 생성

일단 아래와 같은 상태까지 만들어두고 테스트하겠다.

$ git log --all --decorate --oneline --graph
* 119a527 (HEAD -> main) good03.txt changed
* 3472ba1 good02.txt changed
* 0e5962e good01.txt changed
* 1c7343a First Commit

0e5962e 커밋 해시에서 생긴 변동 사항을 되돌리는 새로운 커밋을 만든다고 치자.

$ git revert 0e5962e # 입력하자마자 커밋 메세지 입력창이 나온다.

:wq 를 입력해서 커밋을 저장해주자.


이후에는 아래처럼 새로운 커밋이 생긴것을 확인할 수 있다.

$ git log --all --decorate --oneline --graph
* 192ca06 (HEAD -> main) Revert "good01.txt changed"
* 119a527 good03.txt changed
* 3472ba1 good02.txt changed
* 0e5962e good01.txt changed
* 1c7343a First Commit

그런데 위처럼 바로 커밋이 생기는 게 아니라,
추가적인 변동사항도 같이 add 한 후에 커밋을 하고 싶다면 아래처럼 하면 된다.

일단 다시 테스트를 하기 위해서 $ git reset --hard HEAD^ 를 입력한다.
이러면 바로 이전 커밋 상태로 돌아간다.


$ git revert --no-commit 0e5962e1d6b

## 자세히 보면 맨 끝에 REVERTING 이라는 문구가 보인다!
devToroko@DESKTOP-IBMND88 MINGW64 /d/study/git_command (main|REVERTING)
$ git status
On branch main
You are currently reverting commit 0e5962e.
  (all conflicts fixed: run "git revert --continue")
  (use "git revert --skip" to skip this patch)
  (use "git revert --abort" to cancel the revert operation)

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   good01.txt


devToroko@DESKTOP-IBMND88 MINGW64 /d/study/git_command (main|REVERTING)
$ vim good02.txt

devToroko@DESKTOP-IBMND88 MINGW64 /d/study/git_command (main|REVERTING)
$ git status
On branch main
You are currently reverting commit 0e5962e.
  (all conflicts fixed: run "git revert --continue")
  (use "git revert --skip" to skip this patch)
  (use "git revert --abort" to cancel the revert operation)

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   good01.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   good02.txt
        
devToroko@DESKTOP-IBMND88 MINGW64 /d/study/git_command (main|REVERTING)
$ git add .

devToroko@DESKTOP-IBMND88 MINGW64 /d/study/git_command (main|REVERTING)
$ git status
On branch main
You are currently reverting commit 0e5962e.
  (all conflicts fixed: run "git revert --continue")
  (use "git revert --skip" to skip this patch)
  (use "git revert --abort" to cancel the revert operation)

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   good01.txt
        modified:   good02.txt


devToroko@DESKTOP-IBMND88 MINGW64 /d/study/git_command (main|REVERTING)
$ git commit -m 'revert with another changes'
[main 8e5aca0] revert with another changes
 2 files changed, 3 insertions(+), 3 deletions(-)

devToroko@DESKTOP-IBMND88 MINGW64 /d/study/git_command (main) 
$ # REVERTING 이라는 문구가 사라진 것을 확인할 수 있다.

git revert --abort를 통해서 revert를 취소할 수도 있다.


$ git log --all --decorate --oneline --graph
* 8e5aca0 (HEAD -> main) revert with another changes
* 119a527 good03.txt changed
* 3472ba1 good02.txt changed
* 0e5962e good01.txt changed
* 1c7343a First Commit

$ git reset --hard HEAD^ # 다음 테스트를 위해서 미리 reset 하여 원상복구



revert 시 충돌 예제

이번에는 revert 시 충돌이 일어나도록 해보겠다.
먼저 good01.txt 을 통한 텍스트를 변경하고 0e5962e 커밋 해시을 revert 해보자.

$ vim good01.txt # 수정

# -am은 add 하고 commit 메세지 작성을 한번에 해주는 option이다.
$ git commit -am 'more change on good01.txt'
[main de925a3] more change on good01.txt
 1 file changed, 1 insertion(+)
 
$ git log --all --decorate --oneline --graph
* de925a3 (HEAD -> main) more change on good01.txt # 이 녀석이랑
* 119a527 good03.txt changed
* 3472ba1 good02.txt changed
* 0e5962e good01.txt changed  # 이 녀석이 충돌할 예정이다
* 1c7343a First Commit

그리고 나서 revert를 하면...?

예상대로 conflict 가 발생한다.
conflict 목록과 상세한 충돌 라인 number를 보려면 아래처럼 입력해보자.

$ git diff --name-only --diff-filter=U
good01.txt # 충돌 파일

$ git diff --check # 상세한 충돌 라인 출력
good01.txt:3: leftover conflict marker
good01.txt:8: leftover conflict marker
good01.txt:10: leftover conflict marker

참고로 conflict 가 너무 많다고 판단되면 git revert --abort 로 취소할 수 있다.
그게 아니면 직접 충돌이 난 파일에 찾아가서 고쳐보자.
vim 을 통해서 충돌난 파일 good01.txt 파일을 열어보면 아래와 같이 작성되어 있다.

<<<<<< , >>>>>> 표기되어 있는 곳 사이가 충돌 지점이다.


충돌 해소를 위해서 아래처럼 수정했다.


이후 git add .; git commit; 입력하여 커밋 메세지 작성, 저장하여 revert를 끝낸다.

$ git log --all --decorate --oneline --graph
* 3b6fb4e (HEAD -> main) Revert "good01.txt changed" # 성공!
* de925a3 more change on good01.txt
* 119a527 good03.txt changed
* 3472ba1 good02.txt changed
* 0e5962e good01.txt changed
* 1c7343a First Commit



> git reset

git 특정 커밋으로 원상복구 시키기

git reset에는 3가지 옵션인 hard, mixed (default), soft 가 있다.

git reset -h 를 입력하면 아래와 같이 옵션에 대한 설명이 있다.
잘 모르겠으면 검색! 이론은 최소화하고 싶다.

    --mixed               reset HEAD and index
    --soft                reset only HEAD
    --hard                reset HEAD, index and working tree

일단 싹다 원복하고 싶으면 reset --hard 를 쓴다는 것만 기억하자.
그리고 --mixed--soft를 이어서 해보자.


git reset --mixed

$ git log --all --decorate --oneline --graph
* 3b6fb4e (HEAD -> main) Revert "good01.txt changed"
* de925a3 more change on good01.txt # 여기로 reset --mixed 시도
* 119a527 good03.txt changed
* 3472ba1 good02.txt changed
* 0e5962e good01.txt changed
* 1c7343a First Commit

$ git reset de925  # option을 안 주면 default 옵션인 --mixed 가 적용된다.
Unstaged changes after reset:
M       good01.txt

$ git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   good01.txt

# 보면 알겠지만 reset은 됐지만, workspace에서의 변화 내용은 아직 파일에 기재되어 있다.
# 파일 내용을 보면 우리가 이전에 계속 쌓아왔던 변화가 아직 남아 있다.

$ cat good01.txt
good text 01 text file

nice to meet you, No.1!

i am changed!!!!
more change after all commits
nice to meet you, No.1!

이번에는 --soft 옵션을 보기 위해서 reset 한 행위 이전으로 되돌리겠다.
reset 도 원복이 가능하다. 원복 이후에 바로 reset --soft 를 테스트 해보자.


git reset --soft

# 이전에 했던 git reset --mixed 했던 행위 자체를 무효로 하기 위해서
# "reflog" 와 "reset --hard" 를 사용한다.
$ git reflog
de925a3 (HEAD -> main) HEAD@{0}: reset: moving to de925
3b6fb4e HEAD@{1}: commit: Revert "good01.txt changed" # 여기로 돌아가자!
de925a3 (HEAD -> main) HEAD@{2}: commit: more change on good01.txt 
119a527 HEAD@{3}: reset: moving to HEAD^
8e5aca0 HEAD@{4}: commit: revert with another changes

$ git reset --hard 3b6fb4e
HEAD is now at 3b6fb4e Revert "good01.txt changed"

## reset --mixed 사용 이전으로 돌아온 것을 확인!
$ git log --all --decorate --oneline --graph
* 3b6fb4e (HEAD -> main) Revert "good01.txt changed"
* de925a3 more change on good01.txt
* 119a527 good03.txt changed
* 3472ba1 good02.txt changed
* 0e5962e good01.txt changed # 여기로 "reset --soft" 예정
* 1c7343a First Commit

$ git reset --soft 0e5962e

$ git log --all --decorate --oneline --graph
* 0e5962e (HEAD -> main) good01.txt changed
* 1c7343a First Commit

$ git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   good01.txt
        modified:   good02.txt
        modified:   good03.txt
        
# 복구했지만, 복구하던 시점에 있던 변동 사항들은 staging 상태로 여전히 남아 있다!

이정도 실습이면 reset 에 대한 이해는 충분하다고 생각한다.




👏 Git Branch

이전 실습에서 modified 가 3개 생기는데, commit 해주자.

$ git commit -am 'reset --soft done'

> git branch {브랜치}

git 브랜치를 생성

$ git branch dev-01



> git branch

git 브랜치 목록 확인

원격까지 확인하고 싶다면 -a 옵션을 준다.

$ git branch
  dev-01
* main  # * 가 찍힌 곳이 현재 내가 위치하는 branch이다.



> git switch {브랜치}

git 브랜치 이동

만약 브랜치 생성과 이동을 동시에 하고 싶다면 git switch -c dev-01

devToroko@DESKTOP-IBMND88 MINGW64 /d/study/git_command (main)
$ git switch dev-01
Switched to branch 'dev-01'

devToroko@DESKTOP-IBMND88 MINGW64 /d/study/git_command (dev-01) 
$ # 브랜치 명이 바뀌었다. (main) ==> (dev-01) 



> git branch -d {브랜치}

git 브랜치 삭제

해당 브랜치에는 변동사항이 없어야 한다.
만약 merge 되지 않은 브랜치여도 지우고 싶다면 git branch -D {브랜치 명}로 강제 삭제

$ git switch main
Switched to branch 'main'

$ git branch -d dev-01
Deleted branch dev-01 (was 861fa2c).

$ git branch
* main



> git branch -m {브랜치}

git 브랜치 이름 수정

devToroko@DESKTOP-IBMND88 MINGW64 /d/study/git_command (main)
$ git switch -c dev-01
Switched to a new branch 'dev-01'

devToroko@DESKTOP-IBMND88 MINGW64 /d/study/git_command (dev-01)
$ git branch -m dev-01 dev-02

devToroko@DESKTOP-IBMND88 MINGW64 /d/study/git_command (dev-02)
$ git branch
* dev-02
  main




👏 Git Branch 병합


실습에 앞서 3개의 git branch를 생성하자.

$ git branch
  dev-01
  dev-02
* main

$ git log --all --decorate --oneline --graph
* 861fa2c (HEAD -> main, dev-02, dev-01) reset --soft done
* 0e5962e good01.txt changed
* 1c7343a First Commit

이후에 아래와 같이 작업해준다.

  • main 브랜치는 good01.txt를 변경해주고 커밋
  • dev-01 브랜치는 good02.txt 를 변경해주고 커밋
  • dev-02 브랜치는 good03.txt 를 변경해주고 커밋

## main 브랜치 상태!
$ vim good01.txt # 내용 변경

$ git commit -am 'changed by main branch - 01.text'

$ git log --all --decorate --oneline --graph -3 # 위에서 3개만 보자.
* d659b6c (HEAD -> main) changed by main branch - 01.text
* 861fa2c (dev-02, dev-01) reset --soft done
* 0e5962e good01.txt changed


# dev-01 로 브랜치 변경!!
$ git switch dev-01

$ vim good02.txt # 내용 변경

$ git commit -am 'changed by dev-01 branch - 02.text'


# dev-02 로 브랜치 변경!!
$ git switch dev-02

$ vim good03.txt # 내용 변경

# 충돌 테스트를 위해서 고의적으로 good02.txt도 변경한다.
$ vim good02.txt # 내용 변경 

$ git commit -am 'changed by dev-02 branch - 02,03.text'

결과적으로 아래와 같은 branch 구성을 보여준다.



> git merge {병합할 브랜치}

서로 다른 git branch 를 하나의 커밋에 병합

$ git switch dev-01
Switched to branch 'dev-01'

devToroko@DESKTOP-IBMND88 MINGW64 /d/study/git_command (dev-01)
$ git merge main # 커밋 메세지 작성 vim 이 나오는데, 그냥 :wq 하고 나와도 된다.

결과


그림을 보면 알겠지만 merge 하는 순간에 내가 위치한 브랜치가 merge 커밋에 위치한다.
이 상태에서 main 브랜치를 dev-01 브랜치 위치로 끌어 당기기 위해서는 아래처럼 한다.

$ git switch main
Switched to branch 'main'

$ git merge dev-01
Updating d659b6c..f5b8b44
Fast-forward
 good02.txt | 2 ++
 1 file changed, 2 insertions(+)
 
$ git branch -d dev-01 # 더 이상 쓸모없는 dev-01 브랜치는 지운다!
Deleted branch dev-01 (was f5b8b44).

결과


이제 남은 dev-02 브랜치를 병합시켜보자.
여기서는 충돌이 날 예정이다.

devToroko@DESKTOP-IBMND88 MINGW64 /d/study/git_command (main)
$ git switch dev-02
Switched to branch 'dev-02'

devToroko@DESKTOP-IBMND88 MINGW64 /d/study/git_command (dev-02)
$ git merge main
Auto-merging good02.txt
CONFLICT (content): Merge conflict in good02.txt 
Automatic merge failed; fix conflicts and then commit the result.

# CONFLICT 발생!!
# 혹시라도 merge 하기 이전으로 돌아가고 싶다면 `git reset --hard` 해주자.

# MERGING 이 표기된다! Conflict 난 것을 해결하라는 의미이다.
devToroko@DESKTOP-IBMND88 MINGW64 /d/study/git_command (dev-02|MERGING) 
$ git diff --name-only --diff-filter=U
good02.txt # 충돌 파일 확인!

# 충돌 파일 수정
$ vim good02.txt

# 충돌 파일 staging 및 commit
$ git add good02.txt

$ git commit

git commit 후 아래처럼 화면이 나오면 그냥 :wq로 빠져나온다.
기본 커밋 메세지를 쓰겠다는 의미다.


결과


이제 main 브랜치를 dev-02 와 같은 위치로 이동시키고, dev-02 브랜치를 삭제한다.

$ git switch main
Switched to branch 'main'

$ git merge dev-02
Updating f5b8b44..0b6d558
Fast-forward
 good03.txt | 2 ++
 1 file changed, 2 insertions(+)

$ git branch -d dev-02
Deleted branch dev-02 (was 0b6d558).

결과



> git rebase {옮겨갈 브랜치}

하나의 브랜치의 내용물을 브랜치 분기 시점부터 뜯어서 다른 브랜치 끝에 이음(= 재배치)


실습에 앞서 잠시 테스트 브랜치와 커밋을 만들어 두자.
각 브랜치에서는 다음과 같은 작업을 해둔다. commit 메세지는 아래 "결과" 그림을 참조!

  • main : good01.txt 수정 후 커밋
  • rebase-branch : good04.txt 생성 후, 내용 작성, add + commit
  • rebase-conflict-branch
    • good04.txt 생성 후, add & commit
    • good01.txt 수정 후, add & commit
    • 위 두 개의 파일은 충돌을 위한 것이다.

위의 과정들을 이번에는 적지 않겠다. 여기까지 왔으면 저건 정말 쉬운 내용이다.
직접 해보고 아래 그림의 빨간 박스 내용과 같이 커밋 history가 나오도록 하자.


결과



(rebase-branch ==> main) 재배치 해보기

$ git switch rebase-branch

$ git rebase main
Successfully rebased and updated refs/heads/rebase-branch. # 깔금하게 성공

재배치 결과

main 브랜치의 끝에 rebase-branch 재배치된 것을 확인할 수 있다.


(rebase-conflict-branch ==> main) 재배치 해보기

devToroko@DESKTOP-IBMND88 MINGW64 /d/study/git_command (rebase-branch)
$ git switch rebase-conflict-branch

devToroko@DESKTOP-IBMND88 MINGW64 /d/study/git_command (rebase-conflict-branch)
$ git rebase main
Auto-merging good01.txt
CONFLICT (content): Merge conflict in good01.txt
error: could not apply c23d763... change good01.txt by rebase-conflict-branch
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply c23d763... change good01.txt by rebase-conflict-branch

# 예상대로 Conflict 발생!!


devToroko@DESKTOP-IBMND88 MINGW64 /d/study/git_command (rebase-conflict-branch|REBASE 2/2)
$ # 자세히 보면 끝에 REBASE 2/2 라고 되어 있다. 이건 현재 REBASE 가 진행 중이라는 의미다.
  # 현재 2개의 커밋 내역 중 1개는 무사히 rebase가 됐고, 나머지 하나가 충돌이 생긴 것이다.
  
$ git diff --name-only --diff-filter=U
good01.txt # 충돌 파일 확인

git rebase의 도움말을 보면 알겠지만, rebase 작업 취소는 git rebase --abort 하면 된다.
나는 good01.txt 파일을 수정해서 충돌을 해소하고, 계속해서 rebase를 할 것이다.


파일 내용(충돌 해결 전/후)


$ git add good01.txt
$ git rebase --continue

이후에 아래처럼 git commit 메세지 작성 화면이 나오는데, 그냥 :wq 해서 기본 메세지로 커밋하겠다.


결과




👏 Tips

> git diff 로 충돌 위치 조회

$ git diff --name-only --diff-filter=U
good01.txt # 충돌 파일

$ git diff --check # 상세한 충돌 라인 출력
good01.txt:3: leftover conflict marker
good01.txt:8: leftover conflict marker
good01.txt:10: leftover conflict marker




🍀 참고

profile
백엔드를 계속 배우고 있는 개발자입니다 😊

0개의 댓글