자주 쓰는 Git 명령어 정리
Git과 Github(또는 Gitlab)의 차이
Git(깃) : 프로젝트의 버전관리를 하기 위해 사용하는 프로그램
Github(깃허브), Gitlab(깃랩) 등 : 깃 기반의 저장소 서비스(약간 클라우드같은 개념?)
it 쌩초보였을 시절엔 깃이랑 깃허브가 같은건줄 알았다. 그 후에는 깃허브는 어떤 사이트구나, 그럼 깃은 정확히 뭐지? 했었고...그래서 확실히 정리하고 넘어가고자 한다.
깃은 중간중간 코드를 저장하고, 이전 코드로 돌아가고 싶으면 돌아갈 수 있도록(또는 꺼내 쓸 수 있도록) 도와주는 버전관리 프로그램이다. 깃 덕분에 요즘엔 ui를 구현하다가 마음에 안들면 일단 현재 버전을 저장해놓고(이를 커밋한다고 한다.) 이전 버전으로 돌아가서 다시 수정하곤 한다. 깃을 알기 전과 안 후의 생활이 확 바뀐걸 보면 진작 깃을 사용할걸하는 후회가 든다 ㅎㅎ (하지만 요즘도 깃 에러가 나면 너무 어렵다...)
깃 명령어 모음
git init
깃으로 관리할 수 있는 상태로 만든다. (주로 코딩에서 init은 초기화할 때 쓰는데, 여기서도 그런 느낌인 듯 하다. 처음에 입력해주면 되는듯) / .git이라는 디렉토리를 생성한다.
git config user.name "이름"
//예를 들면
git config user.name "eeeun"
깃 사용자의 이름을 설정한다. (config=설정이라는 뜻)
git config user.email "이메일주소"
//예를 들면
git config user.email "eeeun123@gmail.com"
(해당 이메일은 즉석에서 쓴, 존재하지 않는 이메일입니다.)
깃 사용자의 이메일을 설정한다.
커밋한다. commit을 만들다.
특정 버전을 저장하는 것 (이 특정버전을 '커밋'이라고 부른다.)
git add {files}
//예를 들면
git add 파일명
특정 파일을 staging area에 올린다.
(staging area란? 어떤 파일이 저장소에 커밋되기 전에 거치는 중간 단계로, 사용자가 보다 유연하게 커밋할 수 있도록 해주는 공간이다. staging area에 올려놓고 일부 파일만 커밋할 수도 있는 상황처럼)
git add .
모든 파일을 staging area에 올린다.
git commit -m "커밋메시지"
//예를 들면
git commit -m "first commit"
커밋하고 커밋 메시지를 남긴다. 이 명령어를 통해 커밋이 생성되고 staging area에 저장된다.
(커밋을 보고 작업할 팀원을 위해 무엇이 바뀌었는지 되도록 친절하게 커밋메시지를 작성해주는 것이 좋다.)
git log
이때까지 한 커밋의 기록을 시간 순서대로 볼 수 있다.
git diff {commit_id} {commit_id}
//예를 들면
git diff 34d5 5156
두 커밋 사이의 차이점을 볼 수 있다. 초록색으로 쓰인 부분이 바뀐 부분이다. 커밋 아이디를 칠 때는 앞 네자리만 쳐도 된다.
HEAD란?
현재 내가 위치해있는 커밋을 가리키는 식별자. git log에서 볼 수 있다. 커밋 옆에 HEAD -> master 이런 꼴로 나온다. (master가 아닌 다른 브랜치가 있을 수 도 있다.)
git reset --{option} {commit_id}
//예를 들면
git reset --hard 36d3
git reset --mixed 36d3
git reset --soft 36d3
헤드를 해당 커밋으로 바꾼다. 옵션은 총 3개(hard, mixed, soft)이고 옵션을 주지 않으면 기본값인 mixed로 실행된다. 한마디로 git reset은 언제든지 원하는 커밋으로 돌아갈 수 있는 기능이다.
(3개의 옵션을 잘 알고 사용해야 한다. hard를 잘못 사용하면 커밋을 날려버릴 수 있으므로 주의해야한다.)
git status
현재 깃의 상태를 구체적으로 볼 수 있다.
git reflog
이때까지 헤드가 가리키던 커밋 기록을 모두 보여준다. (reference log의 약자임), HEAD@{숫자}꼴로 나오는데 숫자가 작을수록 최근에 헤드가 가리켰던 커밋이라는 뜻이다.
git remote add origin {클론url}
전체적인 의미는 'url이 가리키는 외부 서버의 프로젝트를 원격 저장소로 지정하는데, 이름을 origin으로 할게!'이다. 매번 url을 치기는 번거로우니 origin으로 쓰려는 것. 사실 origin이 아닌 다른 이름을 써도 되지만, 중심이 되는 원본 프로젝트는 주로 origin으로 쓰는 것이 암묵적인 룰이다.
(여기서 git remote는 내 컴퓨터에서 외부 저장소에 관한 작업을 할 때 사용하는 명령어이다.)
git remote -v
등록된 원격 저장소들을 확인할 수 있다.
git push -u origin master
현재 내 프로젝트의 내용(커밋)을 origin이 가리키는 원격 저장소의 프로젝트로 업로드한다. 커밋을 저장소에 올리는 개념이기 때문에 반드시 커밋을 만든 후에 푸시해야 한다. (처음에는 사용자메일과 비밀번호를 입력하는 창이 뜬다.) 여기서 -u는 --set-upstream으로, 내 컴퓨터의 master 브랜치가 깃허브(혹은 깃랩 등) 서버의 master 브랜치를 바라보게 하라는 명령어다. -u를 붙여서 해주면 다음부터는 이를 기억해 git push, git pull만 해도 된다.
git push
바로 위 명령어(git push -u origin master)를 통해 이미 내 컴퓨터는 origin을 알고 있다. 그렇기 때문에 git push만 입력해주어도 커밋이 푸시된다.
git clone {클론url}
깃허브(혹은 깃랩 등) 서비스에 있는 프로젝트를 맨 처음에 내 컴퓨터로 가져올 때 쓰는 명령어다. url이 가리키는 원격 저장소의 프로젝트를 디렉토리 형식으로 가져온다.
(가져와서 작업을 하고...git config user.name과 email 명령어를 입력해서 누가 작업했는지 알 수 있도록 설정해주는 것이 좋다.)
git pull
깃랩 서비스에 있는 최신 커밋을 당겨온다. 작업하기 전에 반드시 해주어야 하는 명령어다!! 불필요한 충돌을 막기위해 작업하기 전에 꼭 pull을 한 번씩 해주는 습관을 들이자. (pull을 안해서 충돌나고 고생했던 기억이 있다...ㅜㅜ)
branch(브랜치)란?
나뭇가지, 분기된 흐름 = 특정 커밋을 가리키는 '포인터'라고 한다.
쉽게 말해서 브랜치란 독립적으로 작업을 진행하기 위한 개념이다. 각각의 브랜치는 다른 브랜치의 영향을 받지 않기 때문에, 여러 작업을 동시에 진행할 수 있다. (팀원이 여러 명일 때 깃을 사용한다면 브랜치를 활용해야 할 것이다.) 이렇게 각각 만들어진 브랜치는 다른 브랜치와 병합(merge)함으로써 새로운 하나의 브랜치로 합칠 수 있다.
git branch {branch_name}
//예를 들면
git branch ES //ES라는 이름의 브랜치를 생성
새로운 브런치를 생성한다.
git checkout {branch_name}
다른 브랜치로 헤드를 이동한다. 헤드가 직접적으로 해당 커밋을 가리킨다. (주로 과거의 커밋에서 새 브랜치를 만들고자 할 때 사용한다)
git push origin {branch_name}
특정 브랜치에 커밋을 푸시한다. (-u 옵션을 넣을지 말지는 본인 선택이다.)
Cherry-Pick이란?
다른 브랜치로부터 특정 커밋을 가져와서 내 브랜치에 넣는 기능이다. (안드로이드 스튜디오의 경우, terminal 옆 git에 있는 커밋을 우클릭하면 cherry-pick이 뜬다.)
git log --all --graph
헤드가 가리키는 브랜치뿐만 아니라, 모든 브랜치를 그래프 형식으로 보여준다.
git log --all -graph --oneline
커밋의 상세정보가 생략되어서 좀 더 깔끔한 로그를 볼 수 있다.
git merge {branch_name}
현재 헤드가 브랜치를 통해 가리키고 있는 커밋과 merge 뒤에 쓴 브랜치가 가리키고 있는 커밋을 병합한다.
git merge {프로젝트이름}/{branch_name}
특정 프로젝트를 특정 브랜치가 가리키고 있는 커밋과 merge한다.
Fast-forward merge란?
새 커밋이 만들어지지 않고 기존 커밋에 합쳐지는(병합되는) merge이다.
merge에는 merge당하는 브랜치가 동일 커밋 로그 직선 상에 있던 기준 브랜치의 위치로 쭉 당겨지기만 하는 Fast-forward merge와, 특정 시점에서 분기되어 서로 다른 커밋 로그 직선 상에 있어서 아예 새로운 merge 커밋을 생성하는 merge로 나눌 수 있다.
!! merge를 했는데 comflict가 뜨면서 >>>>>HEAD 이런 코드가 추가되고 파일에 빨간오류가 뜬다ㅠㅠ : 두 프로젝트의 같은 파일에 서로 다른 코드가 쓰여져서 그렇다. 깃 입장에서는 둘 중 어느 코드를 써야 할 지 모르는 것. 그럴 땐 내가 원하는대로 코드를 수정하고 (>>>>HEAD는 현재 헤드가 가리키는 파일의 코드라는 뜻이다. 이런건 다 없애주고 내가 원하는 코드로 정리를 한 뒤) git add . 하고 커밋해주면 된다.
fork(포크)란?
프로젝트를 카피해서 내용은 완전 똑같은 별개의 프로젝트를 생성하는 것이다. (한번에 완벽한 커밋을 하긴 불가능한데, 원본 프로젝트에서 다른 사람이 작업하고 푸시하면 곤란하기 때문에 포크한다.)
create merge request
포크해서 복제된 프로젝트에서 작업한 뒤, 원본 프로젝트에 '내가 새 커밋을 만들었어 반영해줘!'라고 원본 프로젝트 주인에게 요청하는 것이다. 명령어라기보다는 깃허브(혹은 깃랩 등) 서비스에 버튼으로 존재할 것이다.
git push --force
푸시를 강제한다. 실무에서는 절대! 쓰지 않는 옵션이다.
merge request의 종류(?) 3가지
: merge commit / merge commit with semi-linear history / fast-forward merge
merge commit : 커밋 히스토리의 모양에 상관없이 항상 merge한다. 늘 새로운 커밋이 생성되며 merge된다. (커밋이 빠짐없이 전부 다 있어서 정확한 히스토리가 생성된다. 하지만 모든 정보가 있기 때문에 히스토리가 지저분하고 한 눈에 보기 어려울 수 있다.)
merge commit with semi-linear history : merge request를 보냈을 때, fast-forward merge가 가능할때만 merge한다. 하지만 늘 새로운 커밋이 생성되며 merge된다.(merge commit타입보다 깔끔한 커밋 히스토리가 가능하다.) merge commit with semi-linear에서 fast-forward가 안돼서 merge가 안 될 때는 rebase를 한다.
git remote -v
지금 작업중인 프로젝트가 인식하고 있는 깃허브(또는 깃랩 등) 서버 프로젝트를 다 한눈에 볼 수 있다.
Detached HEAD
브랜치를 통해 커밋을 간접적으로 가리키고 있는 것이 아니라 직접 커밋을 가리키고 있는 상태의 HEAD를 나타내는 용어
추가 : 리베이스(rebase) 작업 도중 충돌이 발생했을 때 과정
- 내용수정
- git add .
- git rebase --continue
git stash
현재의 작업 내용을 깃에서 관리하는 별도의 영역에 저장하는 작업이다.
git stash pop
stash로 저장해뒀던 작업을 꺼내서 그대로 현재의 working directory에 실행해달라는 명령어다.