Home [Git] 형상관리 시스템과 Git, Github에 대해 알아보자
Post
Cancel

[Git] 형상관리 시스템과 Git, Github에 대해 알아보자

Quest 00. 형상관리 시스템

본 포스팅은 WebDevCurriculum 레포의 퀘스트에서 제공하는 checklist와 Quest를 하나하나 해결하며 기록을 남기기 위한 포스팅 입니다.

시리즈 목록
00. Quest00: 형상관리 시스템과 Git, Github에 대해 알아보자

오늘의 주제

오늘의 주제는 형상관리 시스템이다. 형상관리 시스템인 Git의 기초적인 사용법을 알아보자.

목표

git clone, git add, git commit, git push, git pull, git branch, git stash 명령어를 알고 Git에 대한 이것저것

Checklist

  • 형상관리 시스템은 왜 나오게 되었을까요?
  • git은 어떤 형상관리 시스템이고 어떤 특징을 가지고 있을까요?
    • git은 어떻게 개발되게 되었을까요? git이 분산형 시스템을 채택한 이유는 무엇일까요?
  • git과 GitHub은 어떻게 다를까요?
  • git의 clone/add/commit/push/pull/branch/stash 명령은 무엇이고 어떨 때 이용하나요? 그리고 어떻게 사용하나요?
  • git의 Object, Commit, Head, Branch, Tag는 어떤 개념일까요? git 시스템은 히스토리를 어떻게 저장할까요?
  • 리모트 git 저장소에 원하지 않는 파일이 올라갔을 때 이를 되돌리려면 어떻게 해야 할까요?

Quest

  • GitHub에 가입한 뒤, 이 커리큘럼의 저장소를 Fork떠서 자신의 저장소에 복사해 둡니다.
  • 터미널에 접속하여 명령어를 이용하여 복사한 저장소(자신의 저장소에 있는 레포)를 clone합니다.
    • 앞으로 git 작업은 되도록 커맨드라인을 통해 하는 것을 권장합니다.
  • 이 문서가 있는 폴더 바로 밑에 있는 sandbox폴더에 파일을 추가한 후 커밋해 보기도 하고, 파일을 삭제해 보고 수정해 보기도 하면서 각각의 단계에서 커밋했을 때 어떤 것들이 저장되는지를 확인합니다.
  • clone, add, commit, push, pull, branch, stash 명령을 충분히 익혔다고 생각되면, 자신의 저장소에 이력을 push합니다.

CheckList

1. 형상관리 시스템은 왜 나오게 되었을까요?

형상관리 시스템이 왜 나오게 되었는지 알려면 형상관리의 정의가 무엇인지 알아야 할 것 같아서 정의를 먼저 찾아보았다.

형상관리 시스템이란?
소프트웨어 구성 관리 또는 형상 관리는 소프트웨어의 변경사항을 체계적으로 추적하고 통제하는 것으로, 형상 관리는 일반적인 단순 버전관리 기반의 소프트웨어 운용을 좀 더 포괄적인 학술 분야의 형태로 넓히는 근간을 이야기한다.

음.. 나는 소프트웨어적인 관점에서 형상관리 시스템이란 소스코드 등의 변경사항, 버전 등을 체계적으로 관리해주는 시스템이라고 이해를 했다. 그렇다면 이 시스템은 왜 나오게 되었을까?

만약 내가 형상관리 시스템이 없던 시절의 개발자였다면 아마 이런 상황들이 한번쯤은 발생하지 않았을까 싶었다.

  • “되던 코드를 고쳤는데 에러가 나.. 근데 되던 코드를 저장을 안해놨어..”
  • “너가 A기능을 만들어 내가 B기능을 만들게! 근데 우리 각각의 코드를 어떻게 합치지..?”
  • “컴퓨터가 고장이나서 내가 짠 코드들을 찾을 수가 없어 ㅠㅠ;;;”
  • “매번 코드를 공유할때마다 압축해서 메일로 보내고 받고.. 협업하기 너무 힘드네 ..”

