git cli!
git
익숙하지 않은 git 명령어만 정리
branch, switch
# dev 브런치 생성
git branch dev
# stg 브런치 생성
git branch stg
# stg 브런치로 이동
git switch stg
# 모든 local branch, remote branch 출력
git branch -a
# dev
# main
# * stg
# remotes/origin/HEAD -> origin/main
# remotes/origin/main
# dev 브런치 삭제
git branch -d dev
switch
는 브랜치의 전환만을 위한 명령어.
git switch dev
checkout 은 branch 이외에도 사용되는 경우가 많아 branch 전환을 위해서는
switch
사용을 권장
checkout
checkout 이란 전환
이란 표현이 적용 가능한 모든 아이템에 적용 가능하다.
- branch 전환
- commit 전환
- 특정파일/디렉토리의 전환
- a 파일/디렉토리를 A브런지로부터 전환, 없다면 가져오고, 있다면 전환
# local dev 브런치로 전황
git checkout dev
# dev branch 로부터 dev.txt 가져오기/전환하기
git checkout dev -- dev.txt
# 해당 commit 로부터 main.txt 가져오기/전환하기
git checkout 417a0de -- main.txt
# 지금 어떤 branch 에 있든 상관없이 커밋 버전 이동
git checkout 417a0de
reset
잘못 올린 커밋 원격 리포지토리에서도 취소하기
git reset --hard "commit id"
# main 브런치에선 repository 가 보호되어있어 동작하지 않을 수 있음
git push -f
git reset --hard origin/master
git pull origin master
reflog
실수로 reset
한거 되돌리기
# 과거 commit 으로 강제 이동 및 push
git reset --hard 417a0de
git push -f
# 실수를 깨닫고 복원시작
# local 에서 참조변경기록 확인
git reflog
git reset --hard HEAD@{3}
local 에서만 관리하는 깃에대한 모든 참조변경기록
를 보관하고 있기 떄문에 이전 상태로 돌아갈 수 있음.
merge, rebase
https://gist.github.com/mitchellh/319019b1b8aac9110fcfb1862e0c97fb
모든작업이 main branch
로부터 충돌없이 업데이트된다면 문제는 발생하지 않는다.
하지만 branch
를 나누어 작업하다 보면 충돌은 생기게되고 이를 해결하고 병합하는 과정에서 merge commit
은 반드시 생기게된다.
merge
는 직관적이지만 추가적으로 commit 이 하나 더 생기게 된다.
main 과 dev branch
에 각각 dev.txt
을 생성후 각 브런치에서 수정 후 commit
,
그리고 main branch
에서 dev branch
를 병합하면 아래와 같은 형태로 history 가 구성된다.
o---o---o---o---M main branch
\ /
o---o---o dev branch
rebase
의 경우 아래처럼 branch
를 한줄로 관리할 수 있게 한다.
물론 합치는 과정에서 충돌은 발생하게 되며 충돌을 수정하는 과정에서 dev branch
의 커밋들은 변경된다.
원본 상태:
a---b---c main branch
\
A---B---C dev branch
rebase 후:
a---b---c---A'---B'---C' main branch
(dev branch)
해당 과정때문에 과거에 등록된 commit 들이 변경된 뒤 다시 등록될 수 있다,
이럴경우 force push
를 해야하는데 해당 branch
를 사용하는 다른 사용자들의 혼란을 야기할 수 있다.
자신만 사용하는 branch 에만 사용하는것을 권장한다.
squash 로 commit 기록 통합
아래와 같이 Update 1, Update 2, Update 3
3 개의 커밋을 만들었을 때 rebase
를 통해 합칠 수 있다.
git log --pretty=oneline
# 2d6e68bfb07c20d010e892726b29f11926807840 (HEAD -> dev, origin/dev) Update 3
# cd58900aa0be9962f900c66887a8854db428dd68 update 2
# 50a116474edaf738f883f85d82a776f812fef0a5 update 1
# 39c0a0de0d41cd13dd615c8eaf56b2da55805bbf (origin/main, origin/HEAD, main) add dev.txt comment
head
에서 총 3개의 commit
을 합치기
git rebase -i HEAD~2
위 명령을 실행하면 아래와 같이 3개의 commit 에 대한 처리를 진행하는 vi 입력창이 출력된다.
pick 50a1164 update 1
pick cd58900 update 2
pick 2d6e68b Update 3
# Rebase 39c0a0d..2d6e68b onto 39c0a0d (3 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
git push origin +<branch-name>
아래와 같이 맨 위 commit
을 합치는 기준(pick)으로 두고 squash 진행
pick 50a1164 update 1
s cd58900 update 2
s 2d6e68b Update 3
해당 명령또한 마찬가지로 force push
를 통해 이미 remote
에 commit
을 변경할 수 있음으로 신중히 사용해야한다.
bisect
commit –amend
마지막 commit
에 변경된 파일추가 및 commit
수정하기
해당 명령또한 마찬가지로 force push
를 통해 이미 remote
에 commit
을 변경할 수 있음으로 신중히 사용해야한다.
기존 커밋에 수정된 파일을 밀어넣고 메세지를 수정할 수 있다.
touch test-for-amend.txt
git add test-for-amend.txt
git commit --amend
# vi 창이 출력되면 commit 메세지 수정과 함께 커핏
commit –soft
마지막 커밋을 취소하고 변경된 파일을 다시 stage
로 돌리고 싶을때 사용.
local commit
만 사용하길 권장.
git reset --soft 97b88eb
git reset --soft HEAD^
rm –cached 원격 저장소 파일 삭제
git rm --cached .idea/modules.xml
git rm --cached -r .idea/
git commit -m "Fixed untracked files"
// 원격 저장소(origin)에 push
git push origin master
find . -name .DS_Store -print0 | xargs -0 git rm -f –ignore-unmatch |
checkout
브랜치 전환, 파일체크아웃, head 변경 등에 사용되는 만능명령어
commit을 원하지 않은 파일을 rollback 하고싶을때 아래와 같이 사용
git checkout dev
git checkout -b new-dev # 새로운 branch 생성
git checkout 58f0ab9 # 특정 커밋으로 HEAD를 이동
git checkout {filename}
remote
새로운 remote git 주소를 추가해서 branch 가 추가된것처럼 사용할 수 있다.
git remote add demo https://gitlab.my.company.com/demo-repo
# * main
# remotes/demo/main
# remotes/origin/HEAD -> origin/main
# remotes/origin/main
git fetch demo
git remote -v
# demo https://gitlab.my.company.com/demo-repo (fetch)
# demo https://gitlab.my.company.com/demo-repo (push)
# origin https://kouzie.com/demo-repo2 (fetch)
# origin https://kouzie.com/demo-repo2 (push)
git branch -a
# * main
# remotes/demo/main
# remotes/origin/HEAD -> origin/main
# 만약 demo/main 을 로컬에서 사용하고 싶다면 main branch 이름이 중복되기 때문에 local branch 를 추가생성해야함.
git switch -c demo-main demo/main
git merge <remote-name>/<branch-name> --allow-unrelated-histories
git rebase <remote-name>/<branch-name>
upstream
fork 한 프로젝트의 코드를 다른 위치에 원본 있는 프로젝트로부터 동기화해야 할 때 사용하는 명령어
git remote add upstream https://github.com/Kouzie/test-repo
git remote -v
# origin https://gitlab.my.company.com/demo-group/test-repo (fetch)
# origin https://gitlab.my.company.com/demo-group/test-repo (push)
# upstream https://github.com/Kouzie/test-repo (fetch)
# upstream https://github.com/Kouzie/test-repo (push)
git remote fetch # 원격 데이터 fetch
git merge upstream/main # upstream 의 main 으로부터 merge
git remote rm upstream # 로컬에 연결된 remote upstream 삭제
submodule
저장소 안에 또 다른 깃 저장소가 필요한 경우 사용.
하나의 Git 저장소 내에서 다른 Git 저장소를 서브디렉토리로 포함시키는 방법.
각 서브모듈은 독립된 Git 저장소로 관리되며, 상위 프로젝트와 별개로 버전 관리된다.
아래와 같이 3개의 repository 가 있을 때
git clone https://gitlab.my.company.com/test-group/root-module
git clone https://gitlab.my.company.com/test-group/sub-module-a
git clone https://gitlab.my.company.com/test-group/sub-module-b
root-module repository
에 sub-module repository
2개 를 submodule
로 삽입한다.
cd root-module
git submodule add https://gitlab.my.company.com/test-group/sub-module-a
git submodule add https://gitlab.my.company.com/test-group/sub-module-b
cat .gitmodules
# [submodule "sub-module-a"]
# path = sub-module-a
# url = https://gitlab.my.company.com/test-group/sub-module-a
# [submodule "sub-module-b"]
# path = sub-module-b
# url = https://gitlab.my.company.com/test-group/sub-module-b
각 디렉토리에는 별도의 .git
파일이 존재하고 commit 버전
을 기준으로 연결시키기 때문에 별도의 pull 처리를 해줘야 버전을 따라갈 수 있다.
또한 root repository
에서 어떤 commit 버전
을 사용할지도 결정해줘야 한다.
처음 서브모듈이 있는 git repository 를 git clone 하였을 때 서브모듈이 모두 비어있는 상태이다.
아래 init, update 명령을 통해 초기화 해야 한다.
git submodule init # 서브모듈 초기화
git submodule update # 서브모듈 업데이트
# 서브모듈의 하위 서브모듈까지 모두 업데이트
git submodule update --init --recursive
subtree
subtree는 하나의 Git 저장소 내에서 다른 Git 저장소의 내용을 특정 디렉토리로 병합하는 방법.
서브트리는 상위 프로젝트의 일부로 취급되며, 하나의 통합된 Git 기록을 가진다.
git clone https://gitlab.my.company.com/test-group/root-tree
git clone https://gitlab.my.company.com/test-group/sub-tree-a
git clone https://gitlab.my.company.com/test-group/sub-tree-b
git subtree add --prefix=sub-tree-a https://gitlab.my.company.com/test-group/sub-tree-a main
git fetch https://gitlab.my.company.com/test-group/sub-tree-a main
# warning: redirecting to https://gitlab.my.company.com/test-group/sub-tree-a.git/
# remote: Enumerating objects: 3, done.
# remote: Counting objects: 100% (3/3), done.
# remote: Compressing objects: 100% (2/2), done.
# remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
# Unpacking objects: 100% (3/3), 2.79 KiB | 570.00 KiB/s, done.
# From https://gitlab.my.company.com/test-group/sub-tree-a
# * branch main -> FETCH_HEAD
# Added dir 'sub-tree-a'
ls
# README.md sub-tree-a
subtree 는 기존 git 의 history 를 보존하면서 두 repository 를 합칠 수 있다.
git log
# 두 repository 의 로그가 모두 저장되어있는지 확인
subtree 에서 변경된 내용을 pull 해올 수 있고
root 에서 subtress 의 내용을 변경하고 push 할 수 있다.
git subtree pull --prefix=sub-tree-a https://gitlab.my.company.com/test-group/sub-tree-a main
# warning: redirecting to https://gitlab.my.company.com/test-group/sub-tree-a.git/
# remote: Enumerating objects: 4, done.
# remote: Counting objects: 100% (4/4), done.
# remote: Compressing objects: 100% (2/2), done.
# remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
# Unpacking objects: 100% (3/3), 258 bytes | 86.00 KiB/s, done.
# From https://gitlab.my.company.com/test-group/sub-tree-a
# * branch main -> FETCH_HEAD
# Merge made by the 'ort' strategy.
# sub-tree-a/testb.txt | 0
# 1 file changed, 0 insertions(+), 0 deletions(-)
# create mode 100644 sub-tree-a/testb.txt
git add .
git commit -m "add test.txt at subtree"
# root main 에다 push
git push
# subtree 에다가 push
git subtree push --prefix=sub-tree-a https://gitlab.my.company.com/test-group/sub-tree-a main
git push using: https://gitlab.my.company.com/test-group/sub-tree-a main
warning: redirecting to https://gitlab.my.company.com/test-group/sub-tree-a.git/
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 260 bytes | 260.00 KiB/s, done.
Total 2 (delta 1), reused 0 (delta 0), pack-reused 0
To https://gitlab.my.company.com/test-group/sub-tree-a
373ffb7..c76ee34 c76ee34422e3dcb9ecfcbe9c60bf9f7bdb3d08cc -> main
추가 옵션
subtree로 사용할 원격 저장소 추가
# git remote add <원격 저장소의 이름> <원격 저장소의 주소>
git remote add demo-lib https://gitlab.my.company.com/test-group/demo-lib
# demo-lib 라는 이름으로 새로운 원격 저장소가 추가되었다.
git remote
# origin
# demo-lib
새로운 원격 저장소의 브랜치를 서브트리로 추가
# git subtree add --prefix <클론할 폴더> <원격 저장소의 이름> <브랜치 이름>
git subtree add -P src/demo-lib https://gitlab.my.company.com/test-group/demo-lib main
.gitignore
깃허브에 올리지 말아야할 정보(OS, IDE 시스템정보 등)를 git 에 올리는 것을 방지,
대다수의 IDE 가 프로젝트 생성시 알아서 .gitignore
파일을 만들어 주지만
특수한 상황에서 직접 .gitignore
만들어야 할 때 아래 사이트 추천
위와같이 현재 사용중인 시스템 정보를 삽입하면 아래와 같은 설정이 자동으로 생성된다.
# Created by https://www.gitignore.io/api/git,java,maven,windows,eclipse
# Edit at https://www.gitignore.io/?templates=git,java,maven,windows,eclipse
### Eclipse ###
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
...
...
이파일 내용을 .gitignore
파일로 저장
config
git config –global http.sslVerify false