Study to Git - 2

생활코딩 Gitn 두번째 수업 - GIT2

생활코딩 with Git

시작하기 전

최근 개인 프로젝트를 개발하며 Git에 대한 기본 사용법 또는 advanced 한 사용법에 대해 갈증을 느끼던 와중에 생활코딩의 이고잉님께서 강의하신 GITn 수업을 찾았고, 강의를 정리해가면서 복습할 목적으로 강의 전체에 대한 정리목적의 시리즈 포스팅을 이어나가려고 합니다.

이번 포스팅에서는 GITn 강의의 두번째 수업인 CLI - 버전관리 수업에 대해 정리해보도록 하겠습니다.

포스팅의 내용은 정리된 내용에 따라 매우 짧을수도 있으며 각 챕터마다 링크를 첨부해 내용이 부족해 이해가 안되시거나 햇갈리시는 분들은 강의를 직접 들어보시는 것도 추천드립니다.

이제 시작해보겠습니다! 화이팅!

강의 링크

생활코딩 Git CLI - 버전관리 강의

https://opentutorials.org/course/3839

GIT2 강의전체 유튜브 플레이리스트

https://www.youtube.com/watch?v=85f6tpKM5D4&list=PLuHgQVnccGMATJK16UJ9Fjay0ozrSZKiI

GITn - CLI 버전관리

챕터

  1. 수업소개

  2. 설치 (Mac & Windows)

  3. 버전관리의 시작

  4. 버전 만들기

  5. 여러개의 파일을 버전으로 만들기

  6. 버전간의 차이점 비교

  7. checkout과 시간여행

  8. 보충수업

  9. 삭제 - git reset

  10. 되돌리기 - git revert

  11. 수업을 마치며

1. 수업소개

이 수업은 CLI를 통해서 Git을 제어하는 방법을 강의합니다. 명령어로 Git을 사용하는 방법은 기억해야할 것도 많고, GUI 툴보다 까다로운 점도 있지만 CLI를 통한 제어법을 익히고 나면 복잡한 GUI 툴보다 간편하게 명령어로 Git을 다룰수 있으며 처리해야 할 일을 한번에 명령해서 자동으로 처리할 수 있는 장점이 있으며 추가적으로 GUI 툴로 다룰수 없는 서버환경에서도 Git을 사용할 수 있는 유일한 방법이기도 합나다.

2. 설치 (Mac & Windows)

Git CLI 다운로드

Git CLI 를 설치하는 방법은 https://git-scm.com/ 에 접속하면 위와 같은데 우측 모니터 화면에 나타난 다운로드 버튼을 클릭하고 완료 후 설치를 진행하시면 됩니다. (자세한 설치방법은 아래의 운영체제별 강의 영상을 참고해주세요.)

3. 버전관리의 시작

특정 디렉토리 또는 프로젝트의 버전관리를 시작하기 위해 디렉토리의 root level 에서 git init 명령어를 입력합니다. git initinitinitialize 의 약자로, 디렉토리의 git을 초기화한다는 뜻입니다. git init 명령어가 실행되면 해당 디렉토리에 .git 이라는 디렉토리가 생성되고 이 디렉토리에는 해당 디렉토리 또는 프로젝트의 버전관리에 필요한 모든 정보가 담겨져있는 지역 저장소(Local Repository)가 생성됩니다. .git 폴더를 삭제하면 버전관리의 역사가 모두 삭제되니 주의하셔야 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
> cd Documents/git-opentutorial
> git-opentutorial
git init .
Initialized empty Git repository in /Users/guest/Documents/git-opentutorial/.git
> cd .git
> ls -al
// ~ HEAD
// ~ branchs
// ~ config
// ~ hooks
// ~ info
// ~ objects
// ~ refs

4. 버전 만들기

Git 버전 만들기

  • Working Tree
    • 실제로 파일 생성, 수정 및 저장 등의 작업을 하는 디렉토리
    • 파일 생성 및 수정했을때 버전으로 만들어지기 전 영역
  • Staging Area
    • 버전에 포함될 생성된 또는 수정된 파일들이 대기하는 영역
  • Repository
    • 버전이 저장되는 곳
    • Repository가 가리키는 곳이 바로 해당 디렉토리의 .git 디렉토리임
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
> cd Documents/git-opentutorial
> git-opentutorial
nano hello1.txt // 파일 생성 및 수정 => 영역: Working Tree
> git status // git 상태조회
On branch master