잠깐만 생각을 해봤는데도 굉장히 불편할거같다는 생각이 든다. 당연하게도 형상관리 시스템이 없던 시절에는 이 문제들 외에도 많은 문제점들이 있었을 것이고 이 문제를 해결하기위해 위대하신 개발자 선배님들께서 형상관리 시스템을 만드신 것이 아닐까 생각해볼 수 있을 것 같다.

2. git은 어떤 형상관리 시스템이고 어떤 특징을 가지고 있을까요?

git은 분산 버전 관리 시스템(Distributed revision control system)이다.
버전 관리 시스템은 크게 두가지로 분류할 수 있는데 첫째는 중앙집중식 버전관리 둘째는 분산 버전 관리이다. 중앙 집중식 버전관리의 경우에는 central server에서 코드를 가져오면 그 코드의 commit(변경 기록들)은 가져오지 않고 오직 중앙 서버의 파일만을 받아오는 반면 분산 버전 관리 시스템은 해당 저장소를 변경 기록들과 함께 복제해온다. 그래서 CVCS의 경우 중앙서버에 문제가 생기면 변경기록들을 전부 잃는 반면에 DVCS에서는 중앙서버에 문제가 생겨도 clients중 하나를 골라 변경기록들과 함께 서버를 복원시킬 수 있다.

요약
git은 분산 버전 관리 시스템이며 저장소를 복제할 때 변경사항의 기록들(commit)을 함께 복제해온다는 특징이 있다.

3. git과 Github는 어떻게 다른가요?

git은 버전관리 툴, github은 git을 이용한 서비스라고 생각하면 될 것 같다. Github에서 제공하는 서비스를 활용하여 여러사람들이 하나의 저장소를 가지고 보다 쉽게 협업할 수 있다.

4. git의 clone/add/commit/push/pull/branch/stash 명령은 무엇이고 어떨 때 이용하나요? 그리고 어떻게 사용하나요?

  1. git clone: 원격 저장소의 데이터를 카피해오는 행위이며 이 행위를 clone이라고 한다.

    1
    2
    
    $ git clone https://github.com/j1mmyson/repoName.git
    # Clones a repository to your computer
    

    clone 뒤에 따라오는 url은 깃허브의 해당 저장소에서 확인할 수 있다.

  2. git add: commit을 하기전에 변경된 사항들을 추가해나가는 행위. commit을 하게되면 staging area에 있는 변경사항들에 대해서 기록을 남기게 되는데 이때 git add 명령어를 통해 staging area에 변경사항들을 올릴 수 있다.

    1
    2
    3
    4
    5
    6
    7
    
    $ git add filename
       
    # 작업 디렉토리 전체에서 변경된 사항들을 스테이징 에리어에 올려줌.
    $ git add -A 
       
    # 현재 디렉토리 하위에 있는 변경사항들만 스테이징 에리어에 올려줌.
    $ git add . 
    
  3. git commit: 로컬 저장소에 staged된 변경사항들에 대하여 변경을 확정짓고 기록을 하는 행위. git commit을 통해 변경된 내용들에 대하여 새롭게 기록을 남긴다. 일종의 flag를 남긴다고 생각하면 될 것 같고 나중에 commit된 기록들 중 데이터를 백업하거나 해당 commit의 변경사항을 보거나 할 수 있다. git에서 사용하는 가장 기본적인 원자 데이터 단위이다.

    1
    
    $ git commit -m "commit message"
    
  4. git push: 로컬 저장소에 남긴 기록들의 히스토리를 원격 저장소에 적용하는 행위 commit을 통해 내 로컬 저장소에 남은 기록들을 원격 저장소에 보내는 행위이다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    $ git push <저장소명> <브랜치명>
    $ git push origin master
       
    # <저장소명>은 아래 명령어로 확인할 수 있다.
    $ git remote
       
    # -u 옵션은 최초 한번만 저장소명, 브랜치명을 입력하고 이후에는 git push만 사용해도 되게 해준다.
    $ git push -u origin master
       
    # 가급적 사용하지 말것, 지양해야 할 행위
    # -f 옵션으로 강제로 현재 로컬 저장소의 변경사항을 원격 저장소에 덮어씌우는 행위
    $ git push -f origin master
    
  5. git pull: 원격저장소의 변경사항들을 로컬 저장소로 가져와 merge하는 행위 pull = (변경사항을 가져오는 fetch) + (가져온 변경사항을 적용하는 merge)

    1
    2
    3
    4
    5
    6
    
    $ git pull
       
    # pull은 아래 두가지로 쪼개질 수 있음
    $ git fetch
    $ git diff HEAD origin master # 이거는 fetch해서 가져온 변경사항과 현재 내 저장소를 비교해주는 명령어
    $ git merge
    
  6. git branch: 깃에서는 작업 트리를 관리할 수 있는데 이 작업트리를 다룰 수 있는 명령어이다. Git Branch 기초

    1
    2
    3
    4
    
    $ git branch # 브랜치 목록을 불러온다.
    $ git branch <branch_name> # 이름이 branch_name인 브랜치를 생성한다.
       
    $ git checkout <branch_name> # branch_name 브랜치로 작업공간을 전환해준다.
    
  7. git stash: 현재 작업중인 변경사항을 임시 공간에 저장해두기 위한 명령어 현재 브랜치에서 발생한 변경사항들을 커밋해주지 않으면 브랜치 변경이 불가능한데 현재 변경사항을 커밋하고 싶진 않지만 브랜치는 변경하고 싶을 때 stash명령어를 통해 풀어나갈 수 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    
    $ git stash 
       
    $ git stash list # stashed된 변경사항들의 목록을 불러온다.
    $ git stash apply <stash_name> # stash_name stash를 불러온다. stash_name이 없다면 가장 최근의 stash를 불러온다.
       
    $ git stash drop <name> # name의 stash를 제거한다. name이 주어지지 않으면 가장 최근의 stash를 제거한다.
       
    $ git stash pop # apply와 동시에 drop을 해주는 명령어
    

