Search
Duplicate
🚆

Git 사용방법

Created
2/18/2021, 3:02:00 PM
Tags
Empty

Git의 기본 매커니즘

그림이 git의 전체 과정을 전부 설명해준다.
git은 svn과 달리 local repo와 remote repo가 구분되어 있어서 코드의 관리가 매우 편리한 분산 버전 관리 시스템이다.
git commit으로 저장해놓은 데이터는 로컬에 언제나 완벽히 보존된다! 내가 겪었던 버그는 ipython의 자동저장기능 때문에, git checkout으로 이동 중 과거에 켜둔 웹이 최신버전에 자동저장되면서 마치 데이터가 사라진것 처럼 보이는 현상이었다.
git에서 HEAD의 의미: 현재 내가 보는 코드의 위치

Git 환경 설정하기

git config --global user.email "이메일주소"
git config --global user.name "이름"
git config --global color.ui true : git 출력을 컬러로하기
git config --global core.editor "vim" : git 에서 사용하는 기본 editor를 vim으로 설정하기
git config format.pretty oneline : log에서 확정본을 한줄로 짧게 표시 # 별로일 수도 있음. 그러면 full 로 되돌림
Github의 계정을 public key를 이용, ssh 환경을 세팅해서, 로그인 과정을 생략하기이렇게하면, putty로 git remote repo에 접속할 때, id 비번 입력없이 바로바로 가능하다.- https://developer.github.com/enterprise/2.17/v3/guides/managing-deploy-keys/#deploy-keyshttps://help.github.com/en/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent#generating-a-new-ssh-key
1) ssh key 생성ssh-keygen -t rsa -b 4096
(-C "id@mail.com" 는 comment추가 옵션이다.)(경로를 입력할 때, 생성될 키의 이름도 바꿀 수 있다.)
(Enter passphrase 입력은 그냥 enter치면 없이 넘어간다.)2) ssh private key를 내 컴퓨터의 ssh-agent에 등록하기(최초 설정시에만 필요)eval $(ssh-agent -s) 을 입력해서 agent가 실행 중인지 확인한다.ssh-add ~/.ssh/id_rsa 을 입력해서 ssh를 agent에 등록한다.(ssh-add -l -E md5 을 입력해서 제대로 등록되었는지 확인가능)
3) ssh public key를 github에 등록하기cat ~/.ssh/id_rsa.pub 으로 나온 결과를 통째로 복사한다음github 사이트의 setting - SSH and GPG keys(혹은 deploy key)에 들어가서 복사한 key를 넣으면된다.(title은 적당히 해당 컴퓨터를 가리키는 말을 적으면 됨)
입력하고 나온 Fingerprint가 ssh-add -l -E md5 의 결과와 동일해야함4) 접속하기(최초 설정시에만 필요)
ssh -T git@github.com 을 입력하고 yes를 입력해서 바로 아래의 메시지가 출력되면 정상 접속된 것이다. (주의: git@~~.com 에서 git은 고정이다. 유저 id가 아님)
1.
Hi username! You've successfully authenticated, but GitHub does not provide shell access.
4-1) Permission denied (publickey) 에러위의 메시지가 나오지 않고, Permission denied (publickey)에러가 뜰 경우 다음 링크를 확인.https://help.github.com/enterprise/2.10/user/articles/error-permission-denied-publickey/
5) ID / Password 없이 git 사용하기기존의 remote url이 https를 통하도록 지정이 되어 있으면, 무조건 항상 ID와 비번을 물어본다. 따라서 방금 우리가 만든 ssh를 이용하도록 remote url을 변경해줘야한다.
git remote set-url origin ssh://git@github.com/PATH/TO/Repo.git
5-1) ssh-agent 자동 실행 --> bashrc에 등록하기(최초 설정시에만 필요)bash script에 다음을 추가하여, 자동으로 ssh_key를 이용하도록 수정한다.
eval $(ssh-agent -s)ssh-add ~/.ssh/id_rsassh -T git@github.com
그런데 위의 메시지를 봤는데도, 계속해서 username과 password를 물어본다면 다음을 실행해야한다.(ssh-agent가 실행이 안되어있는 경우임)https://help.github.com/enterprise/2.10/user/articles/working-with-ssh-key-passphrases/
### 여러가지 에러 해결 ###
# ssh-add 를 하여도 passphrase를 계속 물어보면?ssh-keygen -p -P "old_passphrase" -N "" -f ~/.ssh/id_rsa을해서 passphrase를 제거한다.
# remote: Invalid username or password. 에러 해결git remove -vgit remote set-url origin ssh://git@github.com/PATH/TO/Repo.git
https://stackoverflow.com/questions/29297154/github-invalid-username-or-passwordKey is already in usegithub에서는 하나의 key를 오직 하나의 repository에만 등록할 수 있다. 따라서 기존의 repo에서 해당 키를 삭제하거나, 아니면 새로운 키를 생성해서 사용해야 한다.

Github branch 삭제에 대해

1.
브랜치를 삭제하였을 때, 언제든지 복구 가능한 경우는 오직 PR merged가 완료 되었을 때, 해당 PR issue에 들어가서만 복구가 가능하다.
2.
만약 unmerged branch를 삭제해버리면, 코드 history를 보는 기능 등이 망가지므로 주의해야한다.
3.
결국 가장 좋은 방법은 모든 branch를 merge 시킨 후 delete하는 것이다. 그래서 가능하면 unmerged branch를 만들지 않는게 좋다.

git credential 사용하기

