Git 기본 기능
git config
git config는 git의 글로벌 설정값들을 조회, 변경할 수 있는 명령어이다.
현재 git config에 등록되어있는 값 모두 조회 (git 사용자 계정도 이 명령어로 확인 가능)
git config --global --list
git 사용자 계정 변경
git config --global user.name "username"
git config --global user.email "mailname@example.com"
git clone
원격 레포지토리에 있는 코드를 로컬에 받을 수 있다.
git clone https://github.com/username/projectname.git
git add
루트 디렉터리(.git파일이 있는 디렉터리) 내부에서 수정된 추적되지 않은 변경사항(Unstaged)들을 추적된 상태(Staged)로 바꾸어준다.
// 모든 파일
git add .
// 특정 파일
git add Assets/Resources/ScriptableObjects/Effect/GroupEffect.meta
git add "Assets/Resources/ScriptableObjects/Effect/GroupEffect.meta"
git status
현재 레포지토리의 상태(변경사항, 충돌여부, 문제가 있는지 등등)를 확인한다.
git status
git commit
스테이징된 변경사항들을 로컬 레포지토리에 저장한다.
git commit -m "comments changed."
git reset
특정 커밋으로 reset하는 기능이다. 예를 들어 a, b, c 커밋을 한 후, c 커밋에 문제가 있다고 판단되어 b 커밋으로 돌아가고 싶은 경우 b 커밋으로 reset하면 된다. 그러면 reset 대상 커밋 이후의 이력은 모두 삭제된다.
reset에는 hard, mixed, soft와 같이 3가지 기능이 존재한다.
reset을 하기 전에 먼저 커밋 리스트를 확인한다.
git log
commit 0b1a65352bb40aae0c65ebfa416349b14683c598 (HEAD -> master, origin/master, origin/HEAD)
Merge: 72ea2ea da4c3ae
Author: <EC><9E><84><EC><9D><B8><EC><84><AD>
Date: Wed Oct 26 20:04:50 2022 +0900
Merge branch 'master'
commit 72ea2eaaded3950ba2aa0b02e8ad63748d7305e5
Author: <EC><9E><84><EC><9D><B8><EC><84><AD>
Date: Wed Oct 26 20:04:37 2022 +0900
feature: version updated
commit da4c3aefede3ee78827222cf476a43d14466cf03
Merge: 900d7cc c96c98c
Author:
Date: Wed Oct 26 18:32:50 2022 +0900
Merge branch 'master'
..
여기에서 2개의 커밋 이전으로 되돌리고 싶은 경우 다음과 같이 하면 된다.
git reset --soft HEAD~2
여기에서 da4c3aefede3ee78827222cf476a43d14466cf03 커밋으로 되돌아가고 싶은 경우 다음과 같이 하면 된다.
git reset --hard da4c3aefede3ee78827222cf476a43d14466cf03
git push 되돌리기
원격의 push를 되돌려야하는 경우 위 예제처럼 reset으로 먼저 로컬 커밋을 되돌린 후, 원격에 push 를 진행하면 된다. 하지만, 위처럼 reset을 진행한 후 push를 하게 된다면 오류가 발생할 것이다. 이는 로컬 저장소의 커밋 히스토리가 원격보다 뒤에 있어서 발생하는 오류이다. 이때 push 에 --force, -f 옵션을 주어 강제로 덮어쓸 수 있다. 만약 모든 히스토리를 남겨야 하는 경우 revert를 이용하는 방법도 있다.
git revert
위처럼 강제로 되돌릴 경우에는 다른 팀원들과 공유하는 원격 저장소의 커밋 히스토리가 강제로 조작된다는 문제가 있다. 이러한 상황을 피하기 위해 사용하는 것이 git revert이다. git revert는 특청 커밋을 되돌리는 작업까지도 하나의 커밋으로 간주하고 히스토리에 추가시키는 기능이다. 그러므로 히스토리가 망가지지 않도록 하면서 원하는 작업을 되돌릴 수 있다.
기본적인 방법으로는 원하는 커밋지점까지 갈때까지 커밋을 하나씩 revert하는 것이다.
commit history가 다음과 같다고 생각해보자.
commit fcb2d685c2de5ddc56959c534091dd87310caf1f (HEAD -> master, origin/master, origin/HEAD)
commit e570e9624f61eea5379e98a9143f2a6e875dbf0e
commit 1586f53a616cd55339013b33ba111a990e02e4d7
커밋 1586f53a616cd55339013b33ba111a990e02e4d7 까지 가려면 다음과 같이 하면 된다.
git revert fcb2d685c2de5ddc56959c534091dd87310caf1f
git revert e570e9624f61eea5379e98a9143f2a6e875dbf0e
git revert 1586f53a616cd55339013b33ba111a990e02e4d7
git log
현재까지의 모든 커밋 내용 보기
git log
특정 파일의 모든 커밋 내용 보기
git log <filename>
특정 파일의 모든 커밋 내용과 변경사항 보기
git log -p --word-diff <filename>
간단한 그림 형태로 log 표시
git log --graph
git blame
특정 파일에 대해 누가 언제 어떻게 수정했는지 기록을 볼 수 있다.
git blame <filename>
git branch
브랜치를 생성하거나 제거하는 등 여러 명령을 수행할 수 있다.
브랜치 목록 보기
// 로컬 브랜치 목록
git branch
// 원격 브랜치 목록
git branch -r
브랜치 생성
git branch <branchname>
브랜치 제거
git branch -d <branchname>
git checkout
브랜치를 이동시킬 수 있다.
특정 브랜치로 이동
git checkout -b <branch>
리모트의 특정 브랜치를 가져오고 해당 브랜치로 이동
git checkout -t origin/<branch>
특정 커밋으로 이동
git checkout 38f1e2c216b01cdcd0421950a0688020784d62bd
특정 커밋으로 브랜치를 생성하며 이동
git checkout -b temp_branch 38f1e2c216b01cdcd0421950a0688020784d62bd
git merge
A branch의 내용을 B branch에 넣고싶은 경우, git merge를 이용하면 된다.
git checkout B
git merge A
git remote branch 제거
제거 대상 브랜치가 checkout 되어있으면 제거가 되지 않는다.
git branch -d branch_name
git push origin --delete branch_name
git commit undo
실수로 커밋을 했을때 가장 최신 커밋을 되돌리는 방법이다.
git commit -m "blabla" # (Your Accident)
git reset HEAD~
<< edit files as necessary >>
git log
현재까지의 커밋 리스트를 확인할 수 있다.
git log
git restore
현재까지 작업하던 사항을 다시 되돌리고 싶은 경우가 있을 수 있다. 이런 경우 git restore를 이용하면 된다. 예를들어 AAA.cpp라는 파일의 코드를 수정하였을 때 unstaged 파일 목록에 AAA.cpp가 뜰 것이다. 이때 이 파일의 수정사항을 다시 되돌리려고 한다면 다음과 같이 하면 된다.
git restore "AAA.cpp"
그러면 파일이 이전 상태로 되돌릴 수 있다. 또한 파일이 되돌려졌기 때문에 unstaged 목록도 비어 있을 것이다.
git stash
현재까지 작업하던 사항을 잠시 치워두고 다른 작업을 해야하는 경우가 있을 수 있다.
예를들면 마지막 커밋 이후로 갑자기 프로젝트가 망가져서 빌드가 안되는 상황이 생겼다고 가정했을 때,
최근 수정된 내용을 잠시 저장해두고 가장 최근의 세이브지점부터 원인을 다시 추적해볼 수 있다.
그 이후에 원인을 찾으면, 다시 수정된 사항을 가져와서 문제가 되는 부분만 제거해주면, 작업 효율이 비약적으로 좋아질 것이다.
현재까지의 작업 목록을 stash stack에 저장한다.
git stash
stash stack의 list를 확인한다.
git stash list
stash@{0}: WIP on master: 2dfca33 test map fixed
stash@{1}: WIP on master: 77acd29 Merge branch 'master' of ...
원하는 stash 상태로 돌아간다. (git stash apply stashID)
git stash apply stash@{0}
stash list 내역을 지운다.
git stash drop stash@{0}
가장 최신 상태로 돌아가면서 동시의 리스트를 지우는 방법도 있다.
git stash pop
특정 파일만 stash 하는 방법
git stash push <path>
현재까지의 변경사항을 다른 branch에 저장하기
git stash를 활용하면 현재까지의 변경사항을 새 branch에 저장할 수 있다.
git stash
git checkout other-branch
git stash pop
git fetch
git fetch를 수행하면 현재 브랜치에 존재하지 않는 커밋을 현재 브랜치에서 수집 한 다음 로컬 리포지토리에 저장한다. 현재 로컬의 상태와 병합하지 않는다.
git filter
git에서 특정 파일의 히스토리를 모두 지우고 싶은 경우가 있다. 예를 들면 api-key를 git에 올려서 히스토리에 key가 남는 경우 난감해질 수 있다. 이 경우 다음과 같은 명령으로 해결할 수 있다.
git filter-branch --tree-filter "rm -f Path/To/Your/File.txt" -- --all
이렇게 수정한 후 push를 하려 하면 에러가 생긴다. 로컬에서는 히스토리가 지워졌지만 remote에서는 아니기 때문이다. 그러므로 강제 푸쉬 (-f push)를 수행하여야 한다. 그리고 이 repo를 참조하고 있는 다른 사람들의 경우 pull을 받더라도 기존 히스토리가 그대로 남아있는데, 이 문제도 해결해야한다.
Git Remote
원격 레포지토리와 관련된 명령어이다.
git remote url 조회
현재 git의 리모트에 연결된 url을 가져오는 명령어이다.
git remote get-url origin
git remote 레포지토리 연결하기
현재 로컬 레포지토리를 생성되어있는 리모트 레포지토리에 연결시키는 방법이다.
git remote add origin github.com:username/repo.git
git remote 레포지토리 변경하기
현재 연결되어있는 리모트 레포지토리를 변경하는 방법이다.
git remote set-url origin <git url>
git remote 레포지토리 옮기기
현재 작업중인 git 레포지토리를 다른 위치로 옮기고 싶을 수 있다. 이 때 현재까지 작업중인 commit history등 git의 모든 내역까지 옮겨야할 것인데, git remote 레포지토리 변경하기를 응용하면 된다.
cd existing-project
git remote set-url origin <git url>
git push -u origin --all
Git Submodule
Git으로 여러 프로젝트들을 관리하다보면, 조금 복잡한 구조가 생기게 된다. 다음과 같은 상황을 가정해보자.
A와 B라는 프로젝트가 있다. 그런데 프로젝트를 진행하면서 A와 B 프로젝트 모두 공통적으로 사용하는 모듈이 있다는 것을 알게 되었다. 했던 작업을 굳이 한번 더 할 필요가 없기 때문에, 중복되는 기능들을 하나의 모듈로 묶어서 새로운 프로젝트 C를 생성하기로 했다. 그 다음 A와 B가 C를 포함하도록 설계하면 생산성이 향상될 것이다. 하지만 아직 형상관리 차원에서의 문제까지 해결된 것은 아니다. C의 어떤 기능을 수정했을 때, A와 B가 각자 C를 포함하고 있다면, A의 포함된 C에도 이 수정사항을 적용하고, B에 포함됨 C에도 이 수정사항을 적용해 주어야 할 것이다. C를 사용하는 프로젝트가 많아질수록 이 문제는 심각해질 것이다. 그런데 만약 C라는 프로젝트는 하나의 repository만 갖고있고, A와 B가 이것을 참조하는 형태로 바뀐다면 어떻게 될까? C를 수정하는 순간, C를 참조하는 모든 프로젝트들에는 그 수정사항이 반영될 것이다. 이 구조를 가능하게 하는것이 submodule이다. C 프로젝트에 대한 repository를 git으로 생성하고, A와 B의 repository에서는 C를 submodule로 참조하도록 설계하는 것이다.
git submodule 세팅 - Unreal Plugin
언리얼 플러그인을 언리얼 메인 프로젝트의 서브모듈 프로젝트로 두는 예제이다.
1. PluginExample 이름의 플러그인을 만든다. (서브모듈이 될 프로젝트)
2. PluginExample 플러그인을 git repository로 만든다.
3. PluginParentSample 이름의 프로젝트를 만든다.
4. PluginParentSample 프로젝트를 git repository로 만든다.
5. PluginParentSample에서 PluginExample 을 submodule로 추가한다.
git submodule add https://github.com/insooneelife/PluginExample.git Plugins/PluginExample
6. 이제 PluginExample에서 수정된 사항이 있으면 바로 PluginParentSample에 반영시킬 수 있다.
git submodule update --recursive --remote
이 방법 외에도 submodule 디렉터리로 이동하여 직접 pull을 받아도 된다.
7. PluginParentSample 프로젝트에서 submodule의 add files가 목록에 뜨지 않도록 세팅하자.
.gitmodules 파일에 다음과 같이 추가한다.
[submodule "Plugins/PluginExample"]
path = Plugins/PluginExample
url = https://github.com/insooneelife/PluginExample.git
ignore = all
이제 PluginParentSample 프로젝트에서 git status를 해도 Plugins/PluginExample 경로가 unstaged로 잡히지 않는다.
그러므로 수정하고싶은대로 수정하고 커밋 후 올려도 PluginExample의 코드는 stated로 잡히지도 않고 올라가지도 않는다.
만약 PluginParentSample 프로젝트에서 PluginExample 코드를 수정하고 올리고 싶다면, Plugins/PluginExample/ 디렉토리로 이동하여 직접 커밋을 하면 된다.
8. 새로운 레포지토리에서 메인모듈부터 서브모듈까지 모두 받으려면 다음과 같이 하면 된다.
git clone <main repository url>
git submodule init
git submodule update --remote --recursive
git submodule 지우기
서브모듈을 참조하는 레포지토리에서 서브모듈을 완전히 제거하는 방법이다.
git submodule deinit -f -- <submodule_dir>
rm -rf .git/modules/<submodule_dir> (window에서는 폴더를 직접 지우면 됨)
git rm -f <submodule_dir>
ex)
root에서 IamBowlerWebServer라는 레포지토리를 clone한 케이스에서
git submodule deinit -f -- IamBowlerWebServer
rm -rf .git/modules/IamBowlerWebServer
git rm -f IamBowlerWebServer
git submodule 교체
서브모듈을 다른 모듈로 교체하는 방법이다.
방법 1.
1. 먼저 기존 submodule을 지운다. (git submodule 지우기 참조)
2. .gitmodules 파일을 생성한다.
3. 새로운 모듈을 추가한다.
git submodule add <url> Plugins/PluginExample
방법 2.
1. .gitmodules의 서브모듈 url을 새로운 url로 수정한다.
2. git submodule을 동기화시킨다.
https://stackoverflow.com/questions/913701/how-to-change-the-remote-repository-for-a-git-submodule
submodule을 포함한 repository를 받기
1. 레포지토리를 clone하고 연결된 모든 서브모듈을 받는다.
git clone <repository>
git submodule update --init --recursive
2. 클론 후 서브모듈들의 branch는 임시 branch에 놓이게 되므로 master로 이동시켜준다.
cd <submodule_dir>
git checkout master
submodule 지웠다 다시 받기
서브모듈 디렉토리가 망가진 경우 다시 받아야 할 수 있다.
1. 서브모듈 디렉토리를 지운다. (망가졌다고 가정)
2. 서브모듈을 포함한 레포지토리의 root로 이동하고 서브모듈을 다시 받는다.
cd <repository_root>
git submodule update --init --recursive --remote
GitIgnore
git을 사용하다 보면, 형상관리 목록에서 빼주고 싶은 내용들이 생길 수 있다.
Binary 파일들 같은 경우가 좋은 예시가 될 것이다.
이러한 파일들은 프로그램을 실행할 때마다 새로 생기고, 또 용량도 많이 차지하게 때문에 굳이 형상관리를 할 필요가 없다. 이러한 형상관리에서의 예외파일의 목록을 gitignore라는 파일에 작성하면 된다.
파일 이름을 .gitignore로 만들고, git repository에 넣으면 git이 자동으로 이 파일을 인식하고, 파일 내용들을 참고하여 예외 목록들을 만든다.
// .o, .obj로 끝나는 모든 파일
*.o
*.obj
// Binaries 폴더 내부의 모든 파일
Binaries/*
// Plugins 폴더 내부 모든 폴더의 Binaries 폴더 내부의 모든 파일
Plugins/*/Binaries/*
// Build 폴더 내부의 모든 폴더에서 PakBlacklist로 시작하는 .txt파일은 예외로 둠
!Build/*/PakBlacklist*.txt
Unreal .gitignore
github.com/github/gitignore/blob/master/UnrealEngine.gitignore
Git Commit Template
Git commit message 템플릿을 설정하는 방법이다.
먼저 .gitmessage 파일을 생성한다.
그 후 이 파일을 git 기본 템플릿 파일로 config에 등록시킨다.
이후로 git commit을 하면 .gitmessage 파일 내 template 메시지가 표시된다.
git config --global commit.template .gitmessage
다음으로 .gitmessage 파일에 템플릿 메시지를 넣는다.
#으로 표시된 메시지는 주석처리되므로 commit에 들어가지는 않는다.
그 외 메시지는 template 메시지로 commit에 포함된다.
# Template
# {Commit Type}: short message [Issue NO]
#
# Commit Type
# [build, ci, chore, docs, feature, add, delete, fix, perf, refactor, style, test, refactor]
#
# Example
# feature: commit message here. [00000]
template message
커밋을 통해 사용해본다.
git commit
bash 파일에 커밋 메시지를 포함한 텍스트가 표시될 것이다.
i 키를 눌러서 텍스트를 편집하고, esc, :, w, q, enter 를 눌러서 메시지를 저장하면 커밋이 완료된다.
Git LFS
Git Large File Storage (Git LFS)는 git에서 용량이 큰 파일들만 좀 더 효과적인 방법으로 관리하기 위해 만들어진 모듈이다. 일반적인 상황에서는 많이 이용되지 않지만, 프로젝트가 커지면서 소스코드와 같은 텍스트 타입의 파일 외의 사이즈가 큰 형태의 리소스 파일을 레포지토리에 올리게 되면서 사용하게 된다.
프로젝트에 100MB 크기의 파일이 있고, 이 파일을 100번 수정한다고 가정해보자. 기본 Git을 사용하면 모든 변경 사항이 저장소에 저장된다. 따라서 100번의 수정이 누적되어 최종 저장소 크기가 10GB가 된다. 결국, 저장소를 클론할 때마다 10GB를 다운로드해야 하며, 클라이언트의 디스크 공간도 10GB를 차지한다.
Git LFS 적용한다면, 저장소에는 각 파일 버전에 대한 포인터만 저장되므로, 클론할 때는 소량의 데이터만 다운로드한다. 실제 파일은 필요한 버전만 다운로드하므로, 100MB만 다운로드된다. 그러므로 디스크 공간을 크게 절약할 수 있고,용하면 큰 파일로 인해 발생하는 저장소 크기 문제를 해결할 수 있으며, 클론과 체크아웃 시 필요한 데이터 양을 줄여 효율적으로 관리할 수 있다.
단, lfs로 소스코드 파일도 추적해버리면 소스코드의 conflict가 발생한 경우 골치아파질 수 있다. 그러므로 소스코드와 같은 파일 내용의 부분부분에 충돌이 일어날 수 있는 파일들은 git으로 관리하고, 텍스트, 이미지와 같은 용량이 큰 리소스들은 git lfs로 관리하는 것이 효과적이다.
기본
먼저 git lfs를 설치한다.
설치가 완료되었다면 개발중인 프로젝트의 .git 파일이 있는 위치에서 다음 명령을 통해 lfs를 초기화한다.
git lfs install
다음으로 추적할 파일 or 폴더를 지정해준다. 보통 큰 용량을 갖는 리소스들만 모아 둔 폴더를 따로 추적하도록 한다.
// folder 하위의 모든 파일들을 추적
git lfs track "folder/**"
이 작업이 끝난 후에는 .gitattributes 라는 파일이 생성되는데, 이 파일에는 lfs와 관련된 세팅값들이 설정되어있다. lfs 설정값도 공유를 할 것이라면, 이 파일도 레포지토리에 추가해 주어야한다.
git add .gitattributes
git commit -m "lfs"
git push origin master
git lfs untrack
git lfs로 추적중인 파일들에 대해 추적을 해제하고 싶을 수 있다. 그런 경우 다음과 같이 명령어를 작성하면 된다.
git lfs untrack "folder/**"
git rm --cached "folder/**"
그 후 변경사항을 저장한다.
git add .
git commit -m "restore lfs files"
Git LFS를 쓰는 이유
https://stackoverflow.com/questions/35575400/what-is-the-advantage-of-git-lfs
GitHub
과거 커밋 시점의 프로젝트 코드 보기
1. 레포지토리 선택
2. 커밋 히스토리 선택
3. 조회를 원하는 커밋 시점의 프로젝트 히스토리 선택
4. 이제 해당 시점에서의 프로젝트를 작업할 수 있다.
SSH를 이용하여 Github Private Repository에 접근하기
자동으로 github repository를 clone하는 스크립트를 만들다 보면 github의 private repository에 접근해야하는 상황이 생긴다. 하지만 public과 달리 private은 일반적인 방법으로는 접근이 불가능하다. Github에서 지원하는 인증 방법들 중 ssh를 이용하여 이 작업을 수행해보자. (이 작업을 수행하려면 먼저 private repository가 있어야 한다.)
1. SSH Key 생성
윈도우에서는 Window PowerShell을 이용하여 SSH Key를 생성시킬 수 있다.
ssh-keygen -t rsa -b 4096
따로 디렉토리를 지정해주지 않으면 C:/Users/username/.ssh 디렉토리에 private 키와 public 키가 생성된다.
(id_rsa, id_rsa.pub)
2. Github private repository에 SSH Key(Public) 등록
이제 생성된 ssh 키 중에서 public 키(id_rsa.pub)를 github에 private repository에 등록해주어야한다.
Github -> Repositories -> 사용할 private repository -> Settings -> 좌측 -> Deploy keys -> Add deploy key
타이틀을 지정하고 Key 칸에 public 키의 내용물을 모두 복사하여 넣는다.
이제 ssh 키가 등록되었으므로, private 키를 이용한 ssh 인증을 통해 외부에서도 접근할 수 있다.
3. SSH repository url을 이용하여 git 이용
SSH를 이용하는 url은 기존 url과는 조금 다르다. Github에 프로젝트 레포지토리에서 기존 HTTPS clone url을 복사하는 위치 옆에 ssh url 도 선택할 수 있게 되어있다.
# https
https://github.com/username/repositoryname.git
# ssh
git@github.com:username/repositoryname.git
이제 이 url을 이용하면 외부에서도 private repository를 clone할 수 있다.
대신 윈도우에서 ssh를 이용하려면 먼저 C:/Users/username/.ssh 디렉토리로 이동해야한다. 해당 디렉토리에서 cmd를 실행시킨 후 다음 명령을 통해 ssh clone을 수행할 수 있다.
이 명령을 통해 private repository가 잘 clone됨을 확인할 수 있다.
git clone git@github.com:username/repositoryname.git
(주의할 점은 생성된 키의 이름을 바꾸면 동작하지 않는다.)
Github Action
'Tool' 카테고리의 다른 글
[Tool] Visual Studio 기능 정리 (0) | 2020.11.12 |
---|