Git 재활 훈련 1일차 - 개요

0

Git

목록 보기
1/14

이 시리즈는 git에 대해서 아무것도 모르는 사람을 위한 글이 아니다. 분명 학생이었을 때는 열심히 배웠다가, 현업에 들어가서 몇 년동안 비슷한 명령어만쳤던 재활 훈련자를 위한 글이다.

git init

git을 처음 시작할 때는 git init으로 시작하도록 한다.

git init

이 다음 .git directory가 우리의 project에 만들어졌을 것이다.

ls -a .git
.  ..  branches  COMMIT_EDITMSG  config  description  HEAD  hooks  index  info  logs  objects  refs

git status를 통해서 현재 project의 git상태를 확인할 수 있다.

git status

On branch master
nothing to commit, working tree clean

다음과 같이 나왔다면 project의 .git과 상호작용이 되고 있는 것이다.

참고로 .git이 생긴 directory 아래로 모든 file, directory는 git의 영역 안에 있는 것이다. 따라서, .git이 있는 project안에 새로운 directory를 만들어서 또 git init을 할 수는 없다.

git commit workflow

-------------------
|Working Directory|
-------------------
         |
      git add
         |
   --------------
   |Staging Area|
   --------------
         |
      git commit
         |
    ------------
    |Repository|
    ------------

각각의 code checkpoint를 git에서 commit으로 관리하는 것이다.

이들은 3개의 물리적인 영역이 아니라, 가상의 공간이다.

  1. working directory: 실제 작업이 이루어지는 local 공간
  2. staging area: commit하기 전의 변경 사항들이 있는 곳이다. git add로 올린다.
  3. repository: .git directory를 말한다. 여기에 변경 사항들이 저장된다. git commit으로 repo에 저장한다.

만약 working directory에 README.md 파일이 있다면 git status에 다음과 같이 나온다.

git status
On branch master

No commits yet

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

nothing added to commit but untracked files present (use "git add" to track)

git add를 통해서 staging area로 올려주도록 하자. 이 다음 git status를 확인하면 다음과 같다.

git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   README.md

staging area에 있다는 것을 알 수 있다.

git commit 시에는 항상 commit에 대한 설명을 같이 넣어주어야 한다. git commit 명령어 후에 에디터를 통해서 설명을 넣어주면 되는데, git commit -m ""으로 간단하게 메시지를 남길 수 있다.

git commit -m "add README.md"
[master (root-commit) ecba3bc] add README.md
 1 file changed, 42 insertions(+)
 create mode 100644 README.md

다음으로 git status를 쓰면 다음과 같이 나온다.

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

더 이상 working directory에 변경된 부분이 없다는 것이다.

git log를 사용하면 repository에 대한 정보를 얻을 수 있다.

git log
commit 1b624a2c0874b8cdb9aa8ffaf4c9b6110b3ef489 (HEAD -> master)
Author: colt <colt@colt.com>
Date:   Wed Jul 31 14:34:36 2024 +0900

    add README.md

commit ecba3bcc49a2c1691015ecf07139bb903e40f3e1
Author: colt <colt@colt.com>
Date:   Wed Jul 31 14:33:41 2024 +0900

    add README.md

다음과 같이 우리가 commit한 사항들이 나오는데, 이는 .git directory에 기록된 repository 정보라서 나오는 것이다.

git commit을 atomic하게 다루는 것이 좋은데, atomic하게 다룬다는게 무슨말인가?? atomic하게 다루라는 말은 git commit을 더 이상 쪼갤 수 없을 만큼 작게 다루라는 것이다. 즉, commit 한 가지에 한 가지 기능만 집중하라는 것이다.

또한, commit msg는 '현재 시제'를 써야한다. 이는 docs에서 추천하는 방법이다. 즉 changed맏고 change를 쓰라는 것이다. 그런데, 이는 실제 개발을 할 때 매우 애매하다. 왜냐하면 '현재 시제'는 하고 있는 느낌이고 '과거 시제'가 이미 commit한 내용에 대한 설명을 하고 있기 때문이다.

따라서, commit msg에 대해서는 자신이 속한 기관, 오픈소스 프로젝트의 commit style을 따르거나, 자신만의 확실한 이유가 있어야 한다.

만약 git commit 시에 나오는 editor가 너무 어려우면 다음의 명령어를 통해서 editor를 바꿀 수 있다.

git conig --global core.editor "vim"

위의 code는 vim이고 아래의 code는 vs code로 바꾸는 것이다.

git conig --global core.editor "code" --wait

추가적인 설정 방법은 아래를 참고하면 된다.
https://git-scm.com/book/en/v2/Appendix-C%3A-Git-Commands-Setup-and-Config

git commit --amend

commit을 시킨 후에 다음과 같은 이유로 수정을 하고싶을 때가 있다.

  1. 해당 commit에 특정 변동 사항, 추가, 삭제가 누락되었다.
  2. 해당 commit msg에 특정 msg가 누락되거나, 오탈자가 있다.

이런 경우에 git commit --amend를 사용하여, repository에 있는 최신 commit을 수정할 수 있다.

가령 다음과 같은 경우가 있다.