5. git의 Object, Commit, Head, Branch, Tag는 어떤 개념일까요? git 시스템은 히스토리를 어떻게 저장할까요?

git이 파일들을 관리하기 위해 파일을 만드는데 이를 Object라고 부르며 tree, blob, commit, tag 4가지로 이루어져있다. commit의 SHA-1 값중 앞 두자리를 폴더명으로, 뒷 38자리를 파일명으로 갖는다.

1
2
3
4
5
6
ls .git/objects/

01  0f  1b  1c  32  34  48  49  4a  4d  4e  58  7a  7d  7e  84  90  9e  a2  ae  b6  b9  c2  ce  d1  d4  info  pack

ls .git/objects/01/
a03d6611d865f42d50e6b148ae6293bcb0756d

여기서 commit object은 tree SHA-1값, parent 오브젝트의 SHA-1값, author, committer, commit message를 저장한다.
Head는 커밋을 가르키는 포인터와 같은 역할을 하며 Branch는 작업 트리를 나타내고, Tag는 특정 커밋에 태그를 달아주는 역할을 한다.

6. 리모트 git 저장소에 원하지 않는 파일이 올라갔을 때 이를 되돌리려면 어떻게 해야 할까요?

원격 저장소에 커밋을 잘못 기록했을 때 되돌리는 방법은 크게 두가지가 있다. 첫번째는 git reset을 사용해 커밋을 취소하는 방식, 두번째는 git revert를 사용하여 커밋 내용을 되돌리는 방식이다.

git reset을 사용하여 커밋 취소하기

먼저 아래 명령어로 커밋 기록을 불러온다.

1
$ git log --oneline
1
2
3
4
5
6
7
8
9
10
11
12
13
1ec0471 (HEAD -> byungwook, origin/byungwook) dummy 2
cdab146 dummy 1
01a03d6 test stash
4dd0635 byungwook branch
3227c4e (origin/master, origin/HEAD, master) fetch and merge
b92b1bf Create fetchtest.txt
aed7c04 add text file
5115cb1 Quest 19B
01a6919 Quest 18B
11517cd Quest19F : Small fix
7763653 Quest 17-B
749da4a Quest 16-B
7277533 Quest 20

