프로그래밍 공부를 시작하면서 지겹게 들어왔던 git. 대충 내 코드를 관리하기 위해서는 git을 사용한다는 사실만 알고 있었는데 도대체 git은 뭘까? 왜 쓰는 걸까? 에 대해서 정리해보려고 한다.
git은 파일을 관리하는 관리자라고 말할 수 있다. 우리가 프로젝트 하나를 만들기 위해 코드를 작성하다 보면 코드가 한 번에 완벽하게 작성될 수 없다는 사실을 깨닫게 된다. 마치 리포트를 제출하기 전 파일명이 최종, 진짜최종, 진짜마지막최종, 진짜진짜마지막최종, … 을 반복하게 되는 것처럼 코드는 버전 업데이트를 위해서든 에러 수정을 위해서든 계속 해서 변화하게 된다.
이 과정에서 우리는 진짜진짜마지막최종으로 저장했던 파일이 맘에 안 들어서 그 전에 저장했던 진짜마지막최종 버전으로 다시 돌아가 새로운 진짜진짜마지막최종2버전을 만들기도 하는데 그러면 우리는 하나의 프로젝트를 작업하는데도 수많은 버전의 파일을 갖고 관리하게 된다.
이런 번거로움을 해결하고자 수많은 소스 코드를 버전별로 효율적으로 관리하기 위해서 git이 만들어졌다.
git이 제공하는 기능은 크게 버전 관리, 백업, 협업으로 나눌 수 있다.
위에 예시를 들었던 것처럼 원래 내용도 남겨두고 수정한 내용을 저장하기 위해서 보통 파일 이름을 변경해가면서 저장하게 된다. 실제로 프로그램을 만들 때 수정된 파일을 계속 새로운 이름으로 저장해서 관리한다면 언제 어떤 내용을 수정한 파일인지 구분하기 힘들어진다.
그래서 사용자 대신에 git이 언제, 어떤 것을 변경했는지 관리해준다. 즉, 해당 소스 코드의 버전을 구분해준다는 것이다.
내 컴퓨터에서 프로젝트를 생성해서 코드를 작성하고 잘 저장해두었다고 한들 이 코드가 언제나 안전하게 보장된다고 확신할 수 없다. 외장하드, 드라이브 등에 따로 백업해두지 않았다면 어느 날 갑자기 컴퓨터가 고장 났을 때 나는 내가 작성했던 코드를 전체를 잃게 되는 것이다.
이럴 때 git 파일로 저장된 자료를 온라인 저장소에 백업하기 위해 제공되는 서비스가 바로 github인 것이다. git은 버전을 관리하는 것, github는 내 컴퓨터 외에 백업을 할 수 있는 원격 저장소 서비스이다.
github
는 온라인 상에 존재하는 저장소 서비스로 해당 저장소에 접근할 수 있으면 여러 사람이 함께 코드를 가져가 작업할 수 있다. 내 팀원 A가 소스 코드를 저장소에서 다운 받아 작업을 하고 오류를 수정한 코드를 github에 백업하면 내가 오류가 수정된 버전의 파일을 다운 받아 기능 업그레이드를 해서 파일을 다시 백업하는 식으로 여럿이 작업할 때 보다 편리하게 파일을 주고 받을 수 있게 된다.
스테이지(stage)
는 버전으로 만들 파일이 대기하는 곳이다. 파일을 여러 개 수정했더라도 내가 버전을 만들고 싶은 파일만 선택해서 스테이지로 넘길 수 있다. 이렇게 스테이지에 파일을 넘겨서 git에게 버전을 만들 준비를 하라고 알려주는 것을 ‘staging’ 혹은 ‘스테이지에 올린다’ 라고 표현한다.
저장소라고 불리는 리포지토리는 스테이지에서 대기하고 있던 파일들을 버전으로 만들어서 저장하는 공간이다. 작업한 파일을 내 컴퓨터에서 버전을 만들어 저장하는 공간을 LocalRepository
라고 하고 github같은 서비스에 버전을 업로드 해서 저장하는 공간을 RemoteRepository
라고 한다.
staging
된 파일을 가지고 git에서 버전을 만들어 repository
에 저장하는 것을 커밋이라고 말한다. 커밋을 하는 경우에는 현재 저장하는 버전에 어떤 변경 사항이 있었는지 확인하는 메시지를 같이 기록해줘야한다.
commit
이 버전의 기준이 되기 때문에 커밋한 단위로 버전을 구분해서 확인할 수 있게 된다. 커밋하기 전에는 하나의 버전으로 구분하지 않는다.
git에서 관리하는 파일이 변경되었는지 확인하고 변경된 경우 modified
라고 표시한다. git이 파일의 수정 여부를 계속 추적하고 구분하는 뜻으로 이런 파일들을 tracked 파일
이라고 한다.
git에서 버전을 만들 때는 git에서 관리하는 파일의 정보를 전부 확인하게 되는데(tracked 파일) untracked 파일
들은 git이 버전을 관리하지 않기 때문에 수정 내역을 추적하지 않는다.
버전이 관리 되는 중인 파일 안에서 untracked 파일들처럼 버전 관리를 하지 않을 특정 파일이 존재한다면 .gitignore 파일
을 만들어서 버전 관리에서 제외시킬 목록을 지정할 수 있다.
보통 이클립스 같은 프로그램을 사용할 때 프로그램 저장과 동시에 컴파일 되면서 실행되는 bin폴더나 보안상의 문제로 공유하면 안 될 파일들을 지정한다.
local repository(지역 저장소)에서 remote repository(원격 저장소)로 파일을 보내는 것을 pull
이라고 말한다. pull을 실행하기 전에는 커밋이 이루어져야 한다.
push
는 반대로 원격 저장소에서 지역 저장소로 파일을 내려받는 것을 말한다. 내 컴퓨터에서 작업했던 파일을 원격 저장소에 push 해서 백업하고 다른 장소에서 내려받아서 사용하거나 협업 중 내 컴퓨터에 있는 파일의 버전과 원격 저장소에 있는 파일의 버전이 다를 때 pull로 파일을 받아와서 사용한다.
나뭇가지라는 뜻 그대로 여러 갈래로 뻗어나가듯이 갈라지는 코드 버전의 흐름을 가르킨다. branch
는 개별적인 작업대 같은 느낌이다. 해당 작업대에서 사용한 결과들이 옆 작업대에 영향을 미치지 않는다.
협업 중에 내가 버전을 만들 때마다 팀원들의 코드에도 영향을 주게 된다. 하나의 원격 저장소에서 커밋한 파일들을 가져와서 사용하게 되기 때문이다.
이 때 하나의 디폴트 브랜치를 두고 각 팀원들의 브랜치를 따로 만들어 영향 받지 않는 작업을 진행할 수 있게 해줄 수 있다. 이렇게 각자 영향 받지 않게 개별된 브랜치로 작업을 했을 때 브랜치별로 커밋하면서 버전에 대한 정보를 기록해두기 때문에 문제가 발생했을 때 해당 원인을 찾아내기도 쉬워진다.
이해 참고용 사진…
기능B를 만드는 브랜치를 따로 생성하면 해당 브랜치를 만든 시점을 기준으로 디폴트 브랜치에서 생성했던 코드들의 사본을 만드는 것이라고 생각할 수 있다. 이전에 만들어진 디폴트 브랜치의 파일을 가지고 기능B를 구현해서 완성됐다면 해당 브랜치를 디폴트 브랜치에 병합한다.
💡브랜치를 병합하는 것을 merge라고 한다.
기능A를 구현하고 실행하던 도중 오류를 발생했다면 오류 해결 위해 오류난 코드를 아예 없애서 새로운 기능을 구현해볼 수 있고, 오류난 코드를 수정해서 코드를 작성할 수도 있다.
이런 경우 브랜치를 다시 한 번 분리시킬 수 있다. 기능A 브랜치에서는 오류난 코드를 아예 삭제하고 기능을 구현하고 기능A오류수정 브랜치에서는 해당 오류 코드를 가지고 수정을 해보는 것이다. 기능을 구현하던 중 오류 수정보다는 아예 새로운 기능을 구현한 게 더 적합하다고 판단됐을 때 기능A오류수정 브랜치는 버릴 수 있다.
참고한 서적 : Do it! 지옥에서 온 문서 관리자 깃&깃허브 입문