No commits yet // 아직 버전이 없음을 의미

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

hello1.txt

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

Untracked files: ~ 은 아직 추적관리 되고 있지 않은 파일로 git에서 아직 어떠한 버전으로도 관리 되고 있지 않다는 의미입니다. 그럼 버전 관리의 영역으로 넘어가기 위해 아래와 같이 git add hello1.txt 명령어를 치면 hello1.txt 파일은 Working Tree 영역에서 Staging Area로 넘어가면서 git에 의해 추적되고 버전관리의 영역으로 들어가게 됩니다.

1
2
3
4
5
6
7
8
9
10
> git add hello1.txt
> git status
On branch master

No commits yet

Changes to be committed:
(Use "git rm --chached <file>..." to unstage)

new file: hello1.txt

Changes to be committed: ~ 은 기존의 Working Tree 에 있던 파일이 “commit이 되기 위한 변경사항” 으로 버전관리를 받기위해 대기하는 Staging Area 로 편입됐다는 뜻입니다. 그리고 버전을 생성하기 위해서는 git commit 명령어를 통해 지역 저장소에 해당 파일을 버전으로 생성해줍니다.

1
2
3
4
5
6
7
> git commit -m "Message 1" hello1.txt
[master (root-commit) d892719] Message 1
1 file changed, 1 insertion(+)
create mode 100221 hello.txt
> git status
On branch master
nothing to commit, working tree clean

nothing to commit, working tree clean 은 commit이 잘 완료되었으며 commit을 위한 변경사항이 없고, Working Tree도 깨끗하다는 뜻으로 지역 저장소 내에 해당 수정사항에 대한 버전이 잘 생성되었음을 의미합니다.

그렇다면 이 파일을 계속 수정할 경우에는 어떻게 될까요? 일단 hello1.txt 파일을 수정했다고 가정하고 시작하겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
> git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard chages in working directory)
modified: hello1.txt

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

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

> git commit -m "Message 2" hello1.txt
[master (root-commit) a172593] Message 1
1 file changed, 1 insertion(+)
> git status
On branch master
nothing to commit, working tree clean

Changes not staged for commit: ~ 은 commit 되지 않은 수정사항이 Staging Area에 있지 않다는 의미입니다. 그렇다면 Staging Area 영역으로 올리기 위해서는 git add <filename> 명령어를 사용하면 되고, 버전을 만들기 위해 git commit -m "Message 2" hello1.txt 을 실행한 후 git status 를 통해 상태를 조회해보면 더이상 commit 할 파일이 없으며 Working Tree도 깨끗하다는 것을 알 수 있습니다.

5. 여러개의 파일을 버전으로 만들기

위의 챕터에서 한가지 시나리오를 추가해보겠습니다. 단일 파일이 아닌 신규로 한개의 파일을 더 추가해 작업하는 것입니다. 보통의 경우, 한개의 파일만 수정하고 버전관리 하는 경우는 없기도 합니다. 우리는 기존에 hello1.txt 파일만 관리하고 있었는데 이번에 hello2.txt 파일도 신규로 생성해 작업하기 로 했습니다. 터미널에서 git 상태를 조회해보면 아래와 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
> git status
On branch master
Changes to be committed:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard chages in working directory)
modified: hello1.txt

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

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

hello1.txt 파일과 hello2.txt 이 정상적으로 조회가 되고 있음을 보여주고 있는데, 공통점으로는 두개의 파일 모두 Staging Area 에 올라와있지 않다는 점이고, 차이점으로는 hello1.txt 은 이전부터 git에서 버전으로 관리되던 소스이고, hello2.txt 는 아직 관리되지 못하고 있는 즉, 미추적 상태의 파일로 백업된 적도 없으며 원격 저장소(Remote Repository)에도 없기 때문에 협업 또한 진행할 수 없습니다. 따라서 Staging Area 에 올려 관리 받기 위해서는 두개의 파일 모두 git add 명령어를 사용하면 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
> git add hello1.txt
> git add hello2.txt
> git status
On branch master
Changes to be committed:
(use "git reset HEAD <file> to unstage")
modified: hello1.txt
new file: hello2.txt

> git commit -am "Message 3"
[master f430124] Message 3
2 file changed, 2 insertion(+)
create mode 820112 hello2.txt

