Git 유용한 명령어

Git 각종 명령어 정리

Git 유용한 명령어

이전 글

Git Branch와 Merge
Git 버전 관리의 핵심 Branch와 Merge를 알아보자

들어가며

본 포스트에서는 그동안 배웠던 명령어들 외에 편리하지만 별도의 글로 명령어를 알아보도록 하겠습니다. 원하는 명령어를 찾으려고 하신다면 목차를 참고하시거나 Ctrl+F를 권장합니다. 막 암기하려고 하기보단 참고하면서 자주 사용하다 보면 자연스럽게 나오게 되니 마음 편히 띄워 놓고 작업하세요 :)

Local Repository

생성

다음 명령을 실행한 디렉토리는 Git Local Repository가 됩니다.

git init

Remote Repo 추가, 조회, 삭제

로컬 레포에 연결할 원격 레포를 설정합니다. 주 원격 브랜치의 이름은 보편적으로 origin으로 설정합니다.

git remote add 원격레포명
git remote add origin

주 브랜치 이름 설정

주로 사용할 브랜치의 이름을 설정할 수 있습니다. 보편적으로 main 혹은 master를 사용합니다.

git branch -M 주브랜치명
# 주 브랜치 이름을 main으로 설정
git branch -M main 

# 주 브랜치 이름을 master로 설정
git branch -M master

커밋 생성, 업로드, 다운로드

커밋 생성 및 업로드: add - commit - push

Git은 파일의 변경 사항을 추적하고 커밋으로 만들 파일 변경 사항을 구분하기 위해 Staging 영역을 만들어 관리합니다. 파일의 상태를 Modified, Staged, Commited로 구분하여 어떤 파일이 변경되었고 어떤 파일을 커밋할지 선택합니다. 자세한 내용은 해당 내용을 다룬 글을 참고해 주세요!

# 경로가 파일명이라면 해당 파일만, 디렉터리일 경우 하위 파일들을 모두 Stage
git add 경로

# Staged 상태인 변경 사항을 Commit
git commit -m "커밋메시지"

# 로컬 레포의 변경 내역을 원격 레포에 저장
git push 원격레포명 원격브랜치명
git add .
git commit -m "Feat: implement login"
git push origin master

Local Repo 최신화: fetch

원격에 업로드된 타 사용자 혹은 타 환경에서의 작업 내역을 동기화해야 하는 경우가 있습니다. 원격 레포의 변경 사항을 Fetch하여 브랜치 및 각종 설정 등의 변경 사항을 반영합니다. 원격에 생성된 브랜치 정보를 가져오는 등 업데이트가 필요할 때 사용하시면 됩니다.

# 브랜치, 설정 등의 변경사항 로컬 레포에 반영
git fetch

커밋 수정

마지막 커밋 메시지 수정: --amend

최근 커밋 메시지를 수정하려면 amend 옵션을 사용합니다.

git commit --amend

명령을 실행하면 파일 하나가 열립니다.

fix: remove unused location hook

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# 시각:      Sun Sep 24 18:30:44 2023 +0900
#
# 현재 브랜치 main
# 커밋할 변경 사항:
#       수정함:        src/components/Header.tsx
#
# 추적하지 않는 파일:
#       src/hooks/
#

첫줄에 최신 커밋의 메시지가 있고 그 아래에는 사용 방법 및 레포지토리의 상태가 주석처리되어 적혀 있습니다. 메시지 수정은 첫줄의 메시지를 수정한 뒤 저장하면 반영됩니다.

단, 원격에도 올라가 있는 커밋의 메시지를 수정 하면 로컬에서 push할 때 오류가 발생합니다. 이때는 Force Push를 해야 하나, 가급적 원격에 올라간 커밋을 조작하는 일은 없도록 하는 것이 최선이라는 점을 잊지 맙시다.

만약 메시지를 수정하려는 커밋이 최신 커밋이 아니라면 rebase 명령어를 사용해야 합니다. 상세한 내용은 바로 아래의 커밋 수정 부분을 참고해 주세요!