그럼 위처럼 commit id와 함께 커밋 메시지를 불러올 수 있다. 이제 내가 돌아가고 싶은 커밋을 정하고 git reset --hard <commit_id>명령어로 해당 커밋으로 돌아간다. 나는 dummy1, dummy2 커밋을 푸시하기 전인 test stash 커밋때로 돌아가고 싶다고 가정해보자.

1
$ git reset --hard 01a03d6

위 명령어를 실행한 후 다시 git log를 실행시켜보면 HEAD가 test stash커밋을 가르키고 있는걸 확인할 수 있다.

1
$ git log --oneline
1
2
3
4
5
6
7
8
9
10
01a03d6 (HEAD -> byungwook) test stash
4dd0635 byungwook branch
3227c4e (origin/master, origin/HEAD, master) fetch and merge
b92b1bf Create fetchtest.txt
aed7c04 add text file
5115cb1 Quest 19B
01a6919 Quest 18B
11517cd Quest19F : Small fix
7763653 Quest 17-B
749da4a Quest 16-B

이 상태에서 원격 저장소로 푸시를 해주어 커밋을 되돌릴 수 있는데 이때 그냥 푸시해버리면 에러가 발생한다. 현재 로컬에서의 커밋 기록이 원격 저장소의 커밋 기록보다 뒤쳐지기 때문에 발생하는 에러인데 이때 -f 옵션으로 강제로 푸시를 해주어야한다.

1
$ git push -f origin <branch_name>

강제로 푸시를 밀어넣는 방법으로 이미 원격저장소에 올라간 커밋을 삭제하는 방법이기 때문에 협업하는 상황에서 쓰기 좋은 방법은 아니다. 다른 사람이 작업하고 있을 때 이런식으로 커밋기록을 바꾸어 버리면 커밋기록을 바꾸기 전 저장소를 clone해간 사람들이 푸시할 때 충돌에러가 날 수 있기 때문이다. 다음 방법은 커밋 기록을 되돌렸다는 것을 남겨주는 방식인데 뭔지 한번 알아보자.

Revert 로 커밋 내용 되돌리기

revert 명령어를 사용하는 방식은 커밋기록을 삭제하는 것이 아닌 “커밋의 변경사항을 되돌린다”는 커밋을 만들어 주는 방식이다.

1
$ git log --oneline
1
2
3
74a9df1 (HEAD -> byungwook) commit C
458ab3b commit B
26acfd8 commit A

커밋을 revert 시키려면 해당 커밋의 해시값을 revert명령어의 뒤에 붙여주면 된다.

1
$ git revert 74a9df1

명령을 실행하고 파일을 확인해보면 revert시킨 커밋의 변경사항이 폐지되었음을 확인할 수 있을 것이다.
또 여러개의 커밋을 한번에 revert시키려면 revert명령을 여러번 수행하면서 커밋을 하나하나씩 되돌려도 되지만 그렇게 되면 한번의 revert명령마다 하나의 커밋이 추가되므로 쓸데없이 많은 커밋이 생겨버린다. 그래서 --nono-commit 옵션을 사용해 커밋을 남기지 않고 revert를 쌓을 수 있다. 또 HEAD~n..을 붙여주어 한번에 여러개의 커밋에 대해 revert를 실행시킬 수 있다.

최근에 푸시한 3개의 커밋에 대해 revert를 해주고 싶다면 아래와 같이 원하는 목적을 달성할 수 있다.

1
$ git revert --no-commit HEAD~3..

--no-commit옵션을 사용하면 반드시 따로 커밋을 해주어야 한다.

1
2
$ git commit -m "revert recent 3 commits"
$ git push

이제 푸시까지 해주고 원격 저장소를 확인해보면 revert했다는 커밋이 남아있음과 동시에 되돌리고 싶었던 커밋이 되돌려 진 것을 확인할 수 있다.

This post is licensed under CC BY 4.0 by the author.

[vuejs/golang] When the syntax of golang template and vue.js overlaps

Data Structure with Golang