Coder Social home page Coder Social logo

git-study's Introduction

yejineee

git-study's People

Contributors

lillie-yang avatar yejineee avatar

Watchers

 avatar  avatar

git-study's Issues

Detached HEAD란?

Attached HEAD

Detached HEAD가 있다면, Attached HEAD는 무엇일까?

HEAD -> branch -> specific commit 을 가리키는 상태를 Attached HEAD라고 한다.

Detached HEAD

Detached HEAD란 HEAD가 브랜치를 통해 commit을 가리키지 않고, 직접 커밋을 가리키는 것을 말한다.

HEAD가 다른 브랜치로 체크아웃했을 때, 이전 HEAD가 Detached HEAD였다고 하자.

이럴 경우, 해당 커밋의 revision number를 모르면 그 전으로 쉽게 돌아갈 수 없고, 그래프에도 표시되지 않는다.

아래 명령어를 사용하면 detached HEAD상태가 된다.

git checkout master^
git checkout HEAD~2
git checkout origin/master
git checkout <tag name>
git checkout <revision number>

detached HEAD의 상태로 만들기

HEAD가 바로 이전 커밋을 가리키게 하여, detached head 상태로 만들어보자.

git checkout HEAD~1

gloga로 확인해본 브랜치와 HEAD와 커밋의 관계이다.

스크린샷 2021-05-04 오전 11 12 30

HEAD가 직접 커밋을 가리키는 detached head상태가 된 것을 확인할 수 있다.

그리고 이 상태가 되면, git도 내가 어떤 상태인지 알려준다.

스크린샷 2021-05-04 오전 11 00 31

Attached HEAD 상태였던 커밋으로 돌아가면 될까?

다시 attached HEAD상태로 만들려면, HEAD가 attached HEAD였던 커밋으로 돌아가면 되지 않을까?

git reflog 로 내가 돌아가고 싶은 커밋을 확인하고, 이전 커밋으로 돌아가보자

git reflog는 이전 커밋 내역을 보여주는 명령어다.

스크린샷 2021-05-04 오전 11 14 03

3f679ed은 HEAD를 detached head로 만들었던 커밋이다. 바로 이전 커밋으로 돌아가면 attached HEAD가 될까?

HEAD를 master와 branch-a가 있는 8bf981f로 이동시키자.

git checkout 8bf981f

안타깝게도 여전히 detached head상태이다. HEAD가 브랜치를 통해 커밋을 가리키지 않고, 직접 커밋을 가리키고 있다.

스크린샷 2021-05-04 오전 11 16 48

깃은 브랜치를 통해 커밋들을 관리한다. detached HEAD commit은 브랜치에 연결되어있지 않아서 관리가 안되어서 문제이다.

어떻게 Attached HEAD의 상태로 만들까?

방법은 브랜치를 새롭게 만드는 것이다.

git checkout -b <branch name>

브랜치의 상태를 확인해보면, HEAD가 now-in-attached 브랜치를 가리키고, now-in-attached 브랜치는 커밋을 가리키는 attached HEAD 상태가 된 것을 알 수 있다.

스크린샷 2021-05-04 오전 11 22 12

출처

branch base가 잘못되었다니...?!

처음으로 맡은 일을 처리하고 PR을 남기려던 찰나에,
내가 따온 브랜치가 아닌 다른 브랜치에서 브랜치를 따왔어야함을 알게 되었다... 😳

원래 팠어야 하는 브랜치에서 다시 작업을 해야하나...?
고민하던 중에 팀원분께서 cherry-pick을 이용해보라고 하셨다.
cherry-pick이란 다른 브랜치에서 원하는 커밋을 내 브랜치로 가져올 때 사용하는 명령어이다.

branch base를 찾기 위해 여러 블로그를 돌아다니면서 해보았다.
그 여정을 커밋 이력을 살펴보면서 다시 알아봐야겠다.

  • 브랜치 이름 정의
    • feature : 내가 작업했던 브랜치
    • base : 원래 따왔어야 하는 올바른 브랜치

1. rebase로 commit message 바꾸기

 우선 내가 작성한 커밋 메시지가 커밋 컨벤션에 어긋나있음을 확인했다.

커밋 메시지를 수정을 git rebase로 하였다.

git rebase -i HEAD~6

HEAD부터 이전 몇 번째 커밋까지 수정할 것인지를 적어주었다.
그러면 내 커밋 이력이 있는 vim 창이 뜬다.

