/ GIT

Git과 GitHub의 간단 사용법

Introduction

GitGitHub에 대한 간단한 설명입니다. 간단한 이론과 함께 실습을 통해 command 기반의 명령어로 어떤일을 처리할 수 있는지를 알아보도록 하겠습니다.


누구나 한번쯤은 겪었던 일

need-of-vcs

위의 그림은 누구나 한번쯤 겪어봤을 만한 상황입니다. 파일을 계속 수정해 나가면서 이름을 바꾸어 저장하는 경우입니다. 그 당시야 최종 파일이 어떤것인지 알 수 있겠지만 시간이 흐르면 당연히 저 중 어떤 파일이 최종 Report파일인지 알 수 없게 됩니다.

아래의 그림은 조금 다른 경우입니다.

vcs-conflict

( 이미지 출처 : http://slidedeck.io/cursor-education )

여러명이 공동으로 같은 파일을 작업할 때 파일 내용을 덮어쓰는 문제가 생길 수 있습니다. 다른 사람이 작업한 사항을 유실할 수 있다는 것이죠.

이와 같은 문제가 항시 빈번하게 발생하게되고 이를 해결하기 위해 나온 시스템이 바로 VCS( Version Control System ) 입니다.


Version Control System ( VCS )

VCS 는 파일의 변화를 시간에 따라 기록했다가 나중에 특정 시점의 버전을 다시 꺼내올 수 있는 시스템을 의미합니다. 이런 VCS는 다음과 같은 특징을 가지고 있습니다.

  • 각 파일을 이전 상태로 되돌릴 수 있습니다.
  • 시간에 따라 수정 내용을 비교해 볼 수 있습니다.
  • 누가 문제를 일으켰는지 쉽게 추적할 수 있습니다.
  • 파일을 잘못 고쳤을 때 쉽게 복구할 수 있습니다.

Centralized Version Control System ( CVCS )

CVCS는 중앙집중식 버전 관리 시스템입니다. 우리가 예전에 사용했던 CVSSubversion같은 제품이 이 범주에 들어갑니다.

파일을 관리하는 서버가 별도록 존재하고 클라이언트는 중앙 서버에서 파일을 받아서 사용하는 개념입니다. 그림으로 표현하면 다음과 같습니다.

centralized-version-control-system

( 이미지 출처 : https://git-scm.com/ )

여기서 Checkout이라는 용어가 나오는데 나중에 우리가 살펴볼 Git의 Checkout과는 다른 개념임에 유의하셔야 합니다.

이런 CVCS는 중앙서버에 문제가 발생하면 다른 사람과의 협업 자체가 불가능해지게 됩니다. 또한 중앙서버의 하드디스크에 문제가 발생하면 프로젝트의 모든 History를 잃어버리게 됩니다.

Backup서버를 운영하면 이런 문제점을 일시 해결할 순 있지만 본질적인 문제는 남아있게 됩니다. ( 백업서버까지 날라간다면??? )

이런 문제점을 해결하기 위해 분산형 VCS가 등장하게 됩니다.


Distributed Version Control System ( DVCS )

DVCS는 분산 버전 관리 시스템입니다. 우리가 알고 있는 Git이 대표적 제품입니다. 이 외에 다른 제품들도 있지만 Git만 알아도 됩니다.

이 방식은 CVCS처럼 클라이언트가 파일의 마지막 Snapshot을 Checkout하는 방식이 아닙니다. 클라이언트는 서버 저장소를 통째로 로컬에 복제해서 사용합니다. 즉, 그림으로 보면 다음과 같습니다.

distributed-version-control-system

( 이미지 출처 : https://git-scm.com/ )

Git의 탄생

Linux kernel은 대규모의 open source project입니다. 이 project의 버전관리를 위해 초기에는 BitKeeper라는 상용 DVCS를 사용했었는데 2005년도에 이 BitKeeper의 무료사용이 제고되면서 리누스 토발즈의 주도로 Linux 개발 커뮤니티가 자체 VCS를 개발했는데 이게 바로 Git입니다.

Git은 다음과 같은 특징을 가집니다.

  • 단순한 구조에서 오는 빠른 속도
  • 완벽한 분산처리
  • branch를 사용한 비선형적 개발 가능
  • 속도나 크기면에서 대형 Project에 적합

Git의 데이터 저장 방식은 이 포스트의 범주를 넘어가니 그 부분은 제외하겠습니다. 실제 Git이 어떤 방식으로 데이터를 저장하는가에 대한 내용은 여기를 클릭해 살펴보시면 될 듯 합니다.


Git의 기본

Git은 파일을 3가지 상태로 관리합니다. Committed, Modified, Staged라고 불리는 3가지 상태로 파일을 관리하게 되는데 각각의 의미는 다음과 같습니다.

Git의 파일 상태

  • Committed : 파일을 수정한 후 해당 파일에 대해 commit명령을 실행해 파일을 로컬 데이터베이스(로컬 Repository)에 안전하게 저장한 상태를 의미합니다.
  • Modified : 파일을 수정한 후 아직 로컬 데이터베이스에 commit하지 않은 상태를 의미합니다.
  • Staged : 파일을 수정한 후 수정할 파일을 곧 commit할 것이라고 표시한 상태를 의미합니다.

Git은 파일상태 관리와 더불어 3가지 영역을 사용합니다.

Git의 사용 영역

  • Git directory : Git이 project의 메타데이터와 객체 데이터베이스를 저장하는 곳을 의미합니다. 다른말로 Local Repository라고 하며 만약 특정 폴더를 Git directory(Local Repository)로 설정하려면 git init명령을 이용하면 됩니다. Repository로 설정되면 .git이라는 숨김폴더가 생성되고 이 안에 Git 관리 정보들이 생성되게 됩니다.
  • Working directory : project의 특정 branch를 checkout한 내용이 들어있는 폴더입니다.
  • Staging Area : Git directory에 존재하며 단순한 파일입니다. 곧 commit할 파일에 대한 정보를 가지고 있게 됩니다.

Git으로 하는 작업의 기본 순서

작업의 기본순서는 다음과 같습니다.

  • Working directory에서 파일 수정
  • Staging Area에 수정한 파일을 Stage해서 commit할 Snapshot 생성 ( git add )
  • Staging Area에 있는 수정된 파일을 commit해서 Git directory에 영구적인 Snapshot으로 저장 ( git commit )

git-local-operation

( 이미지 출처 : https://git-scm.com/ )

git-local-operation-another

( 이미지 출처 : http://egloos.zum.com/incredible/v/7278471 )

Git 설치 & 기본 설정

http://git-scm.com를 클릭해서 Git Official HomePage로 이동해서 Git을 다운로드 한 후 기본설정으로 install하시면 됩니다.

Git을 설치하신 후 git config를 이용해 기본적인 환경설정을 하시면 됩니다. 설정파일은 크게 3가지 종류가 존재하는데 다음과 같습니다.

Git의 환경설정파일( Windows system 기준 )

  • $GIT_HOME/mingw64/etc/gitconfig : 시스템의 모든 사용자와 모든 저장소에 적용되는 설정으로 git config --system으로 설정합니다.
  • $USER_HOME/.gitconfig : 특정 사용자에게만 적용되는 설정입니다. git config --global으로 설정합니다.
  • .git/config : Git directory안에 위치하며 특정 저장소에만 적용되는 설정입니다.

각각의 설정파일은 위에 나열된 순서의 역순으로 적용된다는 것도 같이 기억해 두셔야 합니다.

Windows system에서 Git을 설치하면 Git Bash 메뉴가 생성되는데 이를 실행해 console을 실행시킨 후 사용자 이름과 Email주소를 설정하시면 됩니다.

git-config-user

참고로 MINGW64는 Windows system으로 porting한 GNU 소프트웨어 도구 모음입니다.


Git Local Repository 생성

그럼 Git을 이용해 Git Repository를 만들어서 사용해 보도록 하겠습니다. 가지고 있는 project가 없기 때문에 간단하게 폴더를 하나 생성하고 그 폴더를 project 폴더로 간주하고 진행하겠습니다.

Git의 기본 명령과 개념을 이해하는 목적이기 때문에 command 창에서 명령어를 이용해서 작업을 진행하겠습니다. 추후에 실제 project에 적용하실 때는 IDE의 기능을 이용하거나 SourceTree와같은 GUI툴을 이용하시는게 좋습니다.

다음과 같은 순서로 진행합니다.

  • 윈도우 탐색기를 이용해 먼저 프로젝트 폴더를 생성합니다. D:/MyProject로 생성합니다. 나중에 Git으로 관리할 파일을 하나 생성합니다. 다음과 같은 내용을 가지고 있는 파일을 생성하고 파일 이름은 readme.txt로 저장합니다.
    This is a sample text.
    
  • project 폴더로 이동해 console을 통해 git init을 실행해 Git Repository를 생성합니다. 다음과 같은 메시지가 출력되는걸 확인하실 수 있습니다.
    Initialized empty Git repository in D:/MyProject/.git/
    
  • 메시지에서 나온것 처럼 .git 폴더가 생성되고 그 안에 Git Repository가 생성됩니다. 또한 Repository에 필요한 각종 Skeleton들도 같이 생성됩니다.

  • 이 상태에서 git status를 실행합니다. 그러면 Git이 아직 추적하고 있지 않은 readme.txt가 존재한다고 알려줍니다. git-status

  • Git Repository를 생성했지만 아직 어떠한 파일도 관리를 하고 있지 않습니다. 이제 Git이 파일을 관리하게 하려면 Repository에 git add를 이용해 파일을 추가하고 git commit을 이용해 commit까지 진행해야 합니다. 다음의 그림처럼 명령을 이용하여 Repository에 파일 추가, 확인, commit까지 진행합니다. ( -m option은 commit message를 작성하기 위해서 사용합니다. ) git-commit

  • 이제 마지막으로 readme.txt 파일의 내용을 에디터를 이용해 적당히 수정한 후에 다시 git status를 실행시켜 보시면 됩니다. 그럼 Git은 해당 파일이 변경(Modified)됬다는 것을 인식해서 보여주게 됩니다. 변경된 내용을 적용해 Repository에 저장하려면 다시 git add를 이용해 해당 파일을 staging 한 후 git commit을 실행해야 합니다. git-modify-commit

Branch 생성

그 다음에 알아볼 내용은 branch 입니다. branch는 기본 project에 영향이 가지 않는 상태에서 새로운 기능을 추가하거나 기존 기능을 변경해야 하는 경우에 유용하게 사용할 수 있습니다. 필요에 의해 만들어지는 이런 각각의 branch들은 서로간의 영향을 받지 않습니다. 그렇기 때문에 여러 작업을 동시에 진행시킬 수 있습니다.

git-branches

( 이미지 출처 : https://rogerdudler.github.io/git-guide/index.ko.html )

Repository를 처음 생성하게 되면 Git는 master라는 이름의 branch를 만들어 줍니다. 위에서 우리가 readme.txt 파일을 Repository에 추가하고 내용을 변경해서 commit까지 진행했었는데 모두 이 master라는 branch에서 처리했던 겁니다.

master가 아닌 다른 branch를 생성할 수 있습니다. 또한 “이제부터의 작업은 xxx branch에서 진행할꺼야!” 라는 식으로 명령을 줄 수 있는데 이걸 checkout이라고 합니다. 즉, checkout은 특정 branch의 내용을 가져와서 Working directory를 설정하는 작업이라고 보시면 됩니다. 특정 branch에서 일어나지 않는 모든 작업은 당연히 master branch에서 일어나게 됩니다.

현재 어떤 branch가 존재하는지 알아볼려면 git branch 명령을 이용하시면 됩니다. 만약 새로운 branch를 생성하고 싶으면 git branch branch_name형태로 branch이름을 명시하시면 새로운 branch가 생성됩니다.

현재 작업중인 branch는 * 기호로 표시됩니다. 아래 그림은 새로운 branch를 생성하고 git checkout 명령을 이용하여 hotfix branch를 Working directory에 가져온 것입니다. 지금부터 하는 작업은 모두 hotfix branch에서 발생하는 것이고 master branch와는 무관하게 동작합니다.

git-branches-hotfix

실제로 파일을 변경하거나 추가해서 hotfix branch에서 작업한 후 다시 master branch를 checkout해보시면 아까 했던 작업이 master branch에는 영향을 미치지 않는다는 것을 확인하실 수 있습니다. 이 부분은 개별적으로 실습해 보시길 바랍니다.

참고로 모든 branch를 확인하기 위해서는 다음의 명령을 실행하시면 됩니다.

git branch -a


Branch Merge

Merge 작업은 현재 작업중인 branch에 다른 branch를 가져와서 병합하는 작업을 의미합니다. git merge branch_name을 이용하여 현재 branch에 명시된 이름의 branch를 가져와 파일을 병합하게 됩니다.

만약 두개의 branch에서 같은 파일의 같은 곳을 수정했을 경우 해당 파일을 병합할 때 당연히 문제가 발생하게 됩니다. 그냥 합쳐질 수가 없기 때문이지요. conflict가 발생했다고 표현합니다. 이런 경우 충돌이 일어난 내용을 살펴보고 수동으로 해결해야 합니다.

Git은 병합이 실패했을 때 그 해결을 모두 사용자에게 일임합니다.

그래서 수동으로 파일을 수정한 후 다시 commit작업을 진행해야 합니다. merge 작업은 Remote Repository 를 설명하는 부분에서 다시 한번 다뤄보기로 하겠습니다.


.gitignore 파일

project 폴더 안에서 굳이 추적할 필요가 없는 파일들도 존재합니다. 입출력 데이터파일이나 로그파일, 혹은 .class와 같은 파일들은 굳이 Git을 이용해서 관리할 필요가 없습니다. 즉, 임시로 사용되거나 결과물로 생성되는 파일들이 이 범주에 들어갑니다.

이런경우 .gitignore 파일을 이용해 추적 관리할 필요가 없는 파일을 배제시킬 수 있습니다. 그냥 만들어도 되지만 여기로 이동해 보시면 조금 쉽게 .gitignore 파일의 내용을 만들어 복사해서 사용하실 수 있습니다.

gitignore-io


Remote Repository

Git은 혼자 사용할 수 도 있지만 기본적으로 다른 사람과 협업을 하기 위한 도구입니다. 협업 도구로서 Git의 가장 큰 유용함은 Remote Repository(원격 저장소)에 있습니다.

이 Remote Repository는 우리가 따로 구축해서 사용할 수 있습니다. 또한 이런 Remote Repository를 서비스하는 회사도 굉장히 많이 있습니다. Git 기반의 Remote Repository 중 가장 대표적인 것이 바로 GitHub입니다.

Remote Repository를 쉽게 생각하자면 로컬에서 작업한 Git Local Repository가 외부에 있는거라고 생각하시면 됩니다. GitHub는 이런 Remote Repository를 전세계적으로 서비스하고 있고 굉장히 많은 사람들이 GitHub를 자신들이 수행하고 있는 project의 Remote Repository로 이용하고 있습니다.

GitHub에 있는 이런 Remote Repository는 크게 public repositoryprivate repository로 구분됩니다. 말 그대로 public repository는 아무나 파일들을 열람할 수 있도록 공개되어 있는 repository이고 private repository는 권한을 가진 사람들만 사용할 수 있는 repository입니다.

GitHub는 ForkPull Request라는 기능을 제공하고 있습니다. 정확히 말하자면 이 Fork와 Pull Request는 Git이 제공하는 것이 아니라 GitHub가 제공하는 서비스 입니다.

  • Fork : 다른 사람의 Repository를 통째로 내 GitHub 계정으로 복사해 오는 기능입니다. 즉, GitHub 계정간 Repository를 서로 복사해 갈 수 있는 기능이라고 보시면 됩니다.

  • Pull Request : 다른 사람의 Repository를 Fork한 후 그 내용을 수정한 다음 원본 Repository에 수정된 내용을 보내 병합을 요청할 수 있는데 이 작업을 Pull Request라고 합니다. 아무나 Repository를 수정할 수 있는 권한을 주게 되면 Repository는 금방 엉망이 될 테니 READ기능(Fork)만 제공하고 병합시에는 요청을 받아서 처리하도록 합니다.


GitHub에 Remote Repository 생성

그럼 이제 GitHub에 계정을 생성하고 Remote Repository를 생성해 사용하는 방법에 대해서 알아보겠습니다.

GitHub에 계정을 생성하고 새로운 Repository를 생성하는 버튼을 클릭하면 다음과 같은 화면을 보실 수 있습니다. Repository이름을 입력하고 간단한 설명을 입력합니다. Repository의 종류를 선택할 수 있는데 private은 비용을 지불해야 사용할 수 있습니다. 우리는 아까 만들어 놓은 Local Repository와 연결시키는 목적으로 사용할 것이기 때문에 README 파일을 만들지 않고 Repository를 생성합니다.

github-repository-create

Repostiroy를 생성하면 다음과 같은 화면을 보실 수 있습니다. Repository에 현재 파일이 존재하지 않기 때문에 이렇게 나오는 것이고 만약 특정 파일들이 저장되어 있으면 파일의 목록들이 보여지게 됩니다.

github-repository-create-result


Remote Repository 관리 명령어

GitHub에 생성한 Remote Repository를 관리하기 위해서 Git은 몇몇개의 명령어를 제공합니다.

  • git clone : Remote Repository의 모든 내용을 Local Repository로 복사합니다.
  • git remote : Local Repository를 특정 Remote Repository와 연결시킬 때 사용합니다.
  • git push : Local Repository에 추가된 파일이나 변경 사항을 연결된 Remote Repository에 저장하기 위해서 사용합니다.
  • get fetch : Remote Repository와 Local Repository의 변경 사항이 다를 때 이를 비교 대조해서 충돌을 해결하고 최신 데이터를 반영하기 위해서 사용합니다.
  • git pull : 연결된 Remote Repository의 최신 내용을 Local Repository로 가져오면서 merge합니다. git push와 반대의 개념이라고 보시면 되지만 merge할 때 문제가 발생했을 때 추적이 어렵습니다. 따라서 git pull을 이용하는 것 보다는 일단 git fetch로 변경사항을 받고 이를 확인해서 코드를 수정한 후 Local Repository에 commit한 다음 git push로 최종 변경 사항을 Remote Repository에 반영하는게 더 좋은 방법입니다.

git clone

git clone은 Remote Repository에 있는 project를 내 컴퓨터로 가져올 때 사용합니다. 즉, GitHub에서 Local 환경으로 복사하는 작업입니다. 위에서 생성했던 MyProjectRemote란 GitHub Remote Repository를 Local로 clone해 보도록 하겠습니다.

  • 먼저 Remote Repository의 주소를 복사합니다. git-remote-repository-url

  • 로컬 컴퓨터에서 프로젝트를 저장할 폴더를 생성한 후 git clone을 이용해 저장소를 복사합니다. D:/GitHub 폴더를 생성한 후 이 폴더 안에서 다음의 명령을 실행시킵니다.

git clone https://github.com/moon9342/MyProjectRemote.git

github-repository-clone

정상적으로 clone이 진행되면 저장소 이름으로 폴더가 하나 생성되는것을 볼 수 있습니다. 당연히 이 폴더는 Remote Repository와 연결되어 있는 Local Repository가 됩니다.

이해를 돕기 위해 순차적으로 생각해보면 다음과 같이 project가 진행될 수 있습니다.

  • 협업을 책임지는 사람(PM)이 GitHub에 빈 Remote Repository를 생성합니다.

  • PM은 자신의 Local Repository에 project에 필요한 기본 구조와 여러가지 환경설정 그리고 개발한 필요한 기타 사항들을 만들어서 저장합니다.

  • PM은 project의 뼈대가 담겨있는 이 Local Repository를 GitHub에 생성해 놓은 빈 Remote Repository와 연결합니다. 이때 git remote 명령을 이용하게 됩니다.

  • PM은 자신이 Local Repository에 가지고 있는 내용을 Remote Repository에 push 합니다.

  • 이제 협업하는 사람 모두가 이 Remote Repository를 clone해서 로컬로 복사해 간 다음 자신이 해야 하는 작업을 진행합니다.

위와 같은 식으로 생각하면 git remotegit clone의 차이점을 이해할 수 있습니다.


git remote

GitHub에 빈 Remote Repository를 생성한 후 git remote를 이용하여 Local Repository와 연결할 수 있습니다. 다음과 같은 명령을 이용합니다.

git remote add origin “Remote Repository URL”

연결이 성공했는지를 다음의 명령어를 이용해서 확인해 볼 수 있습니다.

git remote -v


git push

git remote를 이용하여 Local Repository와 Remote Repository가 연결되었으면 이제 자신이 작업한 내용을 Remote Repository에 upload를 할 수 있습니다.

이 때 git push 명령을 이용하면 파일을 upload할 수 있는데 기본적으로 Remote Repository의 master branch에 upload되게 됩니다. 따라서 만약 다른 branch의 내용을 upload하려 하면 다음과 같이 명령을 실행시켜야 합니다.

git push origin “local branch명”

위의 명령에서 origin은 원격 저장소의 별칭입니다. git remote를 이용하여 Remote Repository를 연결할 때 이 origin이라는 별칭을 이용해서 원격 연결을 했었습니다.

만약 origin 저장소에 Local의 모든 branch를 push하려면 다음과 같이 명령을 수행하시면 됩니다.

git push origin --all

git push가 진행될 때 Remote Repository에 같은 이름의 branch가 존재한다면 내용이 변경될 것이고 만약 해당 branch가 존재하지 않는다면 새로운 branch를 Remote Repository에 생성하게 됩니다. 같은 이름의 branch가 존재하지만 내역이 다르다면 당연히 push는 일어나지 않고 작업이 거부됩니다.

간단한 예를 들자면 Local Repository의 master branch의 내용을 Remote Repository에 push하려면 다음과 같이 실행하시면 됩니다.

git push origin master

만약 Local Repository의 hotfix branch의 내용을 Remote Repository에 push하려면 다음과 같이 실행하시면 됩니다.

git push origin hotfix


git fetch & git pull

Remote Repository를 이용하다 보면 다른 누군가가 먼저 commit할 경우가 있습니다. 이런 경우 git은 당연히 파일의 내용이 서로 상이하기 때문에 push를 허용하지 않습니다.

Remote Repository와 Local Repository를 적절히 서로 맞춰야 하며 이럴 때 사용하는 것이 git fetch 입니다. 즉, fetch는 Remote Repository의 commit들을 Local Repository로 가져오는 역할을 하고 사용자는 Local Repository로 가져온 commit들을 자신의 작업과 적절히 병합하여 Remote Repository에 push해야 합니다.

git pull은 Remote Repository의 정보를 가져오면서 자동으로 Local branch에 병합하는 명령어 입니다. 편하게 사용할 수 는 있지만 만약 conflict가 발생하면 내역 확인이 쉽지 않은 단점이 있습니다.


Remote Branch를 Local로 가져오기

만약 Local Repository에 Remote Repository의 branch가 존재하지 않는다면 git pull을 이용한다해도 자동으로 Remote Repository에 있는 branch를 가져오지 못합니다. Remote Repository에 있는 branch를 Local Repository로 가져오실려면 다음과 같이 작업하셔야 합니다.

우선 git remote에 대한 내역을 갱신해야 합니다. 해당 명령을 하지 않을 경우 나중에 branch를 찾지 못한다는 오류가 발생할 수 있기 때문입니다. 다음과 같은 명령을 이용합니다.

git remote update

그 다음은 Remote Repository의 branch내역을 확인해야겠죠. -a option을 이용하면 Remote Repository와 Local Repository의 모든 branch를 확인할 수 있습니다.

git branch -r

이제 Local Repository에 동일 이름의 branch를 생성하면서 Remote Repostiroy의 branch를 가져온 후 해당 branch로 checkout을 해 보죠. 다음과 같이 실행하시면 됩니다.

git checkout -t <Remote_Branch_Name>

만약 Local Repository에 같은 이름의 branch가 아니라 다름이름의 branch를 생성하고 싶을 경우는 아래처럼 -b option을 이용하시면 됩니다.

git checkout -b <Local_Branch_Name> <Remote_Branch_Name>

End.