소스 형상 관리 도구

Git은 파일의 버전을 관리하는 도구이다. Git을 사용하면 마치 게임에서 세이브와 로드를 사용하는 것처럼 프로젝트의 상태를 변경할 수 있으며, 내 프로젝트를 다른 곳으로 복제하거나 다른 사람의 프로젝트를 통째로 옮겨올 수도 있다.

로컬 저장소

Git에서 저장소는 파일의 각 버전이 저장되는 장소이다. 내 컴퓨터에서 프로젝트를 시작하여 버전을 관리하고자 한다면 로컬 저장소를 만들면 된다. 로컬 저장소는 처음부터 새로 만들거나 원격 저장소로부터 복제하여 만들 수 있다. git을 사용하여 버전을 관리하면 프로젝트 폴더에 .git 이라는 숨겨진 폴더가 생성되는데, 이 폴더가 바로 로컬 저장소이다.

원격 저장소

원격 저장소는 기본적으로 다른 사람과 협업하기 위한 저장소이다. 내 로컬 저장소에서 관리하는 파일 버전들을 원격 저장소에 올려두면 다른 사람이 이를 자신의 로컬 저장소에 복제하는 방식으로 협업이 가능해진다. 유명한 원격 저장소로 GitHub, GitLab 등이 있다.

사용 전략

Git은 사용 목적에 따라 다양한 사용 전략이 있다고 한다.

혼자 작업할 때 - commit, revert, branch, merge, checkout, stash, push

  • git commit 명령을 사용하여 수정된 파일들에 대한 스냅샷을 찍으면 수동으로 index_20200605.html 같은 파일을 만들 필요가 없다.
  • git revert 명령을 사용하여 이전 스냅샷으로 되돌아갈 수 있다.
  • git branch 명령을 사용하여 프로젝트의 (가상)사본을 만들어 파일들을 자유롭게 수정해볼 수 있다.
  • git merge 명령을 사용하여 (가상)사본을 프로젝트에 반영할 수 있다.
  • git stash 명령을 사용하여 현재 프로젝트를 임시저장하고 git stash pop 으로 불러올 수 있다.
  • git push 명령을 사용하여 프로젝트를 서버로 업로드할 수 있다.

소규모 팀에서 협업할 때 - clone, push, pull

  • git clone, git push, git pull 명령을 사용하여 서버의 원격저장소를 중심으로 협업할 수 있다.
  • git clone 명령을 사용하여 공동으로 사용하는 원격저장소를 내 컴퓨터로 복제한다.
  • git push 명령을 사용하여 내 컴퓨터의 수정 사항을 원격저장소에 반영한다.
  • git pull 명령을 사용하여 다른 팀원이 반영한 원격저장소의 수정 사항을 내 컴퓨터에 반영한다.

오픈소스 프로젝트에 기여할 때 - fork, pull request

  • 오픈소스 프로젝트를 fork 하여 나만의 프로젝트로 가져와 마음껏 작업한 다음, 수정 사항을 pull request 하여 승인받으면 오픈소스 프로젝트에 반영할 수 있다.

Hook

저장소에 push 등 이벤트가 발생할 때 자동으로 추가 작업을 실행하고 싶을 때 Hook를 활용할 수 있다. 개발PC에서 html 파일을 수정하면 운영서버에 자동으로 동기화되도록 하는 데 Hook를 활용해보겠다. 여기서는 GitHub 대신 운영서버를 원격저장소로 활용한다. 동작 순서는 다음과 같다.

  • 개발pc에서 git push → 원격저장소 hook 발동 → 서버에서 git pull

이 때 사용되는 저장소는 다음과 같다.

  • 로컬저장소(개발PC) → 원격저장소(운영서버) → 로컬저장소(운영서버)

우선 서버에 원격저장소(bare repository)를 생성한다. 여기에는 html 파일은 저장되지 않으며, git 버전 데이터만 저장된다. 이 곳을 기준으로 개발pc와 서버가 동기화될 것이다.

apt install git
mkdir gitrepos
git init --bare gitrepos/test.git
  • 개발pc에 프로젝트 폴더와 로컬저장소(.git)를 생성한다. 여기에는 html 파일이 저장되며, 원격저장소와 동일한 git 버전 데이터가 저장된다. git push로 html 파일의 수정 버전을 원격저장소로 올려보내 동기화한다.
