GIT

람뽀·2024년 4월 22일

OZ 코딩스쿨

목록 보기
5/11

2024.4.22

~ 2024.4.24

GIT이란?

  • 분산 버전 관리 시스템 distributed version control system - DVCS (ex. GIT, Mecurial, Bazaar, Darcs)

  • 작업의 변경점을 버전으로 기록한다. 기록된 버전의 시점에 해당하는 환경으로 돌아 갈 수 있다.

  • Git(깃)은 버전 관리 시스템이고, GitHub(깃허브)는 Git으로 관리하는 프로젝트를 올려둘 수 있는 사이트이다.

  • GIT : 로컬 버전 관리 시스템. 인터넷이 연결되지 않은 환경에서 사용되며, 다른개발자와의 작업 공유가 힘듬.

  • GIThub : 웹 기반 버전관리 시스템. 클라우드 서버에 소스 코드를 업로드하여 공유. 분산버전제어, 엑세스제어(권한), 소스코드관리, 버스추적, 기능요쳥 및 작업관리 기느을 제공함.

    발표자료를 준비해본 사람이라면 한번쯤은 겪어봤을 최최최종.pdf 로 DVCS의 예시를 들 수 있다.

    각 자료에는 저장된 당시의 내용이 기록되어있고, 사용자는 언제든지 해당 시점의 기록을 확인하고 사용할 수 있다. 작성자가 아닌 이용자도 확인하고 싶은 시점의 버전을 이용 할 수 있다. GIT도 이런 원리이다.

    중앙 서버와 각각의 클라이언트는 모두 백업이력을 갖기 때문에 한곳에 문제가 생겨도 다른 저장소를 복제하여 작업을 시작 할 수 있다.

  • 사용환경

    • CLI : Command Line Interface. 글자를 입력해서 컴퓨터에 명령을 내리는 방식 (ex. VScode)
    • GUI : Graphical User Interface. 아이콘, 메뉴 등 그래픽 요소를 이용해 상호작용하는 방식 (ex. SourceTree)
  • 설치 : https://git-scm.com/ (-> 설치를 시작하면 다양한 방법을 안내해주는데, 홈브루는 추후에 개발을 하면서 설치해야하는 여러가지 프로그램의 버전을 쉽게 관리 할 수 있게 도와줌으로 추천 )

  • 설정

    • 설정범위 : 전역Global / 지역Local / 시스템System
    • 전역 : 특정 저장소로 한정. 생성되는 모든 폴더에 적용 (추천)
      git config --global user.name "원하는 이름 또는 Github 닉네임"
      git config --global user.email "사용하는 이메일 주소 또는 Github 가입에 사용한 이메일"
      git config --list // 기입한 내용 확인
      git config --global --unset user.name // 전역 값 삭제
    • 지역 : 특정 저장소Repository로 한정. 폴더하나
      git config user.name "원하는 이름 또는 Github 닉네임"
      git config user.email "사용하는 이메일 주소 또는 Github 가입에 사용한 이메일"
      git config --unset user.name
    • 시스템 : 해당 컴퓨터의 모든 저장소와 사용자 (추천x)
    • 기본 브랜치명 변경 (master -> main) : 안되면 branch명 자체를 바꿔도 OK (협업하는 동료와 통일)
      git config --global init.defaultBranch main
      변경하는 이유 : 일부 지역에서 master단어를 노예역사의 잔재로 생각하여 이슈 제기. 이후 git에서도 이것을 받아들여 main으로 사용하기를 권장함.