pick 8cc09ef9 Fix: ...
pick 5e355c52 Markup: 이미지 변경
pick 4d0902de Markup: 이미지 변경
pick fc8cb382 Update: [프론트] 
pick 4edee528 Update: [프론트] 
pick 7a339cc4 Update: [프론트]

# Rebase 542daaf8..67bd2376 onto 4d0902de (19 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 <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]

여기서 pickreword 혹은 r로 바꿔주고, :wq로 저장하고 창을 나간다.
이후 차례로 커밋 이력을 수정할 수 있는 창이 뜨게 된다.
커밋 메시지를 수정후, 저장해준다.

수정한 커밋 메시지가 잘 반영되었는지를 git log로 확인하자.

2. 작업한 커밋을 원격 origin 레포의 feature로 푸쉬 -> 실패

커밋이 잘 수정되었으니, 이를 origin 레포에 우선 올려두고자 하였다. (로컬에 있다가는 못찾을까봐 무서워서...)
그래서 feature 브랜치로 푸쉬하였으나 실패하였다.
그 때 떴던 경고가 Detached HEAD라는 것이었다.
HEAD가 브랜치를 가리키지 않고, 커밋을 직접 가리키는 것을 말한다.
이를 해결하기 위해 Attached HEAD로 바꾸는 작업을 진행했다.

3. Detached HEAD를 Attached HEAD로 바꾸기

전략은 이러하다.
커밋 2a0c62cf은 수정된 커밋 메시지의 기록이 있는 가장 마지막 커밋이다.

  • 이 커밋을 기준으로 branch temp를 만들고, 기존 feature 브랜치는 삭제한다.
git branch temp 2a0c62cf
git branch -D feature
  • temp 브랜치의 이름을 feature로 바꾼다.
 gb -m temp feature

4. 작업한 커밋을 원격 origin 레포의 feature로 푸쉬 -> 성공

feature를 다시 원격 feature 브랜치에 푸쉬한다.

 git push origin feature --force

5. cherry-pick으로 base브랜치에 있는 커밋 가져오기

내 feature브랜치에는 없고, base 브랜치에는 있는 커밋을 알아낸 후,
해당 커밋들을 내 브랜치로 가져오고자 하였다.

git log feature..base --oneline --no-merges

여기서 보여지는 커밋 이력중 가장 첫 커밋 ~ 가장 마지막 커밋을 체리픽을 가져오고자 했다.
git cherry-pick <commit-A>^..<commit-B>은 commitA부터 commitB까지의 커밋을 checkout된 브랜치로 가져오게 된다.

git cherry-pick 28791afc^..a0818146

그랬더니 다음과 같은 에러가 뜨면서 체리픽은 실패했다고 알려주었다.

error: empty commit set passed
fatal: cherry-pick failed

base 브랜치가 내가 따왔던 브랜치와 합친 상태여서, base와 내 브랜치에서 충돌은 없었다.
그래서 어제는 일단 PR을 날리고 마무리를 했다.

💡 오늘 다시 와서 생각해보니, base 브랜치에서 새로운 브랜치를 만들고,
그 브랜치에서 내가 작업했던 커밋들을 cherry-pick했어야 하는 것 같다...!

git에 대해 잘 모르니까 시간 너무 잡아먹는다. git 어렵지 않게 사용할 수 있도록, git 공부도 해야겠다.

참고

폴더마다 config 다르게 두기

😑 뭐가 문제였냐면...

회사 레포지토리는 ~/kakao에 두고 있고, 개인 레포지토리는 ~/study에 두고 있다.
global config는 회사 계정이다.
/study 폴더에 개인 레포지토리를 만들어서 커밋할 때마다 계정이 회사 계정으로 등록되었다.
매 번 개인 레포를 만들때마다 local 설정을 해야했지만, 설정해주는걸 까먹은 적도 있고...넘 귀찮고...
그래서, /study 폴더에 있는 레포지토리는 다른 config 파일을 사용하게 하고 싶었다.

😎 그래서 이렇게 하니까...

.gitconfig 파일에 디렉토리 경로에 study가 포함되어있다면 .gitconfig-study 설정 파일을 참고하도록 하였다.

  • ~/.gitconfig
[user]
	name = lillie.yang
	email = [email protected]
[includeIf "gitdir:~/study/"]
	path = ~/.gitconfig-study
...
  • ~/.gitconfig-study
[user]
	name=yejineee
	[email protected]

😏 뭐가 좋았냐면~