git add .
git commit -m "some commit"

그런데, review해보니 forgotten_file을 누락하여서, 새로 생성 후에 stage에 넣어준다.

git add forgotten_file

이 다음은 새로운 commit을 만들어야 할까? 이전 commit에 해당하는 내용이기 때문에 새로운 commit을 만들고 싶진 않다. 어떻게 해야할까?? 이때 사용하는 것이 바로 git commit --amend이다.

git commit --amend

--amend는 이전 commit을 취소하여 이전 commit의 내용과 현재 stage 내용을 바탕으로 새로운 commit을 하나 만드는 것이다. 이 과정에서 commit msg를 수정할 수도 있다.

따라서, git commit --amend를 사용하여 repository에 있는, 최근의 commit에 대해서 수정할 수 있는 것이다.

git log

git log를 사용하면 이런저런 commit들이 쭈룩 나오는 것을 볼 수 있다.

git log
commit 021927702020a86ec4d2c5bd0703a852bbf50339 (HEAD -> master)
Author: colt <colt@colt.com>
Date:   Wed Jul 31 14:51:45 2024 +0900

    feat: update .gitignore

commit 4f8b7e406703ef2cc81a87689fafcae86c9af37a
Author: colt <colt@colt.com>
Date:   Wed Jul 31 14:49:25 2024 +0900

    add .gitignore

...

너무 많고, verbose하기 때문에 필요한 정보를 얻기가 힘들다. 따라서, 필요한 정보를 얻기 편하도록 oneline으로 바꾸는 것이 있는데, 이것이 oneline 옵션이다.

git log --oneline
0219277 (HEAD -> master) feat: update .gitignore
4f8b7e4 add .gitignore
1b624a2 add README.md
ecba3bc add README.md

사실 git log에는 이런저런 option들이 많은데, 굳이 모두 다 사용할 필요는 없다.

Branch

branch는 commit의 연결을 나누는 분기가 된다.

                    --------> (commit4) [test branch]
                    |
(commit1) ---> (commit2) ---> (commit3) [master branch]

이렇게 branch를 나누고, branch를 서로 merge시켜주는 작업이 반복되는 것이 git의 업무이다.

                    --------> (commit4) -------->|     [test branch]
                    |                           merge
(commit1) ---> (commit2) ---> (commit3) ---> (commit5) [master branch]

가장 기본적으로 사용되는 branch가 master branch인데, master branch는 git에서 사용되는 기본 branch로 가장 근간이 되는 branch로 생각하면 된다. github의 경우는 2020이후에 main branch로 바꾸었는데, 이는 github 기준이다.

git log를 사용하면 현재 무슨 branch인지를 볼 수 있다.

git log --oneline
aa83f2c (HEAD -> master) feat: update .gitignore
4f8b7e4 add .gitignore
1b624a2 add README.md
ecba3bc add README.md

master라는 것을 알 수 있다. 그런데, HEAD는 무엇일끼?? 이를 'branch reference'라고 하는데, 이는 현재의 branch의 가장 최근 commit을 말하는 것이다.

                    --------> (commit4 - HEAD) [test branch]
                    |                          
(commit1) ---> (commit2) ---> (commit3) ---> (commit5 - HEAD) [master branch]

test branch의 가장 최근 commit인 commit4가 test branch의 HEAD이고, commit5는 master branch의 HEAD가 되는 것이다.

그래서 git log시에 가장 최근의 commit을 HEAD라고 표시한 것이다.

이제 git branch를 사용해서 현재 repository에 어떤 branch들이 있는 지 확인해보도록 하자.

git branch
* master

현재 master 밖에 없다. 새로운 branch를 만들기 전에 playlist.txt 파일을 만들고 추가해보도록 하자.

  • playlist.txt
SONG - ARTIST
=============

playlist.txt를 만들고, 이를 stage에 넣고 repository로 commit해주도록 하자.

git add ./playlist.txt
git commit -m "add playlist.txt"

git log

commit 193ea6f7130f743ee87fe109870ebbdb8eb2538c (HEAD -> master)
Author: colt <colt@colt.com>
Date:   Wed Jul 31 16:20:29 2024 +0900

    add playlist.txt
...

새로운 branch를 만들어보도록 하자.

git branch <branch-name>

bugfix라는 branch를 생성해보도록 하자.

git branch bugfix

확인해보도록 하자.

git branch 
  bugfix
* master

제대로 생성된 것을 볼 수 있다. 그런데 *master에 있는 것을 볼 수 있는데, master의 branch에 있다는 것을 의미한다.

이제 bugfix branch로 옮겨보도록 하자. 이전에는 git checkout을 사용했지만, 이제는 git switch를 사용한다. 사용 방법은 다음과 같다.

git switch <branch-name>

bugfix branch로 옮겨보도록 하자.

git switch bugfix 

Switched to branch 'bugfix'

이제 HEAD는 master branch가 아니라 bugfix branch를 가리킨다.

git log
commit 193ea6f7130f743ee87fe109870ebbdb8eb2538c (HEAD -> bugfix, master)
Author: colt <colt@colt.com>
Date:   Wed Jul 31 16:20:29 2024 +0900

    add playlist.txt