프로젝트 시작

  • 작업할 폴더 생성. 터미널 or vscode or sourcetree등 원하는 것으로 명령.

  • git init : 로컬 저장소가 깃이 관리하는 저장소로 변경됨. 실행한 폴더의 숨김파일을 보면 .git파일이 생성된것을 확인 할 수 있음. 깃은 이런식으로 코드상태이력을 데이터베이스와 같은 시스템을 이용하지않고 자체적인 파일로 저장함. 해당 폴더를 삭제하면 기록도 모두 삭제됨

  • git status : 폴더 안에 새로운 파일을 생성 한 후 명령어를 입력하면 Untracked files 목록을 보여줌.
    이것은 git의 stage로 untracked(해당 파일을 추적하지 않고 있음) / tracked(추적중) 두 가지의 상태가 있음. 위 파일은 새로 만들어서 추적하고 있지 않은 상태.

  • git add : 생성되어 추적불가능 하거나 수정된 파일을 스테이지에 올리는 명령어 git add 파일명 or .(모든파일)

    다시 확인하면 스테이지에 올라와 있음.

  • .ingnore파일 : 그러나 공유하지 않아야하는 중요한 파일도 있음. 그럴경우 해당 파일에 파일명을 입력하면 git에서 관리하지 않음.

    # 모든 .c 확장자 파일
    *.c
    # .c 확장자지만 무시하지 않을 파일(! 느낌표)
    !not_ignore_this.c
    # logs란 이름의 파일 또는 폴더와 그 내용들
    logs
    # logs란 이름의 폴더와 그 내용들
    logs/

    https://www.toptal.com/developers/gitignore <- 개발 환경에 따라 추천하는 .gitignore파일을 만들어주는 사이트

commit

  • git commit -m "message" : 버전을 만들어주는 명령어. 각 시점을 스냅샷(사진을 찍는것)형태로 저장한다. 협업시 커밋은 남발하지 않는것을 권장한다. 의미없이 사용하지 않아야 한다. 이력이 복잡해지기 때문이다.

    #commit을 만드는 명령어 : -m은 뒤에 commit 메시지를 입력할 수 있도록 해주는 옵션
    git commit -m "커밋 메시지"
    
    #변경된 모든사항을 바로 add하고 commit하는 명령어
    git commit -am "커밋 메시지" // 오류가능성이 있어 비권장

    커밋은 영구적으로 저장되면 커밋 당시의 내용은 변경 할 수 없지만 커밋메세지는 수정 할 수 있음. 각 커밋은 해시값을 가지고 있다. 이미지는 --oneline을 이용하여 짧지만, 실제로는 더 길다. 하지만 앞의 7자리만 사용해도 커밋은 구분 가능하다.

  • git log : 커밋된 이력을 확인 할 수 있음.

    git log --oneline // 한줄로보기
  • git reset : 원하는 시점의 커밋으로 이동함. 해당 시점의 커밋을 기준으로 이후에 작성된 커밋이력을 삭제함.

    • git reset --hard 커밋해시 : 이전 커밋으로 되돌리고 이후 이력 모두 삭제
    • git reset --soft 커밋해시 : 이전 커밋으로 되돌리고 이후 이력들은 삭제되지 않고 stage에 올라감
    • git reset --mixed 커밋해시 : 이전 커밋으로 되돌리고 이후 이력들은 삭제되지 않고 untracked됨.
    • reset을 사용하는 시점에서 이미 커밋을 강제로 되돌리는것이기 때문에 주로 hard를 사용함
    • 혼자서 작업하는 브랜치인 경우나 정말 아무도 이 브랜치를 사용하지 않는다고 확신할 때만 사용해야한다. 삭제된 이력을 팀원도 확인할 수 있어야 하기 때문이다.
  • git revert 커밋해시 : 원하는 시점의 커밋된 내용만 삭제한다. 해당 커밋도 사라지지않고, revert했다고 이력도 남음 (= 새로운커밋생성). 그때 한 작업 내용만 삭제되는 것이다.

  • git reflog : git은.. 모든것을 살피고있다..! 위 명령어들을 사용하여 삭제한 내역도 확인 할 수 있다. HEAD의 참조 이력을 로그 형태로 출력해준다.
    이렇게 리셋, 리버트된 커밋 모두 확인할 수 있기 때문에 해당 커밋이전으로 이동하는 get reset --hard를 이용하면 수정하기 이전의 시점으로 돌아 갈 수 있다.

branch