이렇게하면 따로 레포지토리마다 local 설정을 하지 않아도, study 폴더에 있는 레포지토리들은 전부 개인 계정으로 설정이 된다. 👍

참고

원격저장소의 브랜치 가져오기

git remote 갱신하기

git remote update

원격 저장소 branch 확인

  • 원격 저장소의 브랜치 리스트

    git branch -r
    
  • 로컬, 원격의 모든 브랜치 리스트

    git branch -a
    

원격 저장소의 branch 가져오기

git checkout -t <branch name>

예 : git checkout -t origin/sysprog

  • 이름 변경해서 가져오기
     git checkout -b <생성할 브랜치 이름> <원격 저장소의 브랜치 이름>
    

원격 브랜치 참고하기

git checkout <branch name>

아무런 옵션없이 checkout하면 'detached HEAD' 상태로 소스를 확인, 변경할 수 있다.
그러나, commit push할 수 없으며, 다른 브랜치로 체크아웃시 사라진다.

HEAD란 무엇인가?

HEAD

브랜치가 master, branch-a가 있는데, 이중 작업중인 브랜치를 아는 방법은 무엇일까?

git은 'HEAD'라는 포인터를 갖고 있다. 이 포인터가 지금 작업하는 로컬 브랜치를 가리킨다.

git log —oneline —decorate

git log --oneline --decorate를 사용하면, 브랜치가 어떤 커밋을 가리키는지 확인할 수 있다.

스크린샷 2021-05-04 오전 10 47 51

현재 브랜치는 HEAD가 가리키는 branch-a이다.

master와 branch-a 둘 다 840f217을 가리키는 것을 확인할 수 있다.

  • 팁 : gloga
    zsh는 gloga라는 alias를 제공하는데, 이는 git log --oneline --decorate --graph --all이다.

    간단하게 gloga로 현재 브랜치가 어떤 커밋을 가리키는지 확인하자!

참고

Git - 브랜치란 무엇인가

Git 구조

image

이 그림에서 index가 staging area, local repository가 .git repository이다.

git은 데이터를 일련의 스냅샷으로 기록한다.

커밋을 하면 메타데이터와 이전 커밋에 대한 포인터 등을 포함하는 커밋 object를 저장한다.

이전 커밋 포인터가 있기 때문에 현재 커밋이 무엇을 기준으로 바뀌었는지를 알 수 있다.

최초 커밋을 제외한 나머지 커밋은 이전 커밋 포인터가 적어도 하나씩 있고,

브랜치를 합친 Merge 커밋의 경우, 이전 커밋 포인터가 여러 개가 있다.

git stash로 작업중이던 파일을 임시 저장하기

git stash란?

  • 커밋은 할 수 없지만, 브랜치 전환을 하거나 커밋 변경을 해야할 때, 작업하던 내용을 스택에 넣을 수 있다.

사용법

stash 영역에 추가하기

  • git stash : 트래킹된 파일을 저장. WIP로 저장됨.
  • git stash save [이름] : stash한 작업에 이름을 저장

stash 영역에서 꺼내기

  • git stash apply : 가장 최근에 저장한 stash를 복원. list에 남아있다.
  • git stash apply [stash id] : stash id에 해당하는 stash를 복원
  • git stash pop : 가장 최근에 저장된 stash를 복원하고, list에서 삭제

stash 영역 조회하기

  • git stash list : stash 기록을 리스트로 확인

commit message 수정하기

rebase로 commit message 바꾸기

커밋 메시지를 수정을 git rebase로 하였다.

git rebase -i HEAD~6

HEAD부터 이전 몇 번째 커밋까지 수정할 것인지를 적어주었다.
그러면 내 커밋 이력이 있는 vim 창이 뜬다.

pick 8cc09ef9 Fix: ...
pick 5e355c52 Markup: 이미지 변경
pick 4d0902de Markup: 이미지 변경
pick fc8cb382 Update: [프론트] 
pick 4edee528 Update: [프론트] 
pick 7a339cc4 Update: [프론트]

# Rebase 542daaf8..67bd2376 onto 4d0902de (19 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 <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]

여기서 pickreword 혹은 r로 바꿔주고, :wq로 저장하고 창을 나간다.
이후 차례로 커밋 이력을 수정할 수 있는 창이 뜨게 된다.
커밋 메시지를 수정후, 저장해준다.

수정한 커밋 메시지가 잘 반영되었는지를 git log로 확인하자.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.