📝

7. 그 외 명령어

 
지금까지 배웠던 내용 이외에 협업할 때 자주 쓰는 명령어 5가지 (amend, stash, reset, revert, cherry-pick) 를 알아보겠습니다.

1. amend

커밋은 하나의 기능을 만들 때 변경사항을 저장해 주는 것이 좋습니다. 하나의 기능을 만들고 커밋을 할 때 실수로 커밋하지 못한 파일이나 수정된 파일이 있을 수도 있습니다. 이때, 최신 커밋에 누락된 파일을 추가하고 싶을 때에 amend를 사용합니다. amend를 한 후 커밋을 보면 기존 커밋과 amend한 내용이 저장됩니다.
‘한 번 더 커밋 하면 되지’라고 생각할 수도 있습니다만, 같은 기능을 나타내는 커밋이 2개가 생겨 버리게 되므로 커밋을 되돌릴 때 혼동이 올 수 있습니다.
💡
commit과 push는 날짜나 code 작성 양에 따라 하는 것이 아니라 기능 구현 단위로 해주시는 것이 좋습니다. (유지보수와 복구 측면에서)
commit 한 경우commit 한 경우
commit 한 경우
 
amend한 경우amend한 경우
amend한 경우
amend라는 기능을 amend.txt에 작성하겠습니다.
amend 1
amend.txt
$ git add amend.txt $ git commit -m "기능 추가"
 
기능을 수정합니다.
amend 1 amend 2
기능 수정 후
 
amend를 이용하여 최신 커밋에 수정한 내용을 추가합니다.
$ git add amend.txt $ git commit --amend
notion imagenotion image
 
VSC(Visual Studio Code)를 사용하신다면 위의 명령어 실행 시 VSC editer에서 COMMIT_EDITMSG 파일이 켜지게 됩니다. 아래 사진의 빨간 박스가 있는 부분이 이전 커밋 메시지인 것을 확인할 수 있습니다. 만약 커밋 메시지를 수정하기 원한다면 해당 파일에서 수정할 수 있으며, 수정을 원하지 않는 경우COMMIT_EDITMSG를 꺼주면 amend가 적용된 것을 확인할 수 있습니다.
notion imagenotion image
notion imagenotion image
notion imagenotion image
 
이때, 혼자 사용하는 것이 아닌 여러 명이 함께 사용하는 브랜치인 경우는 히스토리가 복잡해질 수 있으므로 조심해야 합니다.

2. stash

현재 브랜치에서 아직 커밋 하지 못한 파일들이 있는데, 다른 브랜치로 넘어가야 하는 경우 현재 브랜치의 변경사항을 잠시 보관할 때 stash를 사용합니다. stash는 git 저장소에서 관리하고 있는 파일, 첫 커밋이 일어난 대상으로 실행하며 스테이지에 있는 내용과 들어가지 않은 변경 사항 모두를 저장합니다. 추가 명령어를 이용하면 git 저장소에서 관리하지 않는 파일도 stash에 넣을 수 있습니다. 실무에서 회사 우선순위에 따라 작성해야 하는 code가 변경되기도 하니 알아두셔야 합니다.
Tracked 파일을 stash 하는 경우와 unTracked 파일을 stash하는 두 가지 경우에 대해 알아보겠습니다.
💡
들어가기 전 용어 정리 Tracked : git 저장소에서 관리하는 파일 UnTracked : git 저장소에서 관리하지 않는 파일 Git의 Tracked와 UnTracked에 대한 자세한 내용은 2.Git 챕터의 5.2.1을 참고해주세요.
 

2.1. Tracked 파일을 stash하는 경우

main 브랜치에서 README.mdindex.txt를 커밋한 후, 두 파일에서 수정사항이 발생 되었을 때를 가정하고 시작하겠습니다. 우선, README.md 파일을 스테이지에 올리겠습니다.
$ git add README.md $ git status
notion imagenotion image
 
stash를 하면, 수행 중이던 작업을 임시 저장하고 가장 최근 커밋 상태로 만듭니다.
$ git stash $ git status
notion imagenotion image
 
이후 다른 브랜치에서 작업을 하고 돌아온 후, 가장 최근에 임시 저장한 내용을 가져옵니다. 이때, 스테이지 상태까지 그대로 복원하지는 않습니다.
$ git stash pop
notion imagenotion image
 

2.2. UnTracked 파일 stash하는 경우

이번에는 위에 예제에서 새로운 파일을 생성해 git 저장소가 관리하지 않는 파일을 stash에 올려보겠습니다.
test.txt라는 새로운 파일을 생성 후, stash 명령어를 사용해 보겠습니다.
$ touch test.txt $ git stash $ git status
notion imagenotion image
notion imagenotion image
 
이번에는 이전과 다른 결과를 보게 됩니다. 기본적으로 stash 명령어는 git 저장소에서 관리하고 있는 파일들만 임시 저장을 해주기 때문입니다. 새로 생성한 파일(git 저장소에서 관리하지 않는 파일)까지 모두 저장하고 싶은 경우에는 명령어 뒤에 --all 모드를 붙여주면 됩니다.
 