git의 꽃. git이 많은 점유율을 차지하고 있는 이유 중의 하나. 어떤 작업을 독립적으로 수행하기 위한 개념이다.

여러사람이 동일한 소스코드를 기반으로 다른 작업을 진행하면 서로 다른 버전의 코드가 만들어지고, 충돌이 생길 수 밖에 없다. 이것을 방지하면서도 여러 개발자가 동시에 작업할 수 있게 만들어 주는 기능이 branch이다.

기존의 main브랜치의 코드를 복제한 각자의 독립적인 영역에서 마음대로 소스코드를 변경하고, 원래의 버전과 비교하여 하나의 새로운 버전으로 병합Merge된다.

# 브랜치 생성
git branch [브랜치 명]
예) git branch oz

# 브랜치 목록 확인
git branch

# 생성한 Branch로 이동
git switch [브랜치 명]
예) git switch oz

# 브랜치 생성과 동시에 이동하기
git switch -c oz

# 브랜치 삭제하기
git branch -D (삭제할 브랜치명)
예) git branch -D oz

# 브랜치 이름 바꾸기
git branch -m (기본 브랜치명) (새 브랜치명)
예) git branch -m oz oz_new

branch가 많아질수록 HEAD의 중요성이 올라간다. HEAD란 해당 branch의 마지막 commit을 뜻한다.

위 이미지에서 main branch의 마지막 커밋은 맨 윗줄이고 / oz branch의 마지막 커밋은 first commit임을 확인 할 수 있다.

이렇게 현재 branch의 커밋이력이 어디인지를 확인하고, 현재 작업영역이 다른branch에 비해 얼마나 커밋이 차이가 나는지 그리고 차이가 있다면 그것이 무엇인지 파악해야한다.

branch를 합치는 2가지 방법

merge와 rebase가 있다. 브랜치에서 commit 이력을 main의 커밋 이력과 합치는 기능은 동일하지만 병합된 브랜치의 이력을 남기는지(merge) 아니면 이력을 남기지 않고 합치는지(rebase) 목적에 따라 다르게 사용될 수 있다.

merge

  • 병합되는 branch의 커밋이력을 유지한채 main branch에 합치는 기능으로 협업시 주로 사용한다. main으로 이동 후 진행한다.

    #원하는 branch로 이동하는 명령어
    git switch [이동을 원하는 branch]
    
    #main에 branch의 커밋 이력을 합칠때 사용하는 명령어
    git merge [합치고 싶은 branch]
    
    예) 
    git switch main
    git merge oz
    #log 명령어를 통해 합쳐진 이력 확인
    git log
  • merge의 두가지 방식

  • fast-forword : main branch에서 새로운 branch가 분기해나가는 시점 = 두 브랜치가 공통으로 가지고 있는 commit을 base라고 한다. 여기서 이미지와 같이 새로운 branch는 새로운 커밋이 생겼지만, main branch는 그렇지 않기 때문에 merge해도 새로운 커밋이 생성되지 않고 병합된다. 마치 점프하듯 상대 브린채의 참조값으로 이동하는 모습을 본따서 fast-forward라고 부른다. git merge --ff [브랜치명], git merge --no-f [브랜치명] 명렁어를 사용하여 fast-forword으로 merge할지 정할 수 있다.

  • 3-way-merge 방식 : 보통의 흔한 merge방식. 두 브랜치 중 어느 것도 base에 위치하지 않은 상태일 때 git merge 명령을 실행하면 새로운 commit이 생성된다. 기존커밋, 새로운브랜치의 새로운커밋, 메인브랜치의 새로운커밋의 3가지의 커밋을 기준으로 병합하기 때문에 3-way이다.
    -git merge --squash (대상 브랜치) : 강력한 병합방식. commit이력과 merge된 브랜치 이력도 남기지 않고, 새로운 commit에 상대 브랜치의 내용을 모두 집어 넣는다. 자동 커밋이 되지 않아 별도의 커밋이 필요하다.

rebase


위 이미지와 같이 분기된 브랜치의 이력을