일괄 수정: rebase -i

커밋의 메시지, 순서, 작업 내역 등을 수정하거나 여러 개로 나누어진 커밋들을 합치고 싶어지는 경우가 있습니다. 하지만 amend 옵션으로는 최신 커밋의 메시지를 수정하는 정도밖에 되지 않습니다. 그 전 커밋을 수정하는 데는 Rebase를 활용해야 합니다.

# 수정할 커밋의 수는 최신 커밋부터 몇 개의 커밋을 수정할지 그 개수를 적으면 됩니다.
git rebase -i HEAD~수정할커밋수
git rebase -i HEAD~5

명령을 실행하면 기본 에디터로 파일 하나가 열립니다.

pick ee91a91 fix: remove redundant useEffect from header
pick fcd5115 correct: use absolute path
pick 36d8d32 fix: enable absoulte path correctly
pick 4f666b2 refactor: separate nav items into component
pick 908f892 fix: remove unused location hook

# Rebase 4be441d..908f892 onto 4be441d (5 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
#                    commit's log message, unless -C is used, in which case
#                    keep only this commit's message; -c is same as -C but
#                    opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
#         create a merge commit using the original merge commit's
#         message (or the oneline, if no original merge commit was
#         specified); use -c <commit> to reword the commit message
# u, update-ref <ref> = track a placeholder for the <ref> to be updated
#                       to this position in the new commits. The <ref> is
#                       updated at the end of the rebase
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# 여기 줄을 제거하면 해당 커밋을 잃어버립니다!
#
# However, if you remove everything, the rebase will be aborted.
#

아래 주석 처리된 부분을 보면 해당 파일을 수정하는 방법을 알 수 있습니다. 첫줄부터 목록으로 주어지는 커밋들 앞의 키워드를 변경하면 그에 맞게 수정할 수 있습니다. 자주 사용하는 키워드는 다음과 같습니다.

  • reword
    해당 커밋의 커밋 메시지를 수정합니다.
  • squash
    해당 커밋을 그 전 커밋과 합칩니다.

커밋의 순서를 변경할 경우 변경된 순서를 반영합니다. 다만, 이러한 수정 이후에는 커밋의 해시값이 바뀝니다. 즉, 기존 커밋을 수정한다기보단 반영된 수정사항대로 커밋을 새로 만드는 것에 가깝습니다.

기존 커밋을 수정하는 명령이므로 신중하게 사용하되 가급적이면 원격에 올린 커밋에는 사용하지 않는 것을 권장합니다.

Reset

이전 커밋으로 돌아가기: reset HEAD

최근 커밋들을 제거하고 이전 커밋으로 돌아가기 위해서는 reset 명령어를 활용합니다. 명령을 실행한 뒤에는 커밋 제거 후 마지막 커밋으로부터 현재까지 수정한 사항이 Modified 상태로 돌아갑니다. 만약 이 변경 사항들을 모두 버리려면 바로 아래의 최신 커밋 상태로 되돌리기를 참고해 주세요.

# [커밋개수]개 만큼의 커밋을 되돌립니다.
git reset HEAD~커밋개수
# 최근 2개의 커밋을 제거합니다.
git reset HEAD~2

최신 커밋 상태로 되돌리기: reset --hard

최신 커밋으로부터 변경된 모든 사항을 되돌리려면 다음을 실행합니다.

git reset --hard

명령 실행 후 Modified 상태였던 모든 파일들이 최신 커밋 버전으로 돌아가며 Commited 상태가 됩니다. 단, 스테이지한 적 없는 Untracked 파일들에는 아무런 변화가 없습니다. Untracked 파일들을 제거하려면 아래의 추적하지 않는 파일 제거를 참고해 주세요.

특정 파일만 리셋: restore

전체를 되돌리지 않고 특정 파일만 리셋하고 싶은 경우가 있습니다. 이 경우 restore 명령어를 사용합니다.