기존에 stash에 저장한 index.txtREADME.md 파일을 stash에서 빼낸 후, git stash --all 명령어를 이용해 모든 파일을 다시 stash에 올려보겠습니다.
$ git stash pop
notion imagenotion image
$ git stash --all $ git status
notion imagenotion image
이번에는 모든 파일이 stash에 저장된 것을 볼 수 있습니다.
 

2.3. stash mode 소개

$ git stash # 저장하기 $ git stash save [description] # 설명 추가하면서 저장하기 $ git stash list # stash 리스트 보여주기 # stash@{0}: WIP on main: 06c4e12 test <- 이런식으로 stash의 목록을 보여줍니다. # stash@{1}: WIP on main: 02bde12 other $ git stash apply # 가장 최근 stash 가져와 적용 (stash에서 삭제는 안됩니다.) $ git stash apply --index # staged된 상태까지 적용하고 싶은 경우 $ git stash drop # 가장 최근 stash 내용 삭제 $ git stash drop stash@{숫자} # 해당하는 친구 삭제 $ git stash pop # 위에 있는 apply와 drop을 합친 키워드 -> 가장 최근 stash 내용 적용 및 삭제 $ git stash clear # 전체 삭제

3. reset

브랜치에 여러가지 버전을 올린 후 이전 커밋으로 브랜치를 되돌릴 때 사용합니다.
돌아간 커밋 내역 이후의 커밋 히스토리들을 초기화합니다. 때문에, 기존에 push가 된 상태에서 reset을 사용한 후, 다시 push를 하면 로컬 저장소의 최신 히스토리와 원격 저장소의 최신 히스토리가 다르기 때문에 에러가 발생합니다. 강제로 push를 해야 되지만, 혼자 쓰는 브랜치에서만 사용하시고 여러 명이 사용하는 브랜치에서는 사용하면 안 됩니다. 이미 push된 커밋을 돌리고 싶은 경우는 revert를 사용합니다.
$ git reset [mode]
 
자주 사용하는 mode는 다음과 같습니다.
  • hard : 지정한 커밋 이력 이후 변경사항을 다 버리고 지정한 커밋으로 리셋
  • mixed : 지정한 커밋 이력 이후 변경 사항은 로컬에 unstaged 상태로 유지하고 커밋은 리셋
  • soft : 지정한 커밋 이력 이후 변경 사항은 로컬에 stage 상태로 유지하고 커밋은 리셋
 
커밋 내역을 보도록 하겠습니다.
$ git log
커밋 이력 확인커밋 이력 확인
커밋 이력 확인
커밋마다 README.md 파일에 작성된 내용입니다.
first second
second commit
first second third
third commit
first second third fourth
fourth commit
first second third fourth fifth
fifth commit
 
앞, 뒤에 내용을 보고 싶거나 그 상태로 단순 이동이라면 아래 명령어를 사용해주세요. 해당 내용은 commit 내용을 바꾸는 것이 아닌 단순 시간상 이동입니다.
git checkout HEAD^ : 바로 직전 commit으로 이동 git checkout HEAD^^ : 2번 전 commit으로 이동 git checkout HEAD^^^ : 3번 전 commit으로 이동 git checkout HEAD~10 : 10번 전 commit으로 이동 git checkout - : 있는 위치에서 앞으로 한 칸 이동 git switch main : 다시 원래 main의 최상위로 이동

3.1. hard

fouth commit 으로 hard 모드를 사용해 되돌려 보도록 하겠습니다.
$ git reset --hard commit-id $ git log
notion imagenotion image
first second third fourth
README.md
reset을 사용해 fourth commit으로 돌아갔기 때문에 fifth commit 이력이 지워집니다. 또한, hard 모드를 사용하여 README.md 의 기존에 있던 파일 내용이 없어지고, fourth commit의 내용으로 바뀐 것을 확인할 수 있습니다.
여기서 push를 하게 되면 원격 저장소에 있는 git 내역과 다르기 때문에 error가 납니다. 이를 해결하기 위해서는 앞서 말씀드린 것처럼 강제로 push를 해야 합니다.
notion imagenotion image
notion imagenotion image

3.2. mixed

mixed 모드를 사용하여 third commit 으로 되돌려 보도록 하겠습니다.
$ git reset --mixed commit-id $ git log $ git status
이때, 로컬에서 README.md 를 살펴보면 되돌아가기 전 작업 내용은 사라지지 않고 unstaged 상태인 것을 확인할 수 있으며, commit 이력만 리셋된 것을 볼 수 있습니다.
notion imagenotion image
notion imagenotion image
first second third fourth
README.md - unstaged
다음의 예제를 위해 unstaged된 내용을 restore 하여(변경 내역 삭제) third commit 내용으로 맞춰주겠습니다.
$ git restore README.md
first second third
README.md - third commit