main 브랜치와 연결지어 하나의 이력으로 만들어줌. 기존 branch의 이력이 사라져 하나의 깨끗한 이력을 관리하기가 용이하지만 하나의 이력으로 만드는 과정에서 모든 커밋이 재정렬되어 해시값이 변경되고 충돌이 발생 할 수 있음.

#합치려는 branch로 이동하는 명령어
git switch [이동을 원하는 branch]

#합치려는 branch의 커밋 이력을 합칠때 사용하는 명령어
git rebase main

#main branch로 이동
git switch main

#main에서 main branch와 합치고자하는 branch를 merge 진행
git merge [합치고자하는 branch명]

예)git switch develop 
   git rebase main
   git switch main
	 git merge develop

Rebase를 실행하면 branch 이력이 삭제되고 main에 커밋 이력들이 합쳐지는데 이때 main의 head는 main에서 커밋된 마지막 위치에 있기 때문 merge를 이용해 병합한 branch와 다시 한번 합치는 과정을 진행해야 한다.

충돌

병합을 하는 두개의 branch에서 같은 파일에 같은 값이 서로 다르게 수정되어 있으면 충돌이 발생한다.

  • merge : 머지를 이용했을 때 충돌이 발생하면, 해당 파일이 무엇인지 또 어떤 값을 선택할지 결정해주어야 한다. ( 팀원과 충돌된 것이라면 팀원과 회의를 해야한다.)


변경사항을 결정 한 후에 반드시 저장!!!!! 하고 스테이지에 올린 후(git add) 커밋해준다. vim 편집기 화면이 나오는데 최상단에 커밋 이력이 자동으로 입력되어 있기 떄문에 wq로 저장하고 나오면 된다. 완료되면 머지되었다는 새로운 커밋이 생성된다.

  • rebase : 충돌이 일어나면 마찬가지로 해당 파일의 값을 어떻게 수정할지 결정해주어야한다. 이후 스테이지에 올리고, rebase를 마저 진행하라는 명령어를 입력한다. git rebase --continue 충돌이 해결 될 때까지 반복하면 되고, 더이상 수정할 사항이 없다는 알림이 보이면 main으로 이동하여 merge한다.

GIThub

토큰

  • 깃허브 서버에 인증할 때 사용되는 고유값. 계정 비밀번호 대신 사용되며 HTTPS를 통해 Git 저장소에 안전하게 액세스할 수 있음. 보안이 중요한 작업일 경우 토큰을 이용해서만 접근하여 작업하도록 지정할 수 있음.
  • settings의 가장 아래에 위치한 Developer settings에서 발급 가능하며, 발급 시 제어권한을 설정할 수 있다. 한번 발급된 토큰은 이후 다시는 볼 수 없음으로 별도로 저장해두는 것을 추천한다.(잊어버리면 재발급 해야한다.)

원격 Repository


내 GIT에 존재하던 자료, commit, branch를 저장하는 웹상의 클라우드 저장소.
생성시 README.md를 만들겠냐는 옵션은 비추천 (github에는 존재하지만 나의 로컬git에는 없어서 따로 만들어주는 번거로운 과정 필요해짐)

git remote add origin [원격 저장소 주소]
git push -u origin main // 저장소에 이력 저장

위 명렁어를 사용하여 로컬저장소와 연결해줘야 함.

  • origin은 예를들면 변수로 뒤에 오는 주소를 담는 이름임.(즉 꼭 origin으로 안해도 됨. 이 변수는 새로운 주소로 덮어쓰기가 되지 않기 때문에 새로운 주소를 추가하려면 다른 이름을 사용해야 함.)
  • 주소를 복사할 때 SSH는 GitHub과의 안전한 통신을 가능하게 하는 방법 중 하나로 별도의 생성과 연결과정이 필요함.
  • git remote -v로 현재 내 git에 연결된 github repository를 화인 할 수 있음.
  • git remote remove [origin과 같은 별칭 입력] 주소 삭제