보안에 매우 취약한 방법으로, 완전한 개인용 컴퓨터에서만 사용해야한다. 동작 원리는 한 번 로그인한 git의 비밀번호를 plain text로 저장하는 것이다. 이 점을 유의하고 사용해야한다.
git config --global credential.helper store
다시 해제하고 싶으면 아래를 입력한다.
git config --global --unset credential.helper

git credential ID/비번 업데이트하기

git config --global --unset credential.helper git config --global credential.helper store
이렇게 하면 reset되어서 다시 입력하면 된다.

## 주의사항 ##

위의 명령을 실행하면 ~/.git-credentials라는 파일이 생성되는데 이 파일에는 사용자의 ID와 Password가 플레인 텍스트 형태로 그냥 기록된다. 따라서 완전히 무방비로 보안이 노출되기 때문에 가능하면 이 기능은 사용해선 안된다. SSH public key를 이용하는것이 가장 좋은 해결책으로 보인다.
Git stash: commit 하지 않은 현재 작업내용을 임시로 저장하고, 마지막 commit한 상태를 불러오기git stash: 현재 modified 된 파일을 임시로 저장하고, 마지막 commit상태를 불러옴
git stash -u : modified + untracked까지 백업
git stash pop: 임시로 저장해둔 변경내용을 불러옴.          git stash pop == git stash apply && git stash drop.git stash list : 임시 저장목록 가져오기git stash apply [stash@{0}] : 임시 저장목록 불러와서 다시 적용하기git stash drop [stash@{0}] : 저장해둔 내용 삭제git stash show -p stash@{0} | git apply -R : 실수로 충돌 등이 일어난 경우, stash apply한 것을 되돌릴 수 있다.https://www.git-tower.com/learn/git/faq/save-changes-with-git-stashhttps://git-scm.com/book/ko/v1/Git-%EB%8F%84%EA%B5%AC-Stashing
Git 의 핵심 명령어git clone : 최초로 원격 서버에서 최신 버전의 git 서버의 파일들을 컴퓨터로 받아옴.
git clone git_url -b branch_name : 해당 git repo의 특정 branch를 가져온다. ex) git clone https://github.com/imcomking/Practical_Deep_Learning_Tutorial.git ex) git clone https://github.com/imcomking/Practical_Deep_Learning_Tutorial.git DirName
git pull : 서버에서 최신 버전의 workspace 가져오기 (workspace 안에서 실행. push안한 사항이 있을 경우 충돌이 발생함. fetch + merge 을 합친 명령어)ex) git pull origin master : 해당 branch의 원격 서버에 저장된 최신 내용을 가져온다
git checkout . : local repo에서 작업하고, commit 하지 않은 file을 모두 마지막 pull 시점으로 되돌린다.(정확히는 Modified file들의 변경사항만 되돌리고, Untracked file들은 가만히 놔둔다.)git checkout HEAD [파일명] : 해당 파일의 변경사항을 HEAD에 있는 버전으로 되돌린다.
git checkout branch이름 : 해당 branch로 옮겨간다. 이를 실행하기 위해서는 일단 현재 시점에서 modified파일과 untracked파일이 없어야만 가능하다.
git add . : 서버로 새로 추가한 모든 파일의 목록을 전송한다. (git commit 혹은 push 하기 전에 반드시 add 먼저해야함.) (git add -i 혹은 -p 를 하면 대화식으로 추가가 가능) (git add * or -A 랑 다르네 뭔가)
(git add -u : 기존에 tracking하던 파일들만 add하기. 즉 modified file들만 add)(git add -i : 를 이용하면 편리하게 원하는 파일들만 골라서 add할 수 있다. 13 14 15 a 이런식으로)
git rm 파일명 : commit 된 파일이나 폴더를 삭제한다.(로컬에 있는 것까지 삭제해버리는듯.) reset만하면 staging만 안하는데, rm은 여기서 로컬 삭제까지 시켜버림.
git commit : editor가 켜지면서 commit message를 작성하게 된다.
git commit -m "메시지" : 현재 작업 상태의 스냅샷(백업)를 메시지와 함게 local repository에 저장ex) git commit -m "something is changed" (workspace 안에서 실행. -a를 붙이면 add도 한번에 같이 처리 가능)
git push origin master : 서버로 commit 한 내용을 보냄 (git clone으로 workspace를 먼저 다운받은 뒤, 그 안에서 실행) ( -u는 최초의 branch를 push할 때 1회 해주어야 한다는 것 같음.)git push가 하는 일은 local에 있는 branch를 remote에 있는 branch로 보내는 것이다.
# Git 을 local에서부터 시작해서 remote repo에 push 하기 : 주의 사항. remote repo에 파일이 0개인 상태여야만 깔끔하게 연결이 가능하다. (README, License, .gitignore 파일 등도 있으면 안됨.)rm -rf .git : git init 취소하기. 즉 내가 작업하던 폴더의 기존 git 저장소 삭제하기(내 소스코드는 그대로지만, commit/branch 등의 내역들은 다 삭제된다.)git init : 내가 작업하던 폴더를 git의 workspace로 만들기
git remote add origin 원격서버주소
git : git clone이 아닌, git init에서부터 시작 한 경우, 이 명령어를 통해 서버와 local repo를 연결해야한다. 당연히 이걸 하려면, 서버에서 먼저 repo를 생성한 다음 해야한다. ( 여기서 origin은 내가 add할 remote repo를 가리키는 별칭이다. 만약 여러개의 remote repo를 사용할 경우 origin2, origin3 등의 이름을 지어줄 수 있다.)
git add .git commit -m "메시지"
git branch --set-upstream-to=origin/master : git pull만 입력했을 때 default로 가져올 remote를 설정한다.
git push -u origin master로도 동일한 일을 할 수 있음.
git pull
git push origin master

