git fork와 upstream

git은 분산 버전관리 시스템이다.

원격 서버를 거치지 않더라도 버전을 관리할 수 있다.

오픈소스 컨트리뷰톤을 위해 깃허브 수업을 들은 내용을 개인적으로 공부하여 다시 정리해보았다.

remote repository

네트워크 상의 서버에 존재하는 저장소를 remote repository라고 부른다.

local repository

remote에 있는 저장소를 git clone하거나 git init으로 생성해서 로컬에 존재하는 repository를 local repository라고 한다.

push와 pull

local 저장소와 remote 저장소의 작업내용을 반영하기 위해 pushpull이라는 작업을 하게 된다.

  • push: local에서 remote로 commit 이력을 업로드 하는 것
  • pull: remote에서 local로 commit 이력을 다운로드 하는 것

upstream과 downstream

local 기준에서 remote는 upstream, local이 downstream이 된다. remote로부터 local로 흐르는 관계가 되기 때문이다.

초기 저장소에 cli로 push를 할 때 git push -u origin main 명령어를 사용하는데, -u--set-upstream옵션의 줄임말로 upstream을 설정한다는 뜻이다.

upstream을 설정하고 나면 다음부터는 git push 또는 git pull이라고 명령어를 입력하면 자동으로 origin의 main 브랜치로부터 push와 pull을 진행하게 된다.

fork

다른 사람의 저장소를 복사하는 것을 fork라고 한다. 주로 오픈소스 프로젝트에 기여하거나, 협업을 진행하는 경우에 사용한다.

이 경우 원본 remote -> 내가 fork한 remote -> 내 local 순으로 upstream, downstream 관계를 만든다.

때문에 github으로 협업을 할 경우 다음과 같은 프로세스를 거치게 된다.

  1. 원본 remote를 github에서 fork
  2. fork한 remote repository(origin)을 깃 클라이언트로 clone
  3. 기능을 완성할 때 까지 반복
    1. clone한 repository(local)에 commit
    2. local에서 origin으로 push
  4. upstream에 반영하기.
    1. PR을 등록하기 전 upstream에 바뀐 내용이 없는 경우
      1. origin에서 upstream으로 PR
    2. PR을 등록하기 전 upstream에 바뀐 내용이 있는 경우
      1. upstream을 local로 pull
      2. local에서 origin으로 push
      3. origin에서 upstream으로 PR

하지만 보통 pull을 바로 해버리는 것은 위험하다.

때문에 upstream의 변경사항을 미리 확인후에 그걸 반영해서 작업하는 것이 좋다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// upstream에 원본 remote 등록하기
git remote add upstream url
// upstream의 최신 commit history 반영하기
git fetch upstream main
// 베이스 갱신
git rebase upstream/main
// 충돌 사항 확인하기
git diff
// 작업하고 add하기
git add ....
// rebase 변경사항 저장하기(자신의 커밋을 반영)
git rebase --continue
// 지저분한 것들 지워주기
git reset --soft
// 컨플릭트 할 수 있는 상태가 됨
git push origin develop -f
// PR하기

Ref

https://backlog.com/git-tutorial/kr/stepup/stepup2_8.html
https://ihp001.tistory.com/229

git 변경사항 관련 커맨드

git log

커밋로그를 볼 수 있다.(커밋 메시지를 잘 적자!!)
p를 붙이면 더 자세한 정보를 볼 수 있다.

1
git log -p(선택)

git checkout

브랜치 관련 명령어지만 변경사항을 되돌리는데에도 쓰인다.

1
git checkout -- '파일명'

git diff

add 전 후의 변경사항을 알려준다.

1
git diff

git 로컬의 변경사항 취소하기!

로컬에서 작성한 변경사항을 취소하고 싶을 때 다음과 같은 명령어를 사용하여 취소할 수 있다.

별게 없지만 오늘 처음 써봤다..!

1
git restore <path>