원격 branch 관리

  • 로컬에서 만든 branch 원격에 push : git push -u origin from-local
  • 원격의 branch 로컬에 받아오기 : git fetch, git branch -a, git switch -t origin/from-remote
  • 원격의 branch 삭제 : git push (원격 이름) --delete (원격의 브랜치명)

깃허브 원격저장소에 있는 프로젝트를 로컬저장소로 가져오는 방법은 3가지가 있다.

  1. git pull
  2. git fetch
  3. git clone

git pull

  • git pull
  • 원격저장소에 있는 프로젝트의 변경사항을 그대로 로컬저장소에 옮겨와 자동으로 병합한다. 개인단위의 프로젝트에서 사용 多.
    병합 후 커밋이력을 확인 할 수 있다.
  • 만약 원격저장소와 로컬저장소의 이력이 다를때 로컬에서 push를 하면 오류가나며 적용할 수 없다. 이럴경우 pull을 선행해야 한다.
  • git pull --rebase : rebase는 전에 공부한것처럼 이력을 마치 하나처럼 보이게 한다. 이 명령어 또한 이력을 하나로 맞추고 해시를 재정렬한다.

    위 두개의 예시는 일부러 충돌을 발생시키고 위는 git pull --no-rebase 아래는 git pull --rebase로 불러와서 병합했다. 소스트리로 그래프를 확인해보면 rebase는 하나의 이력으로 정리됐다.

git fetch

  • 원격저장소에 있는 프로젝트의 변경사항을 그대로 로컬저장소에 옮겨오지만 병합은 하지 않는다. 다수의 개발자가 함께하는 프로젝트에서 사용 多.
    협동 프로젝트의 경우 어떤것이 수정되었는지 확인할 필요가 있기 때문에 바로 병합하지 않고 fetch로 받아와서 변경사항을 먼저 확인하는 것이 좋다.

사용해보기 위해서 원격저장소에서 직접 파일을 수정한 후 git fetch를 했다. 위 이미지는 git log origin을 해서 원격저장소의 커밋내역을 확인하고 아래이미지는 git log해서 로컬저장소의 커밋내역을 확인했다. 차이가있다.(그냥 log origin해서는 안된다 패치해야 차이가 생긴다 당연한가)
확인하고 나면 pull 하면 된다. (결국 pull이구먼 뭔가 다른줄알았다)

git clone

  • 원격저장소의 내용을 새로운 폴더에 그대로 복사하는 것이다.(다른사람것도 가능)

git branch strategy

무분별한 Branch 생성으로 협무의 효율이 떨어지지 않도록 협업을 위한 전략이 많이 존재한다.

  • One of the Git Flow : 규모가 작은 프로젝트의 경우 적합하다.
    첫번째 master는 실제로 서비스가 적용되는 부분으로 최종코드이다. 완성도가 높고 안정적이어야 한다. 그래서 해당 영역에 직접 작업하지 않고 완전히 복사 fork한다. fork는 특정 레파지토리를 나의 원격 repository로 복제한다.
    그리고나서 나의 로컬storage로 clone하여 작업하는데, 이때도 master branch에 직접 작업하지 않고 작업별로 branch를 만들어서 작성한다.
    fork된 원격저장소에 병합할때도 branch에 저장해야한다. forked master branch에 직접 저장하여 원본파일이 훼손되지 않도록 해야 한다.

tag

커밋 이력의 특정 시점을 키워드로 저장하여 버전을 붙이고자 할 때 사용한다.
https://semver.org/

  • vM.M.P (예. V2.0.0)

    • Major version : API 변경이 필요할 정도의 변화

    • Miner version : 기능 추가 정도의 변화

    • Patch version : 버그 수정 정도의 변화

      태그종류설명
      lightweight특정 커밋을 가리키는 용도
      annotated작성자 정보와 날짜, 메세지, GPG서명 포함 가능
  • 사용방법

  • git tag v2.0.0 : lightweight. 마지막 커밋에 태그를 달아줌

  • git tag : 현존하는 태그 확인

  • git show v2.0.0 : 원하는 태그의 내용 확인

  • git tag -d v2.0.0 : 태그 삭제

  • git tag -a v2.0.0 : annotated 방식으로 태그 추가. 입력하면 메세지 입력창 뜸

  • git tag (태그명) (커밋 해시) -m (메시지) : 원하는 커밋에 태그 달기