작업 내용 추적 관리

# Unstage 하기- git reset -- <파일명> : 아직 commit은 안한 상태에서, add 한 파일 취소하기. 이 명령어는 git add와 완벽히 정반대의 행동을 한다. 즉 unadd라고 볼수 있고, 이번에 commit할 대상에서 제외하기 위함이다.
https://stackoverflow.com/questions/348170/how-to-undo-git-add-before-commithttp://stackoverflow.com/questions/1505948/how-do-i-remove-a-single-file-from-the-staging-area-of-git-but-not-remove-it-fro- git rm --cached [path] : 이미 commit한 특정 파일을 git repo의 index에서 제외시키기. 즉 이미 커밋된 특정 파일을 repo에서 unstaging(=untracked)한다. (git index에서만 빠져있으므로, 아직 내 local dir에는 남아있다.)https://stackoverflow.com/questions/6919121/why-are-there-two-ways-to-unstage-a-file-in-git/6919749
git rm --cached -r [dir path]
: 디렉토리에 대해서는 -r을 붙인다.

Untracked Files 한번에 .gitignore에 추가하기

Untracked file들을 git stash -u로 처리할 수도 있지만, 용량이 매우 큰 경우 stash하기가 쉽지 않다. 그래서 .gitignore에 아래의 명령어를 사용해서 처리할 수 있다. 이렇게 ignore된 untracked들은 git하고 무관하게 존재하므로, 다른 branch에 checkout해도 그 경로에 똑같이 남아있다.
git status --porcelain | grep '^??' | cut -c4- >> .gitignore
C++
# 이미 tracked 중인 파일에 대해 변경사항 무시하기
단점 1 : assume-unchanged 혹은 skip-worktree로 지정한 파일에 변화가 생겼을 때, git status에는 전혀 보여지지 않지만, git checkout branch 을 실행시 다음과 같은 에러가 뜨면서 먹히질 않게된다.
(error: Your local changes to the following files would be overwritten by checkout: Please, commit your changes or stash them before you can switch branches. Aborting)
그런데 이 문제는 설계적으로 의도된 것이라고 한다. 어쩔 수 없이 맞딱들일 수 밖에 없다. https://stackoverflow.com/questions/35690736/handling-changes-to-files-with-skip-worktree-from-another-branch
현실적인 방법은 alias를 등록해서 편하게 사용하는 것이다.
단점 2 : 이 옵션들은 철저히 local을 위한 것으로 push하여 다른 사용자에게 propagation할수는 없다.
Change Tracking 중지하기: 바뀌지 말아야할 파일
git update-index --assume-unchanged [path] : 내가 해당 파일을 local에서 수정한 모든 내용을 무시함. 즉 개발자가 앞으로 변경하지 않을 것이라고 생각되는 대규모의 sdk와 같은 파일에 대해 추적을 중단하여 git stat의 속도를 빠르게 하기 위함.
독립 작업 파일/폴더 설정하기: 편히 바꾸어야할 파일
git update-index --skip-worktree [path] : local 전용 개발을 위한 독립 파일/폴더를 설정함. 즉 개발자가 오직 local에서만 사용할 목적의 수정이 일어나는 경우 설정해줌.
git update-index --no-skip-worktree [path] : undoing
# .gitignore: 계속해서 untracking할 파일을 지정한다.(이미 tracking중인 파일은 영향받지 않는다.)
위의 내용으로 .gitignore파일을 만들고 시작하면 좋음. github에서도 선택을 하면 기본 제공한다고하는듯
commit 해둔 버전으로 돌아가기 : 이건 정말 흔하게 많이 쓰이는 기능이다.
git checkout HEAD~5 : 최신 버전에서 5번 뒤로 가기
git checkout 9d51a7 : 9d51a7이름의 commit으로 돌아가기
git checkout master : 다시 최신버전으로 돌아오기
(여기에 -f 옵션을 추가하면, 수정하던 것을 다 버리고 해당 버전으로 옮겨감)
http://opendive.blogspot.kr/2015/06/git.html- 특정 파일만 commit 해둔 버전으로 돌아가기 :git checkout <commit> 파일명http://ohgyun.com/443
Remote branch에 checkout하기
git fetch
git checkout <remote브랜치명>
과거에 삭제하고 commit한 file 되살리기
git rev-list -n 1 HEAD -- file_path :으로 해당 파일이 삭제된 commit 찾기
git checkout [삭제된 commit]^ -- file_path : [commit hash]^ 을 하면, 그 이전 commit이 선택된다.
Auto-merge된 파일 되돌리기git checkout HEAD~1 -- 해당파일이때 --는 생략해도 되는데, 하면 더 좋은 이유는 똑같은 이름을 가진 branch와 파일이 서로 헷갈리는 것을 막기 위함이다. 즉 -- 를 붙이면 오직 파일중에서만 해당이름을 인식함.https://stackoverflow.com/questions/41101998/git-checkout-vs-git-checkout
실수로 pull 한 작업 취소하기git reset --hard설명) 일단 pull은 아래와 동치이다.git pull origin master = git fetch origin + git merge origin/master항상 문제인데, 이 merge는 git reset --hard하면 취소됨. 즉 git fetch origin만 한 상태로 돌아가짐.
이 작업 중에서 merge가
실수로 Commit 한 작업 취소하기최근 HEAD에서 한단계로 돌아가, commit 한 명령을 취소한다.최근 HEAD에서 한단계로 돌아가, commit 한 명령과 add 명령을 취소한다.(코드의 변경사항은 modified인 상태로 남아 있다.)최근 HEAD에서 한단계로 돌아가, commit 한 명령과 add 명령과 코드의 변경사항을 취소한다. (코드의 변경사항인 modified까지 날아가버리므로, 나의 작업 내용이 삭제되어버린다.)
git reset --soft HEAD~1 :
git reset --mixed HEAD~1 :
git reset --hard HEAD~1 :
실수로 Commit 한 작업에서 1개 파일만 취소하기git reset --soft HEAD~1 : commit 한 내용을 취소한다.git reset HEAD <파일이름> : add한 내용을 취소한다.git commit -c ORIG_HEAD : message를 수정하면서 다시 원래대로 commit한다.
이미 push 한 작업에 대한 처리인듯git revert --hard commit이름 : 그동안의 커밋을 지우지는 않고, 예전으로 되돌아간다.http://ecogeo.tistory.com/276
Commit의 작업 내용 확인하기 git show [Commit]