git push시 none-fast-forward 문제 해결하기

단위별로 push하던 중에 다음과 같은 에러가 발생하였다.

1
2
3
4
5
6
! [rejected]        main -> main (non-fast-forward)
error: failed to push some refs to 'https://github.com/Deep-brain-Academy-2
hint: Updates were rejected because the tip of your current branch is behin
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

기존에 게시글로 작성하였던 git stash를 사용하여 해결하였다.

1
2
3
4
5
git add .
git commit -m "commit msg"
git stash
git pull origin main
git push origin

github pull request시 주의사항

주의사항

같은 단위의 변경사항을 커밋하고 단위마다 pull request를 보내자.

해결방안

브랜치를 신규로 생성하고 특정 commit 리버전을 그 브랜치로 merge한 후 그 브랜치를 커밋, pull request하여 수습(?)한다.

git cherry-pick을 이용할 수 있다.

ref

git 명령어 : git cherry-pick
github 원하는 commit만 pull request 보내기

Please commit your changes or stash them before you merge에러 해결하기

pull을 하였을 때 다음과 같은 에러가 발생하였다.

에러

1
2
3
4
5
6
7
8
$ git pull origin sunghyeon
From https://github.com/pshdev1030/NCRBQDTJY
* branch sunghyeon -> FETCH_HEAD
error: Your local changes to the following files would be overwritten by merge:
Programmers/Sunghyeon/다리를 지나는 트럭/README.md
Programmers/Sunghyeon/다리를 지나는 트럭/다리를 지나는 트럭.py
Please commit your changes or stash them before you merge.
Aborting

발생 이유

pull 받아오기 전에 수정해서 발생한 에러이다

내가 수정한 변경사항을 commit하거나
내가 수정한 변경사항을 merge하기 전에 stash에 임시 저장해두라는 말이다.

내 해결방안

나는 commit후에 pull을 통해 해당 에러를 해결하였다.

다른 해결방안

1
2
3
4
5
6
7
1. git stash //stash로 변경사항을 옮김
2. git pull origin 브랜치명 // 원격저장소에서 변경사항을 받아옴
3. git stash pop //내 변경사항과 원격저장소에서 pull 받은 소스가 merge됨
4. 소스 수정
5. git add .
6. git commit -m "커밋 메시지"
7. git push origin 브랜치명

ref

git stash
git stash

깃 커밋 컨벤션에 대해 알아보기

라고 호기롭게 글을 적었으나,,

여러 글을 참조하던 중 이미 예쁘게 정리해주신 분의 아티클이 있어 공유합니다.

저도 이 분처럼 처음 보는 입장에서도 쉽게 이해가 가는 예쁜 글을 적고싶어요.

갈 길이 멀어요..!

깃 커밋 컨벤션에 대해 알아보기

git flow 이해하기

gitflow는 git을 이용해 개발하는 방법론이다.

gitflow?

git flow는 5개의 branch를 사용한다.

  • main : 제품을 배포하는 branch이다. 실제 사용자가 사용하는 프로덕트의 코드가 이를 통해 배포된다.
  • release : main으로 보내기 전 검사하고 메시지를 작성하는 branch이다.
  • develop : 개발하는 branch고 개발자들이 이 branch를 기준으로 새로운 branch를 만들어 여기에 merge한다.
  • feature : 단위 기능을 개발하는 branch로 기능 개발이 끝날 경우 develop branch에 합친다.
  • hotfix : 배포후에 긴급히 수정해야할 버그가 발생했을 때 수정하는 branch이다

maindevelop가 메인으로 나머지 브랜치들은 상황에 따라 만들었다 지웠다 한다.

초기 설정

  • repo가 있어야 한다.
    github에서 repo를 만들고 초기 설정을 해준다.
레포를 생성하였다
  • git flow 초기화를 해준다.
    맨 위 두 개의 branch명만 확인하면 된다.
    기본값이 지정되어 있을 경우 엔터를 누르면 된다.