Staging Area 에 올린 후 git 상태조회를 해보면 hello1.txt 파일의 경우에는 이전의 버전이 있으며 현재 수정된 상태이기 때문에 modified:, hello2.txt 파일의 경우에는 이번에 새롭게 추가된 파일로써 new file: 상태를 띄고 있습니다. 그리고 git commit 명령어를 통해 이전부터 관리해오던 파일과 신규 생성된 파일을 가지고 버전을 생성해줍니다.

6. 버전간의 차이점 비교

1
2
git diff // Show changes
git log -p

7. checkout과 시간여행

버전관리라고 하는 것은 다른말로 의미있는 변경점들을 기록하는 것. 그리고 이 효용은 미래와 과거로 시간탐색이 가능하는 것입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
> git log
commit commit_index_2 (HEAD -> master)
Author: Joontae
Date: Sun Sep 3 .....

Message 3

commit commit_index_1
Author: Joontae
Date: Sun Sep 3 .....

Message 2

commit commit_index_0
Author: Joontae
Date: Sun Sep 3 .....

Message 1

위와 같은 commit 히스토리가 있다는 시나리오를 가정해보면, 최신 버전은 commit 인텍스가 commit_index_2 인 commit 이고, 따라서 HEAD 라는 표시가 붙습니다. 만약 우리가 commit_index_1 commit 으로 돌아가고 싶으면, 즉 버전을 특정 커밋으로 롤백하고 싶으면 git checkout 명령어를 사용하면 됩니다.

1
> git checkout commit_index_1

위와 같이 git checkout <commit_index> 를 사용하게 되면 해당 커밋으로 롤백할 수 있고, git log 를 실행해 확인해보면, 아래와 같이 commit_index_1 커밋이 HEAD가 됐음을 확인할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
> git log
commit commit_index_1 (HEAD -> master)
Author: Joontae
Date: Sun Sep 3 .....

Message 2

commit commit_index_0
Author: Joontae
Date: Sun Sep 3 .....

Message 1

그리고 다시 우리가 제일 처음 시나리오에서 git log 를 통해 확인했던 가장 최신의 상태로 돌아가고 싶다면 아래와 같이 브랜치 이름과 함께 사용하면 해당 브랜치의 최신 커밋으로 되돌아갑니다.

1
> git checkout <branch_name>

8. 보충수업

1
2
3
4
> git add . // Working Directory에서 수정된 모든 파일을 Staging Area로 옮겨줌
> git commit -am "commit message" // `-am` 플래그는 Working Directory에서 수정된 모든 파일을 git add와 commit을 한번에 실행해준다. But, 단한번도 `git commit`을 통해 버전생성을 한적이 없는 파일은 `git add` 후 `git commit`을 해줘야 한다.
> git commit -m "commit message" // `-m` 플래그는 커맨드라인에서 커밋 메시지를 직접 작성할 수 있도록 해줍니다.

9. 삭제 - git reset

git reset 은 버전을 삭제하는 명령어입니다. 다시 한번 7. checkout과 시간여행git log 시나리오를 가져와보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
> git log
commit commit_index_2 (HEAD -> master)
Author: Joontae
Date: Sun Sep 3 .....

Message 3

commit commit_index_1
Author: Joontae
Date: Sun Sep 3 .....

Message 2

commit commit_index_0
Author: Joontae
Date: Sun Sep 3 .....

Message 1

만약 우리가 커밋 인덱스 commit_index_2 에서 커밋 인덱스 commit_index_1 로 돌아가고 싶다면 git reset commit_index_1 을 하면 됩니다. 그러나 git checkoutgit reset 의 차이점은 현재 작업중인 브랜치의 HEADcommit_index_1 커밋으로 돌아간다는 것입니다 (git checkout의 경우에는 HEAD가 최신 커밋으로 유지).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> git reset --hard commit_index_1
> git log

commit commit_index_1 (HEAD -> master)
Author: Joontae
Date: Sun Sep 3 .....

Message 2

commit commit_index_0
Author: Joontae
Date: Sun Sep 3 .....

Message 1

그렇다면 git reset 명령어 뒤에 붙는 플래그는 무엇이 있을까?

1
2
3
4
5
6
7
8
> git reset --help
Name:
git reset - Reset current HEAD to the specified state

SYNOPSIS
git reset [-q] [<tree-ish>] [--] <paths>...
git reset [--patch | -p] [<tree-ish>] [--] [<paths>...]
git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]