# 새로운 디렉토리에서 시작하려는 경우 원격저장소에서 복제
git clone ssh://myid@mysite:port/~/gitrepos/test.git
# 기존 작업 디렉터리에서 시작하려는 경우 로컬저장소로 만든 후 원격저장소를 지정
git init
git remote add origin ssh://myid@mysite:port/~/gitrepos/test.git
  • 서버에 프로젝트 폴더와 로컬저장소(.git)를 생성한다. 여기에는 html 파일이 저장되며, 원격저장소와 동일한 git 버전 데이터가 저장된다. git pull로 html 파일의 최신 버전을 원격저장소로부터 내려받고, 이를 웹 서버에서 사용한다.
# 새로운 디렉토리에서 시작하려는 경우
git clone gitrepos/test.git
# 기존 작업 디렉토리에서 시작하려는 경우
git init && git add . && git commit -m 'init'
git remote add origin gitrepos/test.git
  • 원격저장소에 Hook를 추가한다. 원격저장소에 push가 발생하면 서버의 로컬저장소로 이동하여 pull 될 것이다. 즉, 개발PC의 html 파일이 서버 원격저장소를 거쳐 서버에 동기화될 것이다.
nano gitrepos/test.git/hooks/post-update
cd <server_local_repo> || exit
unset GIT_DIR
git fetch origin
git pull origin main
exec git update-server-info
  • 개발pc에서 git push 후 서버에서 git pull 이 잘 되었는지 확인한다. 참고로, git remote add 명령을 사용하면 Github Desktop에서도 운영서버로 푸시가 가능하다.

Git Hook은 이러한 용도 외에도 테스트 실행 등 다양한 활용이 가능하다. GitHub Actions도 이와 비슷한 기능을 제공한다.

참고: GIT 기본 명령어

CLI에서 직접 명령어를 입력하여 사용하거나, GUI 프로그램을 사용하는 방법이 있다. GitHub Desktop 같은 GUI를 사용하면 편리하다. 아래는 CLI 기준 자주 사용하는 명령어들이다.

  • 저장소 생성
    • git clone /path/to 또는 git clone user@host:/path/to
    • git init
  • 스테이징
    • git add
    • git add -A
    • git rm
  • 커밋
    • git commit -m “msg”
    • git remote add origin
    • git push origin master
    • git pull
  • 분기
    • git checkout -b
    • git checkout master
    • git branch -d
    • git push origin
  • 병합
    • git merge
    • git diff
  • 태그
    • git tag
    • git log
  • 되돌리기
    • git checkout –
    • git reset –hard orgin/master
    • git gui - Visualize All Branch History - commit 오른클릭 - reset master branch to here

참고: GIT 상황별 명령어