Fast-forward로 PR merge한 경우에 commit 취소하기

이 경우, git reset --hard HEAD~1 이렇게만 해버려도, 한번에 PR로 묶인 commit들을 한번에 리셋시켜버린다. 그래서 내가 원하는 지점의 commit hash를 입력해서 수동으로 처리해야한다
ex) git reset --hard cc34909
git show [Commit] --name-status : 변경된 파일 목록만 확인
두 Commit 간의 차이점 비교하기
git diff HEAD : 현재의 작업으로 변경한(commit하지 않은)내용을 확인git diff <commit> : HEAD와 commit과의 차이 비교git diff HEAD~3 : HEAD~3번째와 HEAD와의 차이 비교git diff <commit1> <commit2> : 두 commit간의 차이 비교 (이때 나중에 만든 commit이 뒤쪽에 와야 +, - 기호가 제대로 표기됨..)--color-words : 이 옵션을 주면 간결하게 색으로 구분할 수 있음
git diff --name-status HEAD : 변경된 파일의 이름과 상태만 출력git diff --staged : add는한 상태이나, 아직 commit되지 않은 변경내용을 확인
local에 commit은 했는데 아직 remote에 push는 안한 내용 확인하기
git log origin/master..HEADgit diff origin/master..HEAD
Dropbox 때문에 git diff에서 이상한 warning: ~~conflicted copy~~이 발생할 때
.git/refs/heads 에 들어가서 conflict 난 파일을 삭제한다.
.git/refs/remotes/origin 에 들어가서 conflict 난 파일을 삭제한다.
git push만 입력했을 때의 기본 행동 설정하기
git config --global push.default simple
(현재의 branch만 push한다. simple 대신 matching을 할 경우 모든 이름이 똑같은 branch를 한 번에 전부 push한다.)

Git bisect

어떤 commit에서 버그가 발생했는지 찾는 도구

Git rebase

git rebase는 과거의 했던 commit의 내용을 수정하고 싶을 때 사용하는 커맨드이다. 보통 git rebase -i HEAD~[N]의 형태로, 과거 N시점부터 현재까지의 commit들을 쭉 살펴보면서 어떻게 수정할지를 정한다.
git rebase -i HEAD~[N] 을 입력하면, editor가 나오는데 여기서 pick이라고 된 것은 해당 commit을 그대로 놔둔다는 의미이고, edit을 입력하면 해당 commit으로 checkout한 뒤, 내용을 수정하겠다는 의미이다. (이때 edit하고난 다음, git add 및 git commit --amend를 입력해서 커밋을 저장한다.) 그리고 reword는 commit message만 변경하겠다는 것이고, squash는 해당 commit을 이전 commit과 합쳐서 하나로 만들겠다는 것이다.
한 단계의 commit을 수정이 완료가 되면, git rebase --continue를 입력해서 다음 commit으로 넘어갈 수 있고 또는 git rebase --abort를 해서 rebase작업을 중단할 수도 있다.
git show --name-status HEAD 을 입력하면 현재 수정중인 commit에서 어떠한 file들을 변경했는지 그 내역을 알 수 있다.
git rebase를 하다보면, "The previous cherry-pick is now empty, possibly due to conflict resolution." 이런 메시지가 나올 수 있는데, 이는 내가 다른 commit과 내가 edit한 commit의 내용이 겹쳐서 merge가 되어버리면 아무런 파일에 변경 내용이 없는 commit이 발생 할 수 있다. 이런 경우 git commit --allow-empty 을 입력해서, 그냥 아무 내용 없는 빈 commit을 저장하고 git rebase --continue를 하면 된다.
git rebase를 하다보면, 내가 다시 작성한 과거의 commit과 다른 그 이후의 commit에서 변경사항이 서로 충돌이 날 수 있다. 이런 경우 git status를 입력해보면 어떤 파일에서 수정이 일어났는지 알 수 있고, conflict 를 해결하고 git add / commit을 하면 된다.
여러개의 commit을 1개의 commit으로 합치기
git rebase -i HEAD~[N]
합칠 커밋들의 맨 앞에 있는 pick을 지우고 squash 또는 s를 적고 editor를 저장한다.
그런데 그리고나서 push를 하려고하면 remote origin에 있는 내용과 맞지 않아서 push할 수 없다. 이러한 경우 git push origin master -f 을 입력해서 강제로 remote의 내용을 덮어씌워야한다.
실수로 용량이 매우 큰 파일을 commit해버렸다가, 다시 되돌리는 방법.
가장 중요한 것은 앞으로의 commit에서 해당 파일을 삭제한다고 되는게 아니라, commit history에서 삭제해야한다는 점이다. 만약 해당 파일이 가장 최근의 commit에서 포함되었다면, 매우 간단히 아래의 두 커맨드로 해결 가능하다.
git rm --cached <filename>
git commit --amend -C HEAD (만약 여기서 --amend를 안하면, 새로운 commit이 생긴다.)
그러나 만약 과거의 commit에 포함이 되어버렸다면 git log와 git show <hash> --name-status 등의 명령어를 통해 어떤 commit에서 포함된지 알아낸 다음, git rebase -i <hash>를 하여 해당 commit에 가서 아래의 두 커맨드를 실행한다.
git rm --cached <filename>
git commit --amend -C HEAD
그다음 git rebase --continue를 하면 된다.
Resolving conflicts in git base git rebase를 과거의 commit에 대해서 하게되면, 현재 시점(HEAD)와 비교하여 소스코드를 재 수정할 수 있게 된다. 만약 HEAD와 과거 commit에서 동일한 파일을 수정한 경우 conflict가 날 수 있고 이를 resolve해주어야한다.
git rebase --continue나 --skip이 안될 때 이유는 잘 모르겠지만, 위의 명령어를 입력했을 때 Rebasing(N/N)에서 무한루프가 걸려서 더이상 넘어가지지 않으면, rm -rf .git/rebase-merge 를 입력한다.