위와 같은 git reset 명령어 뒤에 많은 플래그가 붙는데 그 중 --soft | --mixed | --hard | --merge | --keep 들은 일종의 reset mode 입니다. 일단 --soft--hard 에 대해 설명하면,

  • --soft: 작업중인 파일들은 남겨둔채 HEAD 로 되돌리는 모드
  • --hard: 작업중인 파일까지 모두 HEAD 로 되돌리는 모드

10. 되돌리기 - git revert

git revert 를 사용하면 더 세련된 방식의 삭제의 목적과 보존의 목적을 동시에 달성할 수 있습니다. 다시 한번 7. checkout과 시간여행git log 시나리오를 가져와보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
> git log
commit commit_index_2 (HEAD -> master)
Author: Joontae
Date: Sun Sep 3 .....

Message 3

commit commit_index_1
Author: Joontae
Date: Sun Sep 3 .....

Message 2

commit commit_index_0
Author: Joontae
Date: Sun Sep 3 .....

Message 1

git revertgit reset 과 같이 되돌릴 수 있는 기능을 가지고 있는 것과 동시에 보존을 하는 기능 또한 가지고 있다고 했었습니다. 먼저 git reset 을 통해 현재 HEAD 커밋에서 commit_index_1 커밋으로 되돌린다면 아래와 같이 commit_index_1 커밋이 HEAD 가 될것입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
> git log

commit commit_index_1 (HEAD -> master)
Author: Joontae
Date: Sun Sep 3 .....

Message 2

commit commit_index_0
Author: Joontae
Date: Sun Sep 3 .....

Message 1

그러나 git revert 를 통해 되돌리려고 한다면 reset 과 다른 방식으로 시도해야 합니다. 위 예와 같은 시나리오로 현재 HEADcommit_index_2 커밋에서 commit_index_1 커밋으로 버전을 되돌리려고 할 경우, 우리는 되돌리려고 하는 커밋을 기준으로 그 다음의 커밋을 revert 해야합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
> git log
commit commit_index_2 (HEAD -> master)
Author: Joontae
Date: Sun Sep 3 .....

Message 3

commit commit_index_1
Author: Joontae
Date: Sun Sep 3 .....

Message 2

commit commit_index_0
Author: Joontae
Date: Sun Sep 3 .....

Message 1
1
> git revert commit_index_2

그리고 log를 확인해보면, 아래와 같이 되돌리고자 원하는 커밋 버전으로 되돌아간 것이 아닌 commit_index_2 커밋의 변화를 취소한 것입니다. 따라서, 변화를 취소하면 이전의 버전으로 되돌아간 것과 같은 효과가 나게되며 결국 커밋 인덱스가 commit_index_1 인 커밋과 같아지게 되는 것이고, 되돌아간 버전과 그 이전의 즉, 되돌아가기 직후의 수정된 버전이 모두 보존되는 효과를 얻게되는 것입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
> git log
commit commit_index_3 (HEAD -> master)
Author: Joontae
Date: Sun Sep 3 .....

Revert "Message 3"

This reverts commit commit_index_2.

commit commit_index_2
Author: Joontae
Date: Sun Sep 3 .....

Message 3

commit commit_index_1
Author: Joontae
Date: Sun Sep 3 .....

Message 2

commit commit_index_0
Author: Joontae
Date: Sun Sep 3 .....

Message 1

그리고 만약 commit_index_0 으로 되돌아가고 싶다면, commit_index_1 커밋으로 revert 하는 것이 아니라 commit_index_3, commit_index_2, commit_index_1 커밋을 차례대로 revert 하면 최종적으로 커밋 인덱스 commit_index_0 커밋으로 되돌아가고 되돌아간 히스토리를 보존할 수 있게 됩니다.

11. 수업을 마치며

버전관리의 핵심은 비교 입니다 ! 비교를 통해서 과거를 되돌아볼수 있다는 점이 버전관리의 핵심적인 효용입니다.

  1. Git1: Overview
  2. Git2: Cli - Version (현재 강의)
    • 버전관리를 위한 수업
  3. Git3: Cli - Backup
    • 백업이 필요한 사람들 위한 수업
  4. Git3: Cli - Collaborate
    • 백업을 기반으로 협업까지 진행하는 수업
    • tag, branch 등에 대한 수업