3.3. soft

mixed 모드로 reset한 경우 이전 작업 내용을 unstaged에 남겼다면 soft는 staged 영역에 남기게 됩니다. 모드를 soft로 설정한 후 second commit 커밋 내역을 되돌립니다.
$ git reset --soft commit-id $ git log $ git status
notion imagenotion image
notion imagenotion image
first second third
README.md - staged
히스토리를 살펴보면 커밋 내역은 사라지고 작업 내역은 stage에 남은 것을 볼 수 있습니다.
💡
reset 활용하기 단위 별로 커밋을 잘 해둔다면 개인 공부하실 때 reset을 유용하게 사용할 수 있습니다.
 

4. revert

만약 로컬에 commit만 한 경우에는 reset을 사용할 수 있습니다. 하지만 원격 저장소로 push된 경우 reset을 사용하게 되면, reset 하고자 하는 커밋 이력으로 돌아간 다음 해당 커밋 이후의 커밋 히스토리들이 전부 삭제됩니다. 때문에 작업을 마치고 commit, push를 하게 되면, 로컬 저장소에 있는 커밋 히스토리원격 저장소에 있는 커밋 히스토리가 달라 Error가 발생합니다.
그렇기 때문에 여러 명이 원격 저장소를 다루는 협업에서 reset 사용은 지양하는 것이 좋습니다. 만약 사용을 원한다면 혼자만 이용하는 브랜치에서 reset 사용을 권장합니다.
위와 같은 Error를 방지하며 push된 커밋 이력을 되돌리고 싶은 경우, revert를 사용합니다. revert는 특정 커밋 이력을 되돌리는 작업도 하나의 커밋으로 간주하여 기존의 히스토리는 남겨둔 상태로 새로운 커밋 히스토리를 추가하는 방식입니다.
💡
reset과 revert의 차이점 reset : 지정한 커밋으로 이동(지정 커밋 이후의 히스토리 초기화) revert : 지정한 커밋의 내용으로 새로운 커밋 생성(히스토리 보존)
 
사용 방법
새롭게 하나 만들도록 하겠습니다.
git init echo '1 hello world' >> README.md git add . git commit -m '1'
수정할 때마다 add와 commit을 진행합니다. 총 4개의 commit이 있게 됩니다.
1 hello world 2 hello world 3 hello world 4 hello world
README.md
커밋 이력을 확인해보겠습니다.
$ git log
notion imagenotion image
가장 최신 커밋 이력이 4 commit인 것을 확인할 수 있습니다. revert를 사용하여 커밋 이력을 3 commit으로 되돌려보겠습니다.
💡
반드시 직전 commit으로 되돌아가야 합니다. 만약 처음 commit으로 돌아가고 싶다면 revert를 연속으로 하여 되돌아가야 합니다.
$ git revert <직전커밋 id>
notion imagenotion image
vi editor가 실행되면 메시지를 입력해야 하는데 :wq를 입력한 다음 빠져나옵니다.
메모장을 확인해보시면 revert는 commit 4를 하였는데 내용은 commit 3가 된 것을 볼 수 있습니다.
1 hello world 2 hello world 3 hello world
READEME.md
이처럼 돌아가고 싶은 내용이 있다면 바로 직전의 commit으로 revert해야 합니다.
$ git log
notion imagenotion image
이 상태에서는 commit 3로 revert 할 수 있습니다. 아래 이미지는 commit 3로 revert한 것이고, README.md 파일도 수정이 된 것을 볼 수 있습니다.
notion imagenotion image
1 hello world 2 hello world
이처럼 revert는 이전의 내역들을 지우지 않으면서 그 바로 직전 시점으로 되돌아가게 합니다.

5. cherry-pick

여러가지 커밋 중에 내가 원하는 커밋만 가져와서 현재 브랜치에 붙일 수 있습니다.
cherry-pick 하기 전cherry-pick 하기 전
cherry-pick 하기 전
cherry-pick 한 후cherry-pick 한 후
cherry-pick 한 후
 
예를 들면,
  1. 브랜치에 버그가 생긴 경우 버그를 고쳐서 main 브랜치에 merge
  1. main에 수정 사항이 많아 당장 머지를 할 수 없는 상황이나 릴리즈 브랜치에는 버그 수정커밋이 들어가야할 때, main에서 버그 수정 커밋만 떼어서 붙임
 
우선 main 브랜치와 cherry 브랜치가 있다고 가정하겠습니다.
$ git branch cherry $ git switch cherry
 
cherry 브랜치에서 README.md를 수정하고 add > commit 을 하겠습니다.
$ git add README.md $ git commit -m "commit message"
 
다시 main 브랜치로 돌아와서 cherry-pick 을 사용하여 cherry 브랜치에서 커밋을 가져오도록 하겠습니다.
$ git log $ git switch main $ git cherry-pick commit-id
 
notion imagenotion image