Git branch

#Git 의 branch 다루기 : branch란 내가 원래 작업하던 파일을 안전하게 격리보존한 상태에서(master), 새로운 작업을 다른 저장소에서 해줄 수 있게 하는 기능이다. 마치 backup본 저장시켜 놓고 새로 작업하는 것과 같음. 말그대로 가지치기
git checkout -b 브랜치이름 : 새로운 branch를 생성git branch -d 브랜치이름 : 해당 branch를 삭제git branch -m Old이름 New이름 : branch 이름 변경
git branch : 현재 있는 모든 branch 확인git push origin 브랜치이름 : 해당 branch를 remote 서버에 저장한다.
git checkout master : 현재 workspace를 master branch에 저장해둔 상태로 되돌린다.git checkout 브랜치이름 : 현재 workspace를 해당 branch로 이동한다. ( master , devel , debug 등등 )git checkout 브랜치이름 --파일이름 : 해당 파일 하나를 해당 branch의 최신 버전으로 되돌린다. (SVN의 revert와 완전히 동일. 즉, 변경사항을 전부 날리고 원래 commit했던 파일로 복구하기)

remote branch에 force push하기

remote branch의 commit을 지워버리고, 현재 branch의 commit으로 덮어 씌워버릴 때, 강제로 push를 할 수 있다. 즉 원래는 pull을 한다음 push를 해야하는데, 이를 무시하고 그냥 push를 하는 것이다.
ex) remote의 commit을 간결하게 하려면, local branch에서 rebase를 한다음, 그것을 강제로 remote에 덮어씌워야한다. 그런데 이 경우 remote에서는 해당 commit들이 복구되지 않을 수 있으므로 주의해야한다.
git push -f origin remote_branch
local branch를 이름이 다른 remote branch에 push하기(branch mapping)
아래와 같이 <local>:<remote>로 mapping을 알려주면서 push를 하면 된다.
git push origin local_branch:remote_branch
두 Branch 간의 차이점 비교하기git diff branch1 branch2git diff branch1:[파일경로] branch2:[파일경로]https://stackoverflow.com/questions/4099742/how-to-compare-files-from-two-different-branches
두 Branch 합치기: 이게 branch를 다루는 데서 가장 어려운 부분일 듯.git diff 브랜치1 브랜치2 : 두 branch사이의 차이점 비교
git rebase 목표브랜치이름 : 두개의 branch를 하나의 branch로 합치기 위해서 없애고, 현재의 branch에다가 목표브랜치의 commit을 가져와서 적용시킨다. (그다음 git checkout 를해서 목표브랜치로 이동한다음, 아래의 merge 명령어 실행)
git merge 가져올브랜치이름 --no-commit : 현재 branch에다가 해당 branch를 가져와서 합치되, commit은 하지 않고 staging만 한다.   
반대로 말하면 git merge의 기본 동작은 다른 branch의 변경사항을 가져와서 auto-merge를 한 다음, conflict가 안나면 commit까지 해버리는 것이다.
다른 Branch에 있는 일부 변경사항(commit)을 가져오기git cherry-pick <commit>https://stackoverflow.com/questions/4315948/git-partial-merge-not-whole-branch
다른 Branch에 있는 새로운 파일을 복사해서 가져오기git checkout 다른브랜치 파일이름http://seorenn.blogspot.kr/2014/04/git.html
다른 Branch에 있는 파일 내용으로 덮어씌우기git checkout -p 다른브랜치 파일이름http://seorenn.blogspot.kr/2014/04/git.html
다른 commit에 있는 파일 내용을 가져오기git checkout HEAD~3 -- 파일이름
Branch 이름 변경하기: 이미 remote 에 branch를 push한 경우에 해당함. (push를 안한 경우 그냥 첫번 째 줄만 하면됨.)
git branch -m old_name new_name
git branch -a (local과 remote에 있는 모든 branch 이름확인)
git push origin --delete old_name (old branch 삭제)
git push origin new_name (new branch 올리기)
Local에 있는 branch 삭제하기git branch -d 브랜치이름git branch -D 브랜치이름 (merge 안된 내용이 있어도 강제 삭제)
# Git remote
Remote에 있는 branch에 checkout하기git fetch origingit checkout [브랜치이름]https://stackoverflow.com/questions/1783405/how-do-i-check-out-a-remote-git-branch
Remote에 있는 branch 삭제하기
git push origin --delete 이름* 단 Github에서는 master 브랜치를 삭제하려면, 웹사이트의 setting에 들어가서 default branch를 다른 걸로 변경한다음 삭제해야함.
Remote 다루기
git remote -v : 현재 remote 목록 확인git remote add orgin https://github.com/bi-lab/deeplearning_tutorial.git : remote 추가
git remote remove origin : remote 삭제
Remote에 권한이 없어서 403에러가 뜨는 경우(실제로 권한이 없을 수도 있다.)
git remote set-url origin https://YOURID@github.com/USERNAME/REPOSITORY.git
Remote Repository에 새로 업데이트된 정보가 있는 지 확인하기: https://stackoverflow.com/questions/2514270/how-to-check-for-changes-on-remote-origin-git-repository
git remote update : remote의 정보를 가져오기만한다.(합치진 않음, git fetch origin 과 거의 같은 것으로 보임?)
여러 개의 remote 다루기
git remote add new_origin url : remote 서버 추가
git remote remove new_origin : remote 서버 삭제
git branch -u new_origin/branch : 어떤 remote branch를 트랙할지
git push new_origin branch
git remote push all branch : 모든 remote repo에 push하기
# Git 의 기타 명령어
git status : 파일들의 현재 상태 및 변경 사항등을 확인할 수 있다. 가령 add가 안된 파일 등이 나온다.git log : commit log 살펴보기git log --all --graph : commit log 에서 branch 정보를 그림으로 확인. 아주 유용함.git tag 버전넘버 고유식별자(a1d2c3) : 버전 이름 달기git fetch : remote에 있는 최신 데이터를 내 로컬에 다운로드함. 그 이외 추가적인 작업은 전혀 안 함.(이걸해야 remote에만 존재하는 branch에 checkout을 할 수 있음.)git merge : 서버에서 가져온 최신 내용을 내 local repo와 합침
# Git status 속도가 매우 느려졌을 때 해결 방법
git gc
이걸 하고나니 속도가 몇십배 더 빨라졌다.
# Detached Head에 대한 이해HEAD: 내 현재 워크스페이스가 가리키는 commit을 의미함. Detached HEAD는 내 HEAD가 가장최신 지점을 가리키지 않는다는 의미임. 즉 몸통을 보고있다.
보통의 경우 branch를 checkout하면 항상 가장 마지막 commit 으로 이동되므로 HEAD가 항상 끝에 있다. 그런데 checkout을 branch가 아니라 특정 과거 commit 으로 돌아가는 경우 detached HEAD상태가 된다. Detached HEAD상태에서는 내가 새로 생성항 commit이 그 어떤 branch에도 속하지 못하고, 혼자서만 존재하게 된다. 즉 HEAD에만 새로운 commit을 붙일수가 있는 것인데 몸통에서 commit하면 갈데가 없는것.
checkout으로 commit을 이동하다가 branch에서 떨어져 나온 commit 발생 시 해결 법:우선 이런 상황에서는 다음과 같은 경고 메시지가 뜬다.head detached from <~~~>Warning: you are leaving 1 commit behind, not connected to any of your branches.
이런 현상이 발생하는 것은 checkout으로 branch가 아니라, 특정한 commit에서 작업하다가 새로운 commit을 생성하면, 그것이 특정한 branch에 속하지 않은 상태로 저장되기 때문이다. 반드시 모든 commit은 branch에 속해야하기 때문에 이를 해결하기 위해서는 우리가 원하는 branch로 checkout한 다음 아래와 같이 cherry-pick으로 낙동강 오리알이 된 commit들을 붙여야한다.
## 해결법 1: detached된 commit을 HEAD로 통합해서 가져오는 방법git reflog : commit을 포함해 내가 HEAD를 이동한 흔적을 확인할 수 있다. 이 명령어로 branch에 안 붙은 commit의 id를 확인한 다음
git checkout <붙일 branch이름>git cherry-pick <commit> <commit> <commit> ... : 이 명령어를 통해서 현재의 branch로 해당 commit을 가져온다.http://stackoverflow.com/questions/9984223/what-happens-to-git-commits-created-in-a-detached-head-state
## 해결법 2: HEAD를 날려버리고, 과거 commit을 HEAD로 만들고 싶을 때git checkout 과거commit : 이러면 detached HEAD상태가 됨git branch -b tmp_master : 임시로 카피를 떠둠git branch -D master: HEAD를 날림git branch -M tmp_master master: master로 이름을 변경함
그런데 이렇게 번잡하게 안하고, git reset --hard HEAD~1 으로도 할 수 있을 것 같은데 정확히는 모르겠다.