git restore 경로
git restore file.txt

실행 후 해당 파일 혹은 디렉터리는 최신 커밋 상태로 돌아가며 Commited 상태가 됩니다.

첫 커밋 취소: update-ref -d

git reset 명령어로는 첫 번째 커밋을 취소할 수 없습니다. 브랜치를 삭제하거나, 다음 명령어를 사용하여 첫 커밋을 취소하면 됩니다.

git update-ref -d HEAD

Stash

파일들을 최신 커밋 상태로 되돌리되 현재까지의 변경 사항은 따로 저장하고 싶다면 stash 명령어를 사용합니다. 리베이스나 병합을 위해서는 Modified 상태인 파일이 없어야 하는데, 임시로 이를 해결하기 위해 사용하거나 현재 작업 내용을 타 브랜치에 적용할 때 사용하는 경우가 있습니다.

생성

git stash

저장한 변경 사항을 다시 적용하려면 다음 명령을 실행합니다.

git stash apply

한 번에 여러 스태시를 만들 수도 있는데, 이 때는 각 스태시마다 번호가 부여됩니다. list 명령어로 목록과 이름을 확인하고 apply에 이름을 명시하여 원하는 스태시를 적용할 수 있습니다.

조회하고 이름으로 적용

$ git stash list
stash@{0}: WIP on main: 908f892 message here
stash@{1}: WIP on develop: 102d898 some other message here

$ git stash apply stash@{0}
현재 브랜치 main
커밋하도록 정하지 않은 변경 사항:
  (무엇을 커밋할지 바꾸려면 "git add <파일>..."을 사용하십시오)
  (use "git restore <file>..." to discard changes in working directory)
	수정함:        src/App.tsx
	수정함:        src/components/Header.tsx

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

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

적용한 뒤에는 각 파일이 Modified 상태가 되는데, 스태시하기 전에 add 명령어로 스테이지한 사항이 반영되지 않아 다시 add해 줘야 합니다. 만약 스테이징 상태까지 반영하려면 --index 옵션을 주면 됩니다.

$ git stash apply stash@{0} --index
Saved working directory and index state WIP on main: cdb5440 fix: remove unused location hook
➜  realworld git:(main) git stash apply stash@{0} --index
<stdin>:63: trailing whitespace.

warning: 1번 줄에서 공백 오류를 추가합니다.
현재 브랜치 main
커밋할 변경 사항:
  (use "git restore --staged <file>..." to unstage)
	수정함:        src/App.tsx
	수정함:        src/components/Header.tsx
	새 파일:       src/hooks/useUserProfile.ts

--index 옵션이 없을 때는 커밋하도록 정하지 않은 변경 사항이었던 것이 커밋할 변경 사항이 된 것을 볼 수 있습니다.

다른 브랜치에 적용

스태시는 작업하던 브랜치가 아니더라도 적용할 수 있습니다. 단, 충돌하는 변경 사항이 있다면 관련 프롬프트로 안내해 줍니다. Merge Conflict Resolve 과정 때처럼 파일에 표시된 충돌 표시(<<< === >>>)를 없애고 적절히 수정한 뒤 add - commit하면 됩니다.

$ git stash apply
CONFLICT (modify/delete): middleware/page.js deleted in Updated upstream and modified in Stashed changes.  Version Stashed changes of middleware/page.js left in tree.
CONFLICT (modify/delete): middleware/report.js deleted in Updated upstream and modified in Stashed changes.  Version Stashed changes of middleware/report.js left in tree.
자동 병합: packages/kkujjang-api-server/src/middleware/notice.js
충돌 (내용): packages/kkujjang-api-server/src/middleware/notice.js에 병합 충돌
자동 병합: packages/kkujjang-api-server/src/middleware/user.js
충돌 (내용): packages/kkujjang-api-server/src/middleware/user.js에 병합 충돌
CONFLICT (modify/delete): utility/validation.js deleted in Updated upstream and modified in Stashed changes.  Version Stashed changes of utility/validation.js left in tree.
현재 브랜치 fix/game
병합하지 않은 경로:
  (use "git restore --staged <file>..." to unstage)
  (해결했다고 표시하려면 알맞게 "git add/rm <파일>..."을 사용하십시오)
	이 쪽에서 삭제: middleware/page.js
	양쪽에서 수정:  packages/kkujjang-api-server/src/middleware/user.js
	이 쪽에서 삭제: utility/validation.js

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

