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 를 통해 이미 remotecommit 을 변경할 수 있음으로 신중히 사용해야한다.

bisect

commit –amend

마지막 commit 에 변경된 파일추가 및 commit 수정하기

해당 명령또한 마찬가지로 force push 를 통해 이미 remotecommit 을 변경할 수 있음으로 신중히 사용해야한다.

기존 커밋에 수정된 파일을 밀어넣고 메세지를 수정할 수 있다.

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 repositorysub-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

image26

각 디렉토리에는 별도의 .git 파일이 존재하고 commit 버전을 기준으로 연결시키기 때문에 별도의 pull 처리를 해줘야 버전을 따라갈 수 있다.
또한 root repository 에서 어떤 commit 버전을 사용할지도 결정해줘야 한다.

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 만들어야 할 때 아래 사이트 추천

https://www.gitignore.io/ image26

위와같이 현재 사용중인 시스템 정보를 삽입하면 아래와 같은 설정이 자동으로 생성된다.

# 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 파일로 저장

카테고리:

업데이트: