깃 git

우몽가·2024년 1월 31일

git

버전 관리 시스템(Version Control System)

  • Backup
  • Recovery
  • Collaboration

다운로드

git-scm.com

공식 매뉴얼

Documentation
Pro Git (한국어도 있다.)

실습

codeonweb

명령어

기본 터미널 명령어

pwd

  • print working directory

cd

  • change directory
  • cd ~
    • home directory로 이동

mkdir

  • make directory

cp

  • copy
  • cp <file 1> <file 2>
    • file 1의 내용을 file 2에 복사

ls

  • list
  • 현재 경로의 폴더와 파일 확인

clear

  • clear screen

exit

  • logout

git 명령어

git <command> --help

  • 명령어에 대한 도움말을 확인할 수 있음
  • 방향키로 스크롤링 가능

git init {<path>}

  • 현재 디렉토리를 추적
  • .git 디렉토리 생성, 버전 정보 트래킹 시작

git status

  • 저장소 상태 확인

git add <>

  • git에게 추적 요청('stage'에 올리기)
    • stage : commit 대기중인 파일들이 가는 곳이라고 이해(commit하면 repository로)
  • stage에 올린 파일만 선택적으로 commit 할 수 있음

git config

  • --global user.name <username>
    • 작업자 이름 설정
  • --global user.email <email address>
    • 작업자 이메일 설정

git commit

  • #로 시작하는 line은 처리되지 않음
  • 버전(작업이 완결된 상태, snapshot) 생성
  • vim 활용법 정리하기
    • i
      • INSERT
    • :wq
      • WRITE, QUIT
  • -a
    • 변겅된 파일을 자동으로 stage에 올리고 commit
    • ⚠주의: 버전 관리가 시작되지 않은 파일은 자동으로 staging 되지 않음
  • -m
    • 커밋 메시지에 대한 에디터를 띄우지 않고 in-line으로 커밋 메시지 작성
    • git commit -m 'commit message'
    • git commit -am 'message' 이런 식으로 다중 옵션 사용 가능
  • --amend
    • 커밋 메시지 수정 (amend : 개정하다)

git log

  • 커밋 history 조회
  • 커밋(버전) id 확인 가능
  • git log -p
    • 각 commit의 source 차이를 확인할 수 있음
  • git log <commit id>
    • 해당 commit 포함 이전의 commit 확인
  • git log <branch name 1>..<branch name 2>
    • branch 사이의 commit 차이를 확인
    • branch 1에는 없고, branch 2에는 있는 commit을 확인
  • git log --reverse
    • log를 거꾸로 출력(첫 commit부터 볼 수 O)

git diff

  • 버전 간 source 차이 확인
  • 작업한 내용과 이전 commit과의 차이
    ```bash
    diff --git a/f1.txt b/f1.txt
    index 9462317..e3a30dc 100644
  • -- a/f1.txt
  • ++ b/f1.txt
    @@ -1 +1 @@
  • f1.txt : 2
  • f1.txt : 5
    ```
  • git diff <commit id 1>..<commit id 2>
    • 두 commit의 source 상의 차이를 확인 가능
  • commit 전 작업 내용에 문제가 있는지 마지막으로 review 할 수 있음
    • 작업한 후에 add하고 diff 하면 차이점이 없으니 안보이겠죠?

git reset

  • 커밋 취소(되돌리기)
  • 어렵고, 주의해야 함
  • revert와 비슷하나 다름
  • git reset {--hard} <최신 상태로 하고자 하는 commit의 id> {--hard}
    • 해당 commit version이 최신이 되고 이후의 commit이 사라짐(삭제 X, 숨겨짐)
    • --hard 옵션은 쉽게 사용할 수 있지만 위험하다
  • 협업 시에는 원격 저장소에 source를 공유하게 되는데, 공유를 한 이후에는 절대로 reset하면 안된다. (로컬에서만 go go)

git revert

  • reset과 비슷하나, commit을 취소하면서 새로운 버전 생성

git의 원리

분석 도구 Gistory

git init 시에 .git 디렉토리가 생성되고 여기는 git이 파일 변경 사항을 추적하는 정보가 들어 있다.
이 디렉토리를 분석하는 방식으로 원리를 파악하자

git add

  • 두 개의 파일이 변경된다
    • objects/##/####...####
      • 작성한 파일의 내용이 담겨 있음
    • index
      • 어떤 파일이 어떤 id 정보에 담겨있는지 기록되어 있음

      • 예를 들어 object/78/981922..994e85라면,

        100644 78981922..994e85 0  f1.txt
    • 💥 파일 복사(cp) 시에는 파일이 같은 index를 가지게 된다.
      • git은 파일 이름이 달라도 내용이 같으면 같은 object file을 가리킨다.
      • ❓ copy하지 않아도 그런가? 그러면 파일 내용이 계속 바뀌면?