변경 사항 골라오기: cherry-pick

타 브랜치에서 작업한 커밋의 변경 내역을 가져와 적용하고 싶어지는 경우가 있습니다. 미처 switch하지 않은 채 develop 브랜치에서 작업한 내역을 feature 브랜치로 옮기고자 하는 상황이 그 예시입니다. 다음과 같이 사용 가능합니다.

git cherry-pick [커밋]

직접 여러 커밋을 한 번에 명시할 수도 있고, 표현식을 사용해 여러 커밋을 한 번에 다룰 수도 있습니다. 이후 과정은 Merge와 유사하게 진행됩니다. 커밋의 해시를 확인하는 방법은 GitHub 홈페이지나 아래의 로그 기능을 통해 확인할 수 있습니다.

로그 확인: log

프로젝트의 히스토리를 돌아보는 것도 중요합니다. 이때 Sourcetree나 GitKraken 등 여러 툴을 사용하는 것도 좋겠지만, CLI에서 확인할 일도 있을 것입니다. 이때 사용하는 것이 log 명령어입니다. 별도의 옵션 없이 실행하면 결과는 다음과 같습니다.

$ git log
commit 576c84074960a995ea0caacda856972f73b9f52a (HEAD -> master)
Merge: 3e43508 6d147ca
Author: Godbell <12191579@inha.edu>
Date:   Fri Dec 27 20:43:47 2024 +0900

    Merge feature branch

commit 6d147cae23c64146ed8a14db042e3361011a1936 (feature)
Author: Godbell <12191579@inha.edu>
Date:   Fri Dec 27 20:20:04 2024 +0900

    edit Main.java

commit 3e43508ea5a88767662957072d4114dfd1eedac0
Author: Godbell <12191579@inha.edu>
Date:   Fri Dec 27 20:19:44 2024 +0900

    edit Main.java

모든 정보가 한 번에 출력되는데, 좀 더 간단하게 보려면 oneline 옵션을 주면 됩니다.

$ git log --oneline
576c840 (HEAD -> master) Merge feature branch
6d147ca (feature) edit Main.java
3e43508 edit Main.java
36f65e8 add Main.java
2c5bea9 edit README
d979f27 (origin/main, main, feature1) 이렇게 여러 줄에 걸쳐서 작성할 수도 있습니다 닫는 따옴표 없이 엔터를 치면 이렇게 나오는데 따옴표를 닫고 엔터를 치는 순간
입력이 끝납니다

각 커밋이 더욱 간결한 형식으로 표시됩니다. 로그는 현재 브랜치만 표시됩니다.
저는 주로 그래프 옵션을 주어 모든 브랜치의 그래프를 체크하는 명령어를 많이 사용합니다.

$ git log --all --graph --oneline
*   576c840 (HEAD -> master) Merge feature branch
|\
| * 6d147ca (feature) edit Main.java
* | 3e43508 edit Main.java
|/
* 36f65e8 add Main.java
* 2c5bea9 edit README
* d979f27 (origin/main, main, feature1) 이렇게 여러 줄에 걸쳐서 작성할 수도 있습니다 닫는 따옴표 없이 엔터를 치면 이렇게 나오는데 따옴표를 닫고 엔터를 치는 순간 입력이 끝납니다

마치며

추가적으로 생각나는 자주 사용하는 기능 관련하여 꾸준히 본 글에 업데이트하도록 하겠습니다. 다음 글에서는 브랜치 관리 전략을 다뤄 보겠습니다.