3 기본

source: categories/study/git-beginner/git-beginner3.md

3.1 Git Lifecycle

  • 간단히 add & commit(ci)

    • add: 이 파일을 Git이 관리하게 하겠다 (or 수정 완료했다)
    • commit: 이 파일을 Git에 저장하겠다

  • Untracked

    • Git과 아무 상관이 없는 상태
    • 따라서 Git이 대상 파일을 관리하지 못함
    • 최초 add를 해줘야 Git의 관리 대상이 됨
      위 이미지에서 Untracked 상태에서 add 명령어를 치면 Staged 상태가 되는 것을 볼 수 있다.
    • Git이 관리하는 파일을 삭제하면 Untracked가 됨
  • Unmodified

    • 코드 저장이 완료된 상태
    • Staged 상태에서 commit을 하면 Unmodified가 됨
      위 이미지에서 Staged 상태에서 commit 명령어를 치면 Unmodified 상태가되는 것을 볼 수 있다.
  • Modified

    • Git으로 관리되고 있던 코드를 수정하여 변경이 일어난 상태
    • Unmodified 상태인 파일을 수정하면 Modified가 됨
      위 이미지를 보면 Unmodified 상태에서 파일 수정만해도 Modified 상태가 되는 것을 확인할 수 있다.
    • commit 할 수 없음. commit 하려면 Staged 상태가 되야함
      Staged 상태로 만들기 위해선 add를 해야된다.
  • Staged

    • 이제 코드를 저장해도 좋다는(commit이 가능한) 상태
    • Untracked/Modified 상태인 파일을 add 하면 Staged가 됨

3.2 status (st)

현재 Git Lifecycle에서 어떤 상태인지를 알아볼 수 있는 명령어가 git status이다.

  • 현재 git 상태를 보여줌
  • Untracked files: Untracked 상태인 파일들
> echo "status exer" >> st.md
> git status (alias 등록된걸로 하면 git st)

---

On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)

st.md

nothing added to commit but untracked files present (use "git add" to track)
  • Changes to be committed: Staged 상태인 파일들
> git add st.md
> git status (alias 등록된걸로 하면 git st)

---

On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

new file:   st.md
  • nothing to commit, working tree clean: Unmodified 상태인 파일들
> git commit -m 'Make st.md' (alias 등록된걸로 하면 git ci -m 'Make st.md')
> git status (alias 등록된걸로 하면 git st)

---

On branch master
nothing to commit, working tree clean
  • 파일 수정 후 커밋
> vi st.md
> git status (alias 등록된걸로 하면 git st)

---

On branch master
Your branch is ahead of 'origin/master' by 1 commit.
(use "git push" to publish your local commits)

Changes not staged for commit
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

modified: st.md

no changes added to commit (use "git add" and/or "git commit -a")

3.3 log(lg)

  • 히스토리를 조회하는 명령어
  • 커밋 단위로 히스토리가 쌓임
  • log를 볼 줄 알아야 develop, release, hotfix 브랜치가 난무할 때 merge 방향이나 순서를 이해할 수 있음
  • 위에 있는 것이 최신, 아래 있을 수록 예전 커밋
git lg (alias 등록한 명령어)

---

* ab118e1 - (73 minutes ago) Make st.md - Country
* e5d33ad - (2 days ago) initial commit - Country (origin/master)

3.4 add

  • 파일을 Staged 상태로 만듦 -> 파일을 Git이 관리하는 상태로 만듦

    • Untracked / Modified 상태의 파일에 사용할 수 있음
  • 이제 commit을 하면 코드를 저장할 수 있음
  • Untracked에서 진행
echo "## Git class" >> index.md
git st

---

On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)

index.md

nothing added to commit but untracked files present (use "git add" to track)
git add index.md
git st

---

On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

new file:   index.md
  • Modified에서 진행
vi st.md
git st

---

Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

modified:   st.md
git add st.md
git st

---

On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

new file:   index.md
modified:   st.md

3.5 commit (ci)

  • 파일을 Unmodified 상태로 만듦 -> 한 단위의 작업이 완료
  • Git 시스템에 영구적으로 변경을 저장
  • SHA-1 알고리즘을 적용한 해시값을 키로 생성.
    커밋을 하면 16진수 숫자들이 생성. 이것이 해시키임.
  • 히스토리가 하나 추가됨
  • 실무에서 한 작업 (기능, 피처) 단위로 한 커밋 권장
    커밋 단위가 너무 커도 안되고 너무 작아도 안됨.
git ci -m 'Modify files'

---

[master 42298d3] Modify files
2 files changed, 2 insertions(+)
create mode 100644 index.md
git st

---

On branch master
nothing to commit, working tree clean
git lg