https://backlog.com/git-tutorial 내용을 요약하였다.

  • 기본 조작
    • 저장소를 만들고 싶다 git init
    • 파일과 폴더를 인덱스에 등록하고 싶다 git add <pattern>
    • 인덱스에 추가된 파일을 커밋하고 싶다 git commit
    • 변경된 파일의 목록을 확인하고 싶다 git status
    • 파일의 변경 내용을 확인하고 싶다 git diff
    • 커밋 로그를 보고 싶다 git log
    • 커밋의 상세내용을 확인하고 싶다 git show <commit>
    • 파일과 폴더명을 변경하거나 이동시키고 싶다 git mv <old> <new>
    • 파일을 삭제하고 싶다 git rm <file>
    • 캐시를 삭제하고 싶다 git rm -r --cached .
    • 관리대상이 아닌 파일을 삭제하고 싶다 git clean
    • 변경한 인덱스에 등록되지 않은 파일을 되돌리고 싶다 git checkout -- <file>
    • 인덱스에 등록한 파일을 취소하고 싶다 git reset HEAD -- <file>
    • 이전에 커밋한 적이 있는 파일만을 모두 인덱스에 등록하고 싶다 git add -u
  • 원격 조작
    • 기존의 원격 저장소를 복제하고 싶다 git clone <url>
    • 원격 저장소를 추가하고 싶다 git remote add origin <url>
    • 원격 저장소를 제거하고 싶다 git remote remove origin
    • 원격 저장소 목록을 확인하고 싶다 git remote
    • 원격 저장소 url을 확인하고 싶다 git remote -v
    • 원격 저장소 브랜치로부터 로컬 저장소 브랜치를 만들고 싶다 git checkout <branch> git clone -b <branch> <url>
    • 원격 저장소에 브랜치를 만들거나 변경 내용을 반영하고 싶다 git push <repo> <branch>
    • 원격 저장소의 브랜치 변경 내용을 확인하고 싶다 git fetch <repo> <branch>
    • 원격 저장소 브랜치의 변경 내용을 적용하고 싶다 git pull <repo> <branch>
    • 원격 저장소의 내용과 같아지도록 만들고 싶다 git fetch --all && git reset --hard origin/master && git pull origin master
    • 원격 저장소에 .gitignore의 수정사항을 반영하고 싶다 git rm -r --cached . && git add . && git commit -m "test" && git push
    • 원격 저장소의 브랜치를 삭제하고 싶다 git push --delete <repo> <branch>
    • 원격 저장소에 태그를 만들고 싶다 git push <repo> <tag>
    • 원격 저장소의 태그를 삭제하고 싶다 git push --delete <repo> <tag>
    • 이미 등록된 원격 저장소의 주소를 변경하고 싶다 git remote set-url <name> <url>
    • 이미 등록된 원격 저장소의 이름을 변경하고 싶다 git remote rename <old> <new>
  • 브랜치 조작
    • 브랜치 목록을 확인하고 싶다 git branch
    • 브랜치를 만들고 싶다 git branch <branch> git checkout -b <branch>
    • 브랜치 이름을 변경하고 싶다 git branch -m <old> <new>
    • 브랜치를 삭제하고 싶다 git branch -d <branch>
    • 브랜치를 전환하고 싶다 git checkout <branch>
    • 브랜치를 병합하고 싶다 git merge <branch>
  • 태그 조작
    • 태그 목록을 확인하고 싶다 git tag
    • 태그를 만들고 싶다 git tag <tag>
    • 주석이 달린 태그를 만들고 싶다 git tag -a <tag>
    • 태그를 삭제하고 싶다 git tag -d <tag>
  • Stash
    • 현재 작업을 일시적으로 저장해두고 싶다 git stash (save) (desc)
    • 일시적으로 저장해 둔 작업 목록을 확인하고 싶다 git stash list
    • 일시적으로 저장해 둔 작업을 되돌리고 싶다 git stash pop
    • 일시적으로 저장해 둔 작업을 삭제하고 싶다 git stash drop
    • 일시적으로 저장해 둔 작업을 모두 삭제하고 싶다 git stash clear
  • 커밋 로그 조작(미확인)
    • 이전에 작성한 커밋을 수정하고 싶다 git commit --amend
    • 이전 커밋의 메시지 만을 수정하고 싶다 git commit --amend (add하지 않고)
    • 과거 커밋의 내용을 수정하고 싶다 git rebase -i <commit>
    • 과거의 커밋 메시지 만을 수정하고 싶다 git rebase -i <commit>
    • rebase를 하는 도중에 중지하고 싶다 git rebase --abort
    • HEAD의 이동 이력을 보고 싶다 git reflog
    • 브랜치 앞부분의 이동 이력을 보고 싶다 git reflog <ref>
    • 이전 커밋을 취소하고 싶다 git reset --hard HEAD~
    • rebase를 취소하고 싶다 git reset --hard <commit>
    • 이전에 실행한 reset을 취소하고 싶다 git reset --hard ORIG_HEAD
    • 다른 브랜치로부터 특정 커밋을 가져와서 내 브랜치에 넣고 싶다 git cherry-pick "<commit>"
    • 특정 코멘트를 포함한 커밋을 찾고 싶다 git log --grep "<pattern>"
  • Git 설정(미확인)
    • 사용자 이름/메일주소를 설정하고 싶다 git config --global user.name <username>
    • 출력 색상을 변경하고 싶다 git config --global color.ui auto
    • 명령어에 ‘Alias(단축키)’를 설정하고 싶다 git config --global alias.<aliasname> <commandname>
    • 불필요한 파일을 관리 대상에서 제외하고 싶다 .gitignore
    • 빈 폴더를 관리 대상에 넣고 싶다 .gitkeep
    • 설정 목록을 확인하고 싶다 git config --global --list
    • 프록시 서버를 경유하여 http 접속하고 싶다 .gitconfig
    • 사용자 인증이 필요한 프록시 서버를 경유하여 http 접속하고 싶다 .gitconfig

참고: .git 폴더 용량 초기화 + 여러개의 원격 저장소에 푸시하기

# 개발PC 로컬저장소
rmdir .git /q /S
git init && git add . && git commit -m "From zero"
git remote add origin <저장소1>
git remote set-url --add --push origin <저장소1>
git remote set-url --add --push origin <저장소2>
git push -u --force origin master
# 서버 원격저장소
# -> 그대로 둔다.
# 서버 로컬저장소
rm -rf .git
git init && git add . && git commit -m "init"
git remote add origin gitrepos/test.git

참고로, Git이 동작하는 원리는 파일의 스냅샷(VirtualBox의 스냅샷 같은)과 델타(diff) 등을 이용하는 것이라고 한다. 스냅샷은 특정 시점의 파일 내용을 담은 사본, 델타는 이전 시점과 비교하여 달라진 정보라고 생각하면 될 것 같다.

참고