...

HEAD가 bugfix와 master를 가리키는 것을 알 수 있다. 이는 bugfixmaster의 최근 commit이 동일한 것이라는 걸 알려주고 있다.

이제 몇 가지 새로운 code를 추가하기 위해서 playlist.txt를 수정해보도록 하자.

  • playlist.txt
SONG - ARTIST
=============
DEAN - what2do
NEWJEANS - Super Shy

stage에 넣고 repository로 commit을 시켜주두록 하자.

git add ./playlist.txt
git commit -m "update playlist.txt"

이제 git log를 통해서 HEAD가 어디에 있는 지 확인해보도록 하자.

git log

commit f002b8fa14f0056fd77eb5f7f17972a98a029553 (HEAD -> bugfix)
Author: colt <colt@colt.com>
Date:   Wed Jul 31 16:29:47 2024 +0900

    update playlist.txt

commit 193ea6f7130f743ee87fe109870ebbdb8eb2538c (master)
Author: colt <colt@colt.com>
Date:   Wed Jul 31 16:20:29 2024 +0900

    add playlist.txt
...

master의 commit과 분리되어 HEADbugfix만 가리키는 것을 볼 수 있다.

다시 master branch로 이동해보면, bugfix에 추가했던 DEAN - what2doNEWJEANS - Super Shy가 playlist.txt에 없을 것이다.

git switch master

cat ./playlist.txt 
SONG - ARTIST
=============

checkout vs switch

git checkout 역시도 git switch처럼 branch를 이동할 수 있는데, git checkout이 이전부터 사용되어 아직도 많이 사용되고 있다. 그러나 git checkout은 너무나 많은 기능들을 담당하고 있기 때문에 git checkout 대신에 git switch가 등장한 것이다.

git checkout 역시도 branch 이동이 가능하다.

git checkout <branch-name>

또한, 가장 많이 사용되는 것 중 하나가 branch를 생성함과 동시에 이동하는 명령어로 -b옵션을 사용하면 된다.

git checkout -b <branch-name>

이 기능은 switch에서도 제공해주는데, -b가 아니라 -c로 create 옵션이라는 것이다. 즉, 새로운 branch를 create하고 이동하겠다는 것이다.

git switch -c <branch-name>

checkout은 그 의미도 기능도 매우 모호하지만 switch는 매우 명시적이다.

Staging 되지 않은 변경사항이 있을 때 branch를 이동하는 경우

현재 master branch에 있다고 하자. 여기서 playlist.txt 파일을 수정해보도록 하자.

  • playlist.txt
SONG - ARTIST
=============

eqweqwewqew

그러나 git add를 통해서 playlist.txt 파일을 staging시키지 않고, branch를 이동시키려고 한다면 어떤 문제에 봉착할까? 이전에 만든 bugfix branch로 이동해보도록 하자.

git switch bugfix 
error: Your local changes to the following files would be overwritten by checkout:
        playlist.txt
Please commit your changes or stash them before you switch branches.
Aborting

거부당하게 되는데, error 로그를 잘 보면 playlist.txt가 수정되었지만 staging area에 없기 때문에 다른 branch로 이동시 삭제됨으로 처리하라는 것이다.

이를 해결하기위해서는 staging area에 넣고 commit해야한다.

git add ./playlist.txt 
git commit -m "update playlist.txt"

git switch bugfix
Switched to branch 'bugfix'

bugfix로 branch가 옮겨지는 것을 볼 수 있다.

이렇게 branch를 이동하기 전에 특정 file을 수정했다면 commit 후에 branch를 이동하는 것이 좋다.

그런데, 만약 file을 새로 만드는 경우는 어떻게 되는가?? moon.txt를 하나 만들어보도록 하자.

  • moon.txt
hello moon

이 상태에서 branch를 이동해보도록 하자.

git switch master 
Switched to branch 'master'

문제없이 이동되는 것을 볼 수 있을 것이다. 이처럼 새로운 파일을 추가하는 것은 어떤 branch를 이동하던간에 commit을 하지 않아도 따라가게 된다.

branch 이름 변경, 삭제

삭제를 하기 위해서 쓸모없는 branch를 하나 만들어보자.

git switch -c deleteMe

git branch
  bugfix
* deleteMe
  master

branch를 삭제할 때는 -d 또는 --delete를 사용하면 된다.

git switch master

git branch -d deleteMe 
Deleted branch deleteMe (was 204aed7).

만약, 병합 상태가 해결되지 못했다면 -d를 사용해도 삭제되지 않는다. 강제로 삭제하는 방법이 있는데, -D 를 사용하면 된다. 이는 --delete --force의 단축어이다.

다음으로는 branch의 이름을 변경하는 벙법인데 -m 또는 --move 옵션을 사용한다. 이름을 바꾸려는 branch에 가서 git branch -m <바꾸고 싶은 이름>을 쓰면 된다.

git switch -c recent

recent branch의 이름을 lately로 바꾸자.

git branch -m lately

git branch
  bugfix
* lately
  master

바뀐 것을 볼 수 있다.

0개의 댓글