---

* 1e928bc - (20 seconds ago) Modify files - Country (HEAD -> master)
* 51462d0 - (4 hours ago) Modify st.md - Country
* ab118e1 - (4 hours ago) Make st.md - Country
* e5d33ad - (2 days ago) initial commit - Country (origin/master)  

3.5.1 옵션

  • -m : 메시지를 넣음
  • -a : add를 같이 함. 단순히 Modified
  • -am : -a-m을 합친 것. 제일 많이 사용
  • --amend

    • 마지막 커밋을 수정
    • Stage 상태의 파일들과 같이 커밋됨
    • 만약 Stage에 아무것도 없다면 (commit이후에 작업을 안했으면) 커밋 메시지만 수정
      git lg
        
      ---
        
      * 1e928bc - (5 minutes ago) Modify files - Country (HEAD -> master)
      * 51462d0 - (4 hours ago) Modify st.md - Country
      * ab118e1 - (4 hours ago) Make st.md - Country
      * e5d33ad - (2 days ago) initial commit - Country (origin/master)
    
      git ci --amend
        
      ---
        
      [master 69e0e26] Rewrite commit message
      Date: Mon Mar 9 23:32:31 2020 +0900
      2 files changed, 2 insertions(+)
      create mode 100644 index.md
    
      git lg
        
      ---
        
      * b0c729f - (6 minutes ago) Rewrite commit message - Country (HEAD -> master)
      * 51462d0 - (4 hours ago) Modify st.md - Country
      * ab118e1 - (4 hours ago) Make st.md - Country
      * e5d33ad - (2 days ago) initial commit - Country (origin/master)
    

3.6 branch (br)

  • 커밋 사이를 가볍게 이동할 수 있는 어떤 포인터 같은 것 (3.1 Git 브랜치 - 브랜치란 무엇인가)
  • 하나의 작업 공간 단위 정도로 생각하면 쉬움
  • 브랜치 확인: git br
  • 브랜치 생성: git br test/1
  • 브랜치 삭제: git br -D test/1
git br

---

* master

현재 작업중인 브랜치 앞에 *이 붙어있음.
현재 브랜치는 master 브랜치 하나가 있고, 현재 내가 작업하고 있는 브랜치는 master 브랜치이다 라는 뜻.

git br test/1
git br

---

* master
  test/1
git br -D test/1

---

Deleted branch test/1 (was b0c729f).

-D 대문자 D를 써도되고 소문자 d를 써도 된다.

git br

---

* master

3.7 branch 전략

3.7.1 Git branch 전략 (Git Flow)

Gif Flow 전략
위 사진이 Git Flow 전략을 설명할 수 있는 사진입니다.
위 사진 제일 위에 쓰여있는 것들이 브랜치 이름입니다.
보통 위 5개의 이름을 가진 브랜치들을 사용해 개발을 하게됩니다.
그리고 시간은 아래로 갈수록 지나는 것입니다.