object 파일명의 원리

구글에 'SHA1 Online' 검색(hash 알고리즘)

  • 파일의 데이터를 통해 hash 값 생성
  • 첫 두 문자로 directory를 만듦
  • 그 뒤 문자로 파일을 만들어서 정보 저장

commit의 원리

  • 파일 update에 대해 5개의 파일 생성 및 수정됨
    • COMMIT_EDITMSG0
    • logs/HEAD
    • logs/refs/heads/master
    • objects/##/####...####
      • commit 결과는 object file로 저장이 되고
      • ❓(잘 모르겠음) object file의 tree 값엔 해당 버전의 파일 이름과 내용이 link되어 있음
      • (첫 commit이 아닌 경우)parent에는 이전 commit의 commit id가 있다
    • tree ####...### parent ####...### author yck <yck@example.com> ########## +0900 committer yck <yck@example.com> ########## +0900 1(commit message)
    • refs/heads/master

Object 파일

object 파일엔 크게 세 가지가 있다.

  • 파일의 내용을 담고 있는 blob
  • 디렉토리의 파일명과 내용에 해당되는 blob에 대한 정보를 담고 있는 tree
  • commit

status의 원리

변경 사항이 없을 때, nothing to commit임을 어떻게 알 수 있을까?

  • index와 최신 commit의 tree를 비교

구글에 'git working directory vs index vs repository' 등의 키워드로 검색하면 괜찮은 시각 자료들이 많다.

