준비 과정이 좀 길었다.
이제는 정말 기본 명령어 실습을 해보자.
참고로 파일 내용 편집은 웬만해서는 다 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
Initialized empty Git repository in D:/study/git_command/.git/
git 상태 확인
참고: 상태값의 의미
git 스테이징
$ git add . # git add {파일명} 도 가능
git un staging
$ git rm --cached . # git index 비우기
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 커밋 이력 조회
$ 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 특정 커밋 변동 사항을 거꾸로 한 커밋 생성
일단 아래와 같은 상태까지 만들어두고 테스트하겠다.
$ 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 특정 커밋으로 원상복구 시키기
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 에 대한 이해는 충분하다고 생각한다.
이전 실습에서
modified
가 3개 생기는데,commit
해주자.$ git commit -am 'reset --soft done'
git 브랜치를 생성
$ git branch dev-01
git 브랜치 목록 확인
원격까지 확인하고 싶다면 -a
옵션을 준다.
$ git branch
dev-01
* main # * 가 찍힌 곳이 현재 내가 위치하는 branch이다.
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 브랜치 삭제
해당 브랜치에는 변동사항이 없어야 한다.
만약 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 브랜치 이름 수정
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
실습에 앞서 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 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).
결과
하나의 브랜치의 내용물을 브랜치 분기 시점부터 뜯어서 다른 브랜치 끝에 이음(= 재배치)
실습에 앞서 잠시 테스트 브랜치와 커밋을 만들어 두자.
각 브랜치에서는 다음과 같은 작업을 해둔다. 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
해서 기본 메세지로 커밋하겠다.
결과
$ 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