위 사진의 master 브랜치를 보면 Tag 0.1이 생성되고 거기서 develop 브랜치가 나오고 hotfixes 브랜치가 나오고, 이런 과정들을 쭉 볼 수 있습니다.

  • master

    • git init하면 생기는 태초의 브랜치
    • 배포 가능한, 말그대로 master 브랜치
    • 보통 태그를 따서 태그로 배포함
      태그는 보통 위 사진에서도 볼 수 있듯이 0.1버전, 0.2 버전, 1.0 버전 이런식으로 땁니다.
      master 브랜치에서 태그 버전을 따서 그 태그를 가지고 배포를 하게됩니다.
      보통 master는 중앙 브랜치로 사용하게 됩니다.
      즉, 그렇기 때문에 master 브랜치는 어떤 Tag로 롤백을 하더라도 바로 배포가 가능하도록 관리를 해야됩니다.
  • develop

    • 보통 작업을 할 때 기준이되는 브랜치입니다.
      위 사진에서도 보시면 처음에 master 브랜치에서 develop 브랜치를 생성하고 그 뒤로 많은 일들이 develop 브랜치에서 이뤄지는 것을 보실 수 있습니다.
    • 개발 서버에도 평소에는 develop 기준으로 배포하며 테스트함.
      보통 회사에선 개발서버와 리얼서버로 나뉘어져있는데, 개발서버 같은 경우는 develop 브랜치를 기준으로해서 배포를해서 테스트를 합니다.
    • 생성위치: master (태초)
      보통 처음에 master 브랜치로부터 생성됩니다.
  • hotfix

    • 핫픽스는 말 그대로 급하게 고친 버전을 의미하는데 서비스에 문제가 생겨 갑자기 무언가 고쳐서 배포해야할 때 사용합니다. (또는 급하게 기능이 추가되었을 때)
    • 생성위치: master (그렇지 않으면 다른 작업들이 딸려나감)
      위에서도 언급했지만 master 브랜치는 어느 시점이던지 배포해도 아무런 문제가 없도록 관리가 되어야한다고 했습니다.
      그래서 hotfix가 발생할 때는 develop에서 hotfix 브랜치가 따지는 것이 아니라 master 브랜치에서 생성해서 hotfix 브랜치를 만들게됩니다.
    • merge: master & develop
      그럼 hotfix 브랜치에서 고칠 것을 고치고 이제 배포를 해야되는데 그때는 master 브랜치로 합치고 또 develop 브랜치에도 합쳐줍니다.
      develop에도 해줘야되는 이유는 그래야 developmaster와 싱크가 맞고 그 상태에서 새로운 작업을 할 때, hotfix에서 추가된 기능들을 사용할 수 있기 때문입니다.
  • feature

    • 실제로 뭔가 기능(feature)를 만드는 브랜치
    • 생성위치: develop
      보통 develop 브랜치에서 생성합니다.
    • merge: develop (code review)
      develop에서 생성했기 때문에 다시 합칠 때도 develop 브랜치로 합쳐줍니다.
      그래서 보통 회사에서 일을 할 때는 develop 브랜치에서 feature 브랜치를 생성해서 거기서 특정 기능을 개발을해서 pull request를 보내서 거기서 코드리뷰를 받고 거기서 승인을 하면 develop 브랜치로 합치게됩니다.
  • release

    • 새로운 기능들을 추가하여 배포하기 위한 브랜치
    • 생성위치: develop
    • merge: master & develop
  • 이러한 Git Flow 전략 말고도 다른 전략들이 있습니다.