git hooks


숨겨져있는 .git폴더를 보면 많은 sample이 있음. sample을 때면 동작함. Git상의 이벤트마다 자동으로 실행될 스크립트를 지정할 수 있음 (푸시 혹은 커밋될 때마다 이모지추가 or 테스트코드 자동실행 후 검증 or gitAction과같은 CI/CD)

  • gitmoji : 커밋마다 이모지를 달아줌. 아무거나 다는건 아니고 의미마다 붙여주는것.(개발자들은 참 이모지를 좋아하네 글자만 보고 살아서 그런가)
  • 터미널에서 gitmoji 설치 : brew install gitmoji
  • 프로젝트 폴더이서 gitmoji 실행 : gitmoji -i
  • 이후 commit 해보면 임티 추가하라고 뜸.
    title, commit message까지 입력 가능.

git submodules

git프로젝트에 다른 git프로젝트를 하위 디렉토리에 포함시키는 방법.

상위 레포지토리를 슈퍼 프로젝트(superproject), 하위 레포지토리를 서브 모듈(submodule)이라고 부른다. (혹은 부모 저장소, 자식 저장소라고 부르기도 한다.)

하나의 저장소에 여러개의 프로젝트를 관리하며 각 프로젝트는 별도의 저장소로 유지됨. 여러 프로젝트에서 사용되는 공통 모듈일 때 유용하다.(라이브러리 등)

  • 연습을 위해 main project, submodules라는 각각의 repository생성
  • main에서 git submodule add (submodule의 GitHub 레포지토리 주소) (하위폴더명, 없을 시 생략)
  • main 프로젝트 내에 submodule폴더와 .gitmodules 파일이 생성됨. -> commit
  • main프로젝트 내의 파일과 생성된 submodule폴더에 각각 값을 수정하고 git status해보면 submodule폴더의 변경사항은 포함되지 않음을 볼 수 있음.
  • 하지만 submodule폴더에 들어가서 commit을 한 후 main으로 돌아와서 다시 git status해보면 commit변경이력은 둘 다 확인됨 -> 파일 수정은 확인하지 않지만 커밋이력은 인지함.
  • 이후 main에서 다시 commit하고 push하면 이력이 적용되는데, submodule의 레파지토리는 변하지 않음. (퍼온거니까!)

git organization

같은 프로젝트를 관리하는 데 사용하는 Github 그룹 계정, 개인 레파지토리에서 작업하는 것 보다 효율적임.

  • 권한관리, 이슈 및 pull Request관리, 프로젝트 관리, 보안 및 액세스 제어 가능

  • 생성 후 팀원 초대

  • repository 생성

  • 이슈 템플릿 생성 가능

  • 프로젝트 관리 템플릿 가능

    이미지에서는 식사추천을 하고있지만!
    저런식으로 각각의 이슈를 만들어서 해당 이슈를 누가 작업할지, 무엇을 어떻게 작업할지를 정할 수 있고 팀장에게 pull request를 신청하고 통과되어 merge되면 done으로 자동으로 이동됨.
    이런식으로 라벨을 붙일 수도 있고, 작업한 내용이 남으며 서로 코멘트도 남길 수 있음.

  • pull request : 여기서 Pull Request란 '코드를 수정했는데 당신도 코드를 수정했다면 제 수정한 내용도 적용시켜 주세요'라는 의미다. 병합하기 전에 팀원 or 리더가 코드를 확인하는 과정으로 이후 merge가 진행된다. 원본 저장소의 내용을 fork한 후 내가 작업한 내용을 원본저장소에 적용하길 원할 때 요청한다.


Git&GitHub를 연습해볼 수 있는 사이트

profile
시리즈별로 정리중 ✍(´ι _`  )

0개의 댓글