Untracked file 한방에 지우기

git clean -n : 앞으로 뭐를 지울건지 보여준다
.git clean -d  -f .  : 지운다.
“The following untracked working tree files would be overwritten by checkout”
문제 해결

유용한 git alias

말도 안되는 git alias 덕후의 예제...

commit 할 때마다 hash 값 남기기

comm = "! git commit && git describe --always > git_hash.txt"

Git 의 log 쉽고이쁘게 보기

vim ~/.gitconfig 에다가 다음의 설정을 입력한 후 저장한다.
[alias] lol = log --graph --decorate --pretty=oneline --abbrev-commit lola = log --graph --decorate --pretty=oneline --abbrev-commit --all lolan = log --graph --decorate --pretty=oneline --abbrev-commit --all --name-status [color] branch = auto diff = auto interactive = auto status = auto
Plain Text
또는 다음을 실행해도 된다.git config --global alias.lol "log --graph --decorate --pretty=oneline --abbrev-commit"git config --global alias.lola "log --graph --decorate --pretty=oneline --abbrev-commit --all"git config --global alias.lolan "log --graph --decorate --pretty=oneline --abbrev-commit --all --name-status"
사용법: git lol / git lola / git lolan
## skip-worktree등록하기
[alias]
hide   = update-index --skip-worktree
unhide = update-index --no-skip-worktree
hidden = "!git ls-files -v | grep ^[hsS] | cut -c 3-"
# git tag
git tag는 특정한 commit hash에 유니크한 이름을 짓는 것으로 이해할 수 있다. 보통 release version을 관리하기 위해 사용되고, 다음과 같은 명령어를 사용할 수 있다.
git tag -l : tag 리스트 보기
git tag tag이름: Lightweight tag 생성하기(상세 설명을 달지 않는다)
git tag -a tag이름 -m "코멘트" : Annotated tag 생성하기
git show tag이름 : tag관련 문서 보기
# git 협업 이슈 해결## OS가 다른 환경에서 공동 작업시 생기는 CRLF문제- Window는 line ending으로 \r\n (CRLF)를 사용하는 반면, Unix나 Mac OS에서는 \n (LF)만을 사용한다.
만약 Mac에서 작업한 코드를 윈도우에서 pull하게 되면 변경된 모든 파일의 line ending이 달라서 파일 전체에 대해 수정이 일어 났다고 인식해서 git diff를 하게되면 지옥이 펼쳐진다.
이러한 문제를 다음의 문서를 참조하면 거의 대부분 해결이 가능하다.
위 해결 방법의 결론을 요약하면 다음과 같이 2가지 선택지가 있다.1. 윈도우 사용자는git config --global core.autocrlf true
Unix나 Mac 사용자는git config --global core.autocrlf input
을 빠짐 없이 입력하면 아무런 문제가 생기지 않는다.(무조건 git repo에 LF만 올리는 방식)
2. 그러나 위 방법의 불편함을 없애려면, .gitattributes 파일을 repo에 추가시키면 알아서 각 contributor의 설정을 덮어 씌워서 해결된다.
그리고 다음 github에서 기본 공통 파일을 받을 수 있다.https://github.com/alexkaratarakis/gitattributes
그런데 위의 세팅을 개발 처음단계에서 부터 했으면 괜찮은데, 개발 중간에 추가하게 된 경우 모든 파일의 line ending을 초기화해주어야한다. 다음을 참조
다음은 line ending을 무시하고 diff 및 merge를 하는 방법이다,git diff master origin/master --ignore-space-at-eolgit merge origin/master -s recursive -Xignore-space-at-eol
## Conflict Resolve 하기(Resolve: HEAD, ===== 등을 제거하고 conflict난 코드를 1개로통합하는 작업을 의미함)
git pull : Automerge가 불가능한 파일들에서 conflict가 발생했다고 뜬다.git status : Unmerged path에 conflict가 발생한 파일을 확인한다.conflict가 일어난 파일을 에디터로 열어서 head <<< / >>> source 이런 부분을 다 지우고 제대로된 하나의 파일로 만들어준다. 이때 vim의 여러 단축기 (ex) 한줄 삭제 : dd)를 활용하면 좋다. 그리고나서 파일을 다 수정한다음,git add -Agit commit -m "conflict merged"git push origin master
## 3-way Conflict Resolve하기Sublime_merge 에서 resolve를 클릭하면 [Commit A/Conflict Merge상태/Commit B] 세가지 화면이 보여지는 3-way merge tool이 실행된다. 이를 사용해서 수동으로 merge하면 된다.
아직 push안된 commit의 message 수정하기git commit --amend
git commit --amend -m "새로 덮어 쓸 메시지"
gitignore 사용하기
.gitignore 파일을 이용해 특정한 확장자의 파일들이 add되는 것을 방지할 수 있다. 예를 들어 pyc같은 백업 파일 등이 이에 해당한다.
.swp.pyc
등을 작성해서 .gitignore파일을 workspace에 넣어놓으면 알아서 add대상에서는 제외된다.
Git config 설정하기git config -l : 전체 config 목록 확인git var -l : 전체 var 목록 확인
vim ~/.gitconfig
git config --global http.proxy ~~~git config --global --unset http.proxy
Git config를 각 디렉토리마다 설정하기git config --local user.email "이메일주소"git config --local user.name "이름"
# Git 아키텍쳐 관리
반드시 최소한의 project 단위로 repo를 생성해야한다. 그렇지 않으면 두개의 project에서 동시에 작업이 일어났는데, 그것이 하나의 repo에 모두 저장이 되면 context가 꼬여서 도저히 작업을 할 수 없게된다.
또한 git repo내부에 또다른 git 을 생성하면 submodule의 개념으로 다른 repo에서 해당 작업을 알아서 clone해서 가져온다. 그러나 일반적으로는 사용하지 않는 방식. 거대한 프로젝트에서 사용
# Subtree
git remote add [origin_name] [github_url]
git subtree add --prefix [위치할 경로] [origin_name] [remote_branch_name] --squash
git reset --hard HEAD~1  : 방금 실행한 subtree add 명령을 취소한다.
git subtree pull --prefix  [위치할 경로] [origin_name] [remote_branch_name] --squash
또는 git push -s subtree [origin_name] [remote_branch_name]
git subtree push --prefix [위치할 경로] [origin_name] [remote_branch_name]  : subtree project에 push하기
또는 git pull -s subtree [origin_name] [remote_branch_name]
에러해결
Working tree has modifications. Cannot add.
이 에러는 현재 시점에서 commit이 안된 수정사항이 있거나 뭔가 branch가 더럽혀진 상태일 때 발생한다. 따라서 변경사항을 전부 commit하거나, 아래와 같이 checkout을 해주어야한다.
git checkout <current branch>
subtree add 명령어 추가 설명
-squash: subproject의 git history를 1개의 commit으로 요약해서 가져온다. 보통 --squash를 해주는게 기본적이다.
-prefix: subproject가 위치할 경로를 지정할 수 있다. 이때 경로의 이름에 '-'가 들어가면 안된다. Python 모듈의 이름에는 '-'을 쓸 수 없기 때문이다.
subtree 삭제하기
git rm -r <subtree_directory>
rm -r <subtree_directory>
그냥 해당 directory를 삭제해버리면 된다.
명령어에 대한 상세 튜토리얼
subtree directory 변경하기
git mv old_dir new_dir
subtree 내에서의 코드 변경사항만 확인하기
git log -- subtree_dir
# Submodule
## Submodule 그냥 따라하기
(submodule add할 때, --force를 하지 않으면, repository에 간혹 submodule 내용이 올라가지 않아서, 다운받아지지 않는 경우가 있어서 매우 불편하다.)git status --ignore-submodules=dirty
git submodule add --force [submodule_url]
git submodule update --init --recursive
git add .
git commit -m "submodule added"git push origin master
## Submodule 추가하는 다양한 방법git submodule add --force [submodule_url] : remote repo를 "repo이름"을 기본 경로로하여 clone해서 submodule로 추가함
git submodule add --force [submodule_url] [submodule_path]: remote repo를 지정한 경로에 clone해서 submodule로 추가함
git submodule add --force -b [branch이름] [submodule_url [submodule_path]: remote repo의 특정 branch를 지정한 경로에 clone해서 submodule로 추가함
위의 submodule add 명령을 한다음에는, 반드시 다음 명령을 수행해야함
git submodule update --init --recursive
## Submodule들만 업데이트하기개별 submodule에 들어가서 git pull을 하거나, 혹은 다음을 실행
git submodule foreach git pull origin master
Plain Text
## clone하면서 submoudule까지 한 번에 받아오기
git clone --recurse-submodules [GIT_URL]
Plain Text
https://stackoverflow.com/questions/3796927/how-to-git-clone-including-submodules## git pull 하면서 한번에 submodule도 업데이트하기git pull --recurse-submodules
## Submodule 삭제하기: 안타깝게도, 현재 submodule은 수동으로 직접 삭제해줘야한다.1. vim .gitmodules-> 해당 submodule에 대한 내용삭제 후 저장(만약 한개의 submodule만 존재하면, 그냥 .gitmodules 파일을 삭제해도 됨)2. vim .git/config-> 해당 submodule에 대한 내용삭제 후 저장3. 수동 파일 삭제
git rm --cached [submodule_path]rm -rf .git/modules/[submodule_path]rm -rf [submodule_path]4. git commit
git add .git commit -m "submodule removed"
## Submodule 내용을 변경된 경우를 git status에서 표시하지 않는 방법Submodule 디렉토리에 들어간다음 git checkout . 을 해서 변경사항을 모두 없애주어도 된다.https://stackoverflow.com/questions/4873980/git-diff-says-subproject-is-dirty/39803366
만약 단순히 status에서 표시만하지 않으려면 .gitmodules에 ignore = dirty 을 추가하여 변경 사항을 무시할 수 있음.
https://stackoverflow.com/questions/3240881/git-can-i-suppress-listing-of-modified-content-dirty-submodule-entries-in-sta혹은 일괄로 처리하고 싶은 경우, submodule을 추가하기 전에 먼저 git status --ignore-submodules=dirty을 실행하면 된다.
## Submodule의 문제와 해결
local repo의 위치를 변경할 경우, submodule의 gitdir을 일일이 수정해줘야한다. 그렇지 않으면 git add 실행시 fatal: Not a git repository: 이런 에러가 계속해서 뜬다.
해결방법: vim submodule/.git 을 입력해서, 일일이 경로를 수정해준다.
ignore옵션에는 다음과 같은 것들이 있다.
all : 해당 submodule에 대한 모든 것을 무시한다.dirty: commit 되지 않은 모든 변화를 무시한다.
untracked: untracked file에 대해서만 무시한다.
none: 무시하지 않는다.
## Read권한 사용자가 Pull Request(PR 보내기)
아래의 링크에 잘 설명되어 있다. 핵심은 다음과 같다.
1. fork를 해서 read 권한만 갖고 있는 repo를 내 계정으로 밑으로 복사해온다.
2. PR을 보내고 싶은 원본 repo를 remote add 로 추가한다.
3. Local repo에서 commit을 생성하고, 새로운 branch에 push한다.4. fork된 github에 가면 "New pull request"을 클릭하여, 원본 repo에 PR을 요청한다.
# 기타 팁리베이스 머지하면 갈라졌던 브랜치를 옮겨서 한줄기로 만드는 일을 한다. 구체적으로는 다른브랜치에 적용된 커밋을 가져와서 적용하는게 리베이스 임
깃허브는 컨트리뷰션하기위해서는 포크해서 고대로 복사해온다음 코드 수정하고 그 해닿레포가 내꺼를 풀하게만드는거라 풀 리퀘스트를 요청하는개념 임
머지할때 --노-에프에프 옵션을 반드시 줘야 브랜치를 머지한기록이 남아서 되돌릴수가 있음

주요 참고 자료

TOP