3.7.2 HEAD

  • 지금 작업하는 로컬 브랜치를 가리키는 포인터 ((3.1 Git 브랜치 - 브랜치란 무엇인가)[https://git-scm.com/book/ko/v2/Git-%EB%B8%8C%EB%9E%9C%EC%B9%98-%EB%B8%8C%EB%9E%9C%EC%B9%98%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80]{:target="_blank"})
  • 현재 브랜치 마지막 커밋의 스냅샷
  • branch를 변경하면 해당 브랜치의 마지막을 가리키고 있음
  • HEAD를 움직이면서 여러 버전의 코드들을 볼 수 있음

3.8 checkout (co)

  • 다른 브랜치로 이동
  • 옵션

    • -b : 브랜치 생성하고 그 브랜치로 checkout

      • 아래 두 명령은 같음
        git co -b develop
      
        git br develop
        git co develop
      
git co master

3.9 checkout TIP

  • 커밋의 hash값을 알면 시간 여행이 가능함
git lg

---

* b0c729f - (3 hours ago) Rewrite commit message - Country (HEAD -> master)
* 51462d0 - (6 hours ago) Modify st.md - Country
* ab118e1 - (7 hours ago) Make st.md - Country
* e5d33ad - (2 days ago) initial commit - Country (origin/master)
git co e5d33ad

---

Note: checking out 'e5d33ad'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

git checkout -b <new-branch-name>

HEAD is now at e5d33ad initial commit
git lg

---

* b0c729f - (3 hours ago) Rewrite commit message - Country (master)
* 51462d0 - (6 hours ago) Modify st.md - Country
* ab118e1 - (7 hours ago) Make st.md - Country
* e5d33ad - (2 days ago) initial commit - Country (HEAD, origin/master)
git br

---

* (HEAD detached at e5d33ad)
  develop
  master

현재 브랜치는 master도 아니고 develop도 아닌 것을 확인할 수 있습니다.
이렇게 옛날 커밋으로 돌아가는 행동을 왜할까?
실무의 경우로 생각해보겠습니다.

  1. 예전 코드를 확인해야될 때
  2. 롤백해야될 때
git co master

다시 master로 돌아갈 수 있습니다.

git br

---

  develop
* master

3.10 push

  • 로컬 브랜치의 정보를 원격 저장소로 업로드
  • Clone 한 리모트 저장소에 쓰기 권한이 있어야 함
  • 같은 브랜치로 여러명이 받아서 누군가 push를 했다면 나는 push 안됨
  • 다른 사람이 작업한 것을 가져와서 합친 후에 (Merge or Rebase) Push 할 수 있음
git st

---

On branch master
Your branch is ahead of 'origin/master' by 3 commits. (너의 브랜치는 원격 master보다 3커밋이 앞서있다 라는 뜻)
(use "git push" to publish your local commits)

nothing to commit, working tree clean
git lg

---

* b0c729f - (26 hours ago) Rewrite commit message - Country (HEAD -> master, develop)
* 51462d0 - (30 hours ago) Modify st.md - Country
* ab118e1 - (31 hours ago) Make st.md - Country
* e5d33ad - (3 days ago) initial commit - Country (origin/master) // <- 원격 저장소의 master 브랜치는 이 시점에 멈춰있음을 의미합니다.
git co master
git push [origin] [master]

위의 [] 대괄호 표시는 생략 가능하다는 뜻입니다.

  • 옵션

    • --force (-f)

      • 내 로컬 브랜치로 원격 브랜치를 덮어 씌워버림
      • 내가 혼자 작업하던 feature 브랜치에서만 사용해야함
      • 시나리오: 누군가 악의적으로 master브랜치를 망가뜨린다면?
        위에서 말씀드렸다시피 Git의 장점은 분산처리. 즉, 어떤 누군가의 로컬에 이전 버전이 남아있다면 복구 가능.
        여튼 이러한 위험 때문에 master 브랜치엔 누구나 push할 수 있는 권한을 안줌. 제한을 걸어놓음.

3.11 pull, fetch

  • pull: Clone 한 서버에서 데이터를 가져오고, 그 데이터를 자동으로 현재 작업하는 코드와 Merge (2.5 Git의 기초 - 리모트 저장소)
  • fetch: 서버에서 데이터만 가져오고 자동으로 코드를 합치지는 않음
-- 새로운 디렉토리
cd ~
mkdir git-other
cd git-other
git clone 'https://github.com/<깃계정>/<레포이름>.git'
cd git-class
vi README.md
git ci -am 'Modify README.md'
git push
-- 원래 디렉토리
git pull

-- 새로운 디렉토리
cd ~
mkdir git-other
cd git-other
git clone 'https://github.com/<깃계정>/<레포이름>.git'
cd git-class
vi README.md
git ci -am 'Modify README.md'
git push
-- 원래 디렉토리
git fetch

git fetch를 하면 변경점을 내려받긴하나 합치진 않습니다.
fetch를 통해 변경점을 확인하신 후에

-- 원래 디렉토리
git pull

git pull을 하시면 합쳐집니다.

3.12 pull & push 실습

  • 환경: master에서 딴 test 브랜치 / 2개의 터미널
  • 내용

    1. fetch vs. pull
    2. pull 충돌 실험

       <<<<<<< HEAD
       b222b
       =======
       b111b
       >>>>>>> eb1e37c
      

      위의 HEAD는 현재 내 로컬이 가리키는 커밋.
      eb1e37corigin/test가 가리키는 커밋.
      이 상태에서 git merge --abort 명령어를 실행하면 git pull하려고 했던 명령어가 취소됩니다.

       git merge --abort
      
       git st
              
       ---
              
       On branch test
       Your branch and 'origin/test' have diverged,
       and have 1 and 1 different commits each, respectively.
       (use "git pull" to merge the remote branch into yours)
              
       nothing to commit, working tree clean
      

      그런데 이렇게 항상 --abort만 할 수 없습니다. 문제를 해결하고 merge하는 것도 해보도록 하겠습니다.

       b333b
      

      이렇게 충돌 파일을 수정하고

       git add a.txt
       git ci -m 'a.txt resolve conflict'
       git lg
      

      해결되어 잘 merge된 것을 확인하실 수 있으실 겁니다.

    3. branch 삭제

       git co master
       git br -D test
       git br
              
       ---
              
         develop <- 로컬에 존재하는 develop 브랜치는 아직 원격저장소에 안올렸기 때문에 원격저장소엔 없습니다.
       * master
      
       git br -r (remote에 있는 브랜치 확인)
              
       ---
              
       origin/master
       origin/test <- test는 로컬에서만 지웠기 때문에 아직 남아있습니다.
      
       git push origin --delete test (원격 저장소에있는 test 브랜치를 지우겠다는 뜻입니다.)
      
Tip

다른 작업자가 브랜치를 삭제해 원격 저장소에 적용해도 내 로컬엔 적용이 안됩니다.
git pull을 해도 삭제된 브랜치가 적용이 안됩니다. 내 로컬엔 그 브랜치가 남아있는 경우가 있습니다.
이럴 경우엔

git fetch -p

명령어를 통해 삭제된 원격 저장소의 브랜치를 로컬에도 반영합니다.
-pprune(가지를 쳐내다)의 약자입니다.

  • 추가 명령어

    • 파일 변경 내용 보기: git diff
    • 리모트의 브랜치 삭제: git push origin --delete {branch명}
    • 삭제된 리모트 브랜치를 로컬에도 반영: git fetch -p