1
git flow init
git flow init
  • develop이 생성되었는지 확인한다.
    현재 gitflow 작업이 끝남에 따라 자동으로 develop 브랜치로 이동하였다.
1
git branch
branch 확인
  • 만들어진 develop을 원격 저장소에 알린다.
    로컬엔 develop가 있지만 원격저장소에선 push하기 전 까지 알 수 없다.
1
git push -u origin develop
branch push

이걸로 maindevelop은 같은 상태가 되었다.

git flow 이용하기.

git flow를 이용한 개발은 다음과 같이 이루어진다.

  1. 기능 개발을 위해선 develop에서 feature/기능명 을 만들고 작업한 후 develop에 merge한다.
  2. 여러 기능들이 각각의 feature/기능명 브랜치에서 작업이 완료되었을 경우 release에 merge하고
    부족한 점을 보완하고 버그를 픽스하고 기술문서를 작성한다.
  3. releasedevelopmain에 merge한다.
  4. main에서 버전 태그를 붙여서 배포한다.

git으로 작업한다면 상당히 복잡하지만 git flow를 통해 작업을 편하게 할 수 있다.
window기준으로 git설치시 git flow도 자동으로 설치된다. macOS의 경우 별도의 설치가 필요하다.

차례대로 진행해보자.

  1. feature/기능명 만들기
    git flow에선 다음의 커맨드를 이용하여 기능개발을 시작할 수 있다.
    나는 README라는 기능명으로 만들었다.
1
git flow feature start '기능명'
기능 개발을 시작하자

생성된 브랜치를 확인하면

1
git branch
새 브랜치가 생성되었다.

feature/'기능명'이 잘 생성된 것을 확인할 수 있다.

  1. 작업하기
    git flow에서 feature 명령어를 사용할 경우 자동으로 기능개발을 위한 branch로 이동한다.

이 상태에서 README를 임의로 수정하였다.

README를 수정했다.
  1. 기능개발 종료하기
    작업이 끝났으면 기능 개발 단위별로 변경사항을 add하고 commit 해준다. push는 하지 않아도 된다.
1
2
3
git status
git add [변경된 파일들]
git commit -m "커밋 메시지"
변경사항을 적용하기

그 후 기능개발을 끝내는 커맨드를 입력한다.
이 커맨드는 developfeature/기능명의 내용을 비교하고 변경점을 적용한 후 merge한다.

merge가 완료되면 현재 branch를 develop으로 옮긴다.
작업이 완료된 후 git branch로 확인하면 feature 기능명이 없어진 걸 확인할 수 있다.
변경사항을 develop 으로 push 해준다.
push전에 pull을 통해 최신상태로 유지해준다.

1
2
3
4
5
git flow feature finish "기능명"
git branch
git status
git pull origin develop
git push origin develop
feature branch가 사라졌다.

릴리즈하기

위 작업을 끝냈다면 develop엔 변경사항이 적용되어 있다.
릴리즈하는 명령어는 다음과 같다.
명령어 입력후 커밋 메시지를 작성할 수 있다.

1
2
git flow release start [version]
git flow release finish [version]
message 작성하기

변경사항을 main branch에도 적용하기

다음 명령어를 통해 main에 tags와 변경 사항등을 적용할 수 있다.
여기까지 했다면 main과 develop은 같은 상태로 기능 추가가 무사히 완료되었다.

1
2
3
git checkout main
git push --tags
git push origin main

느낀점

git flow는 굉장히 좋은 툴 같다.
브랜치를 만들어 작업하고 변경사항을 적용하는 것이 기존의 사용자에게 영향을 주지 않고 기능들을 추가할 수 있어 안정적이라고 생각한다.
gitflow를 이용한 협업과 프로젝트 관리도 간단히 경험해보았는데 상당히 유익한 경험이였다.
이것 또한 조만간 문서로 작성해보아야 겠다.