branching

  • 작업 분기? 'branch'를 만든다
    • 고객 요청에 따른 customizing이 필요할 때
    • 기능에 따라 branch를 파서
      개발 진행할 때 등
  • git branch
    • branch 목록 및 현재 branch 출력
    • 기본 branch 이름은 'master'('20년 이후론 'main'을 사용한다고 함)
  • git branch <브랜치명>
    • branch 생성
    • 생성 시 현재 branch의 상태를 그대로 가지고 있음
  • git branch -d <브랜치명>
    • 브랜치 삭제
    • merge 후에 삭제하는 경우가 있다
  • git checkout <브랜치명>
    • branch 이동
  • git log --branches --decorate {--graph} {--oneline}
    • branch 별 최신 commit 확인 가능
    • HEAD는 현재 checkout된 branch를 나타냄
    • --graph
      • 왼쪽에 branch 시각화됨
    • --oneline
      • 한 줄에 출력

git merge

  • exp라는 branch의 내용을 master branch로 병합하려면 어떻게 해야 할까?
    • master로 checkout한 뒤에 merge한다!
      • git checkout master
      • git merge exp
    • merge하는 commit이 생성됨.
    • merge 후엔 양쪽의 commit을 모두 홀드함

branching 심화

지옥 git 20강
👀 Pro Git <-> 보고 이해하기

git stash

한 브랜치에서 작업하다가 작업이 끝나지 않았는데 다른 브랜치로 checkout하여 다른 작업을 해야 하는 경우가 있다.

그런 경우 끝나지 않은 작업을 commit하지 않으면 checkout하지 못하는 경우가 발생한다. 완료되지 않은 작업을 commit하기도 애매한데..

그럴 때 stash를 하면 작업 내용을 숨겨놓았다가 HEAD version으로 이동하여 현재 branch 상태를 깔끔하게 만들고 다른 branch로 checkout할 수 있다.

💥 주의사항: 추적되고 있는 파일에만 stash 작업 가능

  • git stash {save}
  • Saved working directory and index state WIP on exp: 9161e43 1 HEAD is now at 9161e43 1
  • 이후 git status를 확인하면 'nothing to commit'이 뜨고 작업 내용도 '감춰진다'
    • 다른 branch로 checkout할 수 있게 된다
  • git stash apply
    • stash했던 작업 내용이 적용됨
  • git stash list
    • stash했던 작업 리스트 출력
    • stash 내용은 명시적으로 삭제하지 않는 이상 남아있게 된다.
  • git stash drop
    • 최신 stash 삭제
    • 응용하기
      • git stash apply; git stash drop;
      • 한번에 하려면 git stash pop

branch 충돌 해결

서로 다른 브랜치에서 같은 파일에 대해 작업을 한 뒤에 merge하게 되면 충돌이 발생할 수 있다.
같은 파일이라도 다른 부분에 대해 작업하면 괜찮을 수 있는데, 같은 부분을 다르게 작업한 뒤 병합하려고 하면 충돌이 발생한다.

$ git merge <branch name>

Auto-merging source.code
CONFLICT (content): Merge conflict in common.txt
Automatic merge failed; fix conflicts and then commit the result.
$ git status

On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:  common.txt

no changed added to commit (use "git add" and/or "git commit -a")
  • both modified
    • 병합하려는 브랜치 모두에 수정이 되었기 때문에 충돌 발생, 병합 실패
$ vim common.txt
function b() {
}
<<<<<<< HEAD
function a(master) {
=======
}
function a(exp) {
>>>>>>> exp
}
function c() {
}
  • ======= 구분자를 기준으로
    • <<<<<<< HEAD (Current Change)
      • 현재 checkout한 브랜치의 수정사항(즉 여기선 master)
    • >>>>>>> exp (Incoming Change)
      • exp 브랜치의 수정사항
  • source를 보고 conflict 수정해서 add, commit하면 됨

reset checkout

  • git reset을 해서 버전을 되돌려도 이전 버전이 삭제되지는 않는다

    • .git 디렉토리의 파일들(ORIG_HEAD 등)을 보면 알 수 있음
  • 그러면 reset한 뒤에 다시 원복하고 싶으면 어떻게 할까?

    $ git reset --hard ORIG_HEAD
  • 이렇게 하고 git log를 확인하면 reset이 취소되었음을 알 수 있다.

  • git reflog에서 내역 확인 가능

commit으로 checkout

  • git checkout <commit id>
    • detached HEAD state가 된다.
    • git branch를 확인하면 master 브랜치가 아닌 93c9517과 같이 commit을 가리키고 있음을 확인할 수 있다.
    • .gitHEAD 파일을 보면 HEAD가 직접 commit id를 가리키고 있음을 알 수 있다. (HEAD가 브랜치를 직접 가리키지 않고 commit을 가리키는 'detached' 상태)
    • git checkout master 등으로 돌아갈 수 있음

Git의 내부 구조 : working copy & index & repository

working directory

❓❓ '24. 1. 18. 아직 세 가지 구조가 100% 이해되지 않는다

  • 작업을 진행하는 곳
  • A.K.A.
    • working tree
    • working copyindex
  • git add했을 때 해당되는 곳
  • A.K.A.
    • staging area
    • cacherepository
  • version, 즉 commit이 저장되는 곳
  • A.K.A.
    • history
    • tree

git reset의 옵션들

  • git reset --help로 확인 가능
    • --soft, --mixed, --hard가 주로 언급됨
  • --hard
    • working directory, index, repository 모두 영향
    • 쉬운데 위험하다;
  • --mixed
    • index, repository에 영향
  • --soft
    • repository에 영향

merge와 conflict

'kdiff3'라는 오픈소스 머지 도구 설치

git config --global merge.tool kdiff3
git mergetool  // 충돌 난 파일을 kdiff3라는 mergetool 이용하여 merge

3-way merge

Branch 1BaseBranch 2
AAnull
BBB
1C2
nullDD

다음과 같은 상황에서 B2를 B1으로 merge하려면 어떻게 할까?

2-way merge

Base는 신경쓰지 않고 B1과 B2를 비교하여 병합
Branch 1 | Branch 2 | 2-way merge
---|---|---
A|null|?
B|B|B
1|2|?
null|D|?

3-way merge

Base를 참고하여 B1과 B2를 병합
👍 훨씬 좋다
Branch 1 | Base | Branch 2 | 3-way merge
---|---|---|---
A|A|null|null
B|B|B|B
1|C|2|?
null|D|D|null

  • ※ 원래 코드와 비교하여 누가 수정을 했는가? 에 초점을 맞춰서 생각

Remote Repository(원격 저장소)

  • Local Repository(지역 저장소)와 대비되는 개념
  • 인터넷에 연결된 저장소를 통해 다음이 가능해진다.
    • 소스코드 버전 백업
    • 협업

원격 저장소 세팅

  • git remote add origin <path>

    • local repository와 remote repository를 연결한다.
    • 경로에 origin이라는 별명을 븥인다
  • git remote -v

      origin  home/git/git/remote (fetch)
      origin  home/git/git/remote (push)
  • git remote remove origin

    • 저장소 삭제
  • git push

    • master branch를 원격 저장소에 같은 branch 이름으로 upload
  • git push --set-upstream origin master

    • origin의 master branch로 push한다.
    • --set-upstream
      • 앞으로 master 브랜치에 push하면 자동으로 origin master로 푸쉬하겠다 라는 것.
  • git push

    • 최신 commit까지의 상황을 remote repository에 upload
  • git clone <원격 저장소 주소>

    • remote repository의 내용을 local repository로 가져옴

GitHub

(원격 저장소 서비스 中 1)
작업하고 있던 local repository를 remote repository(GitHub)에 연결하려면?

  • git remote add origin https://github.com/username/repositoryname.git
    • GitHub에 생성된 remote repository에 연결
    • 주소가 너무 기니까 origin이라는 alias 부여
    • git remote -v로 확인

push

local repository -> remote repository

  • git push -u origin master
    • -u 옵션
      • --set-upstream
      • 이후 push하면 origin master로 감

동기화 방법

회사 컴퓨터와 집 컴퓨터 두 기기에서 작업을 한다고 하자.
집 컴퓨터에서 commit 후 push를 하고 회사 컴퓨터에서 작업을 이어가려면 어떻게 해야 할까?

우선 git pull을 해야 한다. (remote -> local)

작업 끝나면 git push를 습관화하자.

pull 안하고 작업헀을 때

  • push가 안됨(rejected)
  • 다른 저장소에서 push했을 수 있음
  • pull 해서 먼저 병합해주어야 함

SSH

SSH : Secure SHell
HTTPS와 다른 통신 방법.

$ ssh-keygen
  • ssh를 통해 다른 기기에 접속할 수 있는 pw 생성
  • cd ~/.ssh
    • home directory > .ssh 이동
    • 두 가지 파일 생성됨
      • id_rsa (private key)
      • id_rsa.pub (public key)
    • public key를 원격 접속하려는 컴퓨터에 저장해 두고 private key를 통해 자동 로그인하는 방식(으로 이해)
  • cat id_rsa.pub
    • public key를 정교하게 복사 후 GitHub에 제출
    • Settings > SSH and GPG keys

자기 서버에 원격 저장소 만들기

('24. 1. 18.) 일단 스킵. 필요할 때 다시 보기

원격 저장소 원리

  • git remote add origin <remote repo>
    • .git에서는 config라는 파일이 수정됨
    • config 내에 remote repo와 local repo 정보가 저장됨
  • git push

현재 branch인 master는 upstream(local repo에 연결된 remote repo)의 branch에 연결되지 않았다. 이런 뜻

    • 현재 branch의 upstream을 set(--set-upstream)한다.
    • 뭐로? remote repo 'origin'의 'master' branch로
  • fatal: The current branch master has no upstream branch. To push the current branch and set the remote as upstream, use git push --set-upstream origin master

pull vs fetch

  • fetch는 다운로드 이후 최신 커밋이 원격 저장소 몇 번인지는 기록했지만 local repository의 master 브랜치에는 변화 가하지 않음
    • 즉, remote repository에서 가져오지만 병합하지 않음
    • git merge origin/master로 원격 저장소(origin)의 브랜치와 병합할 수 있음
  • pull은 remote repository에서 불러와 병합까지 해줌

tag

  • GitHub에서, 'releases'는 뭘까?
    • release는 사용자에게 제공되도 좋은 각각의 의미 있는 version
  • 'tag'는 특정 commit id(version)을 가리키지만, branch와 다르게 고정적이다.
  • 만약 버전 1.0.0을 릴리즈했다고 하면 시간이 지나도 그 버전이 어떤 commit에 해당되는지 알아야 한다.
  • git tag 1.0.0 <branch-name or commit-id>
    • master branch가 특정 commit을 가리키고 있을 때
    • 해당 commit에 대한 tag가 생성됨
    • git tag, git log에서 태그 확인 가능
  • git checkout <tagname>
    • 태그로 checkout
  • 'annotated tag' VS 'lightweight tag'
    • git tag -a 1.1.0 -m "bug fix"
      • 태그에 대한 message 작성 가능
    • git tag -v 1.1.0
      • 태그 생성한 사람, 설명 등 확인 가능
  • git tag -d <tagname>
    • tag 삭제

태그를 remote repository로 보내기

  • 그냥 push하면 태그까지 upload되지는 않음
  • git push --tags
    • local repository에서 만든 tag가 remote repository로 upload됨
  • Pro tip : Semantic Versioning

태그 원리

('24. 1. 18.) 스킵

Rebase

  • merge와 비슷하나 다르다
  • 두 브랜치가 공통으로 갖고 있는 조상을 base라고 함
  • rebase는 base를 바꾸는 것
    • master branch에서 feature branch가 파생되어 각각 뻗어나갔을 때
    • git checkout feature, git rebase master
    • feature의 조상이 master가 됨
  • merge에 비해 어렵고 위험하다
  • 다른 사람과 공유된 branch는 손 대지 말자.

Git Flow

Material: A Successful Git Branching Model

브랜칭 전략

profile
우몽가의 노트

0개의 댓글