210129 Git TIL

Git

  • branch에 대한 개념 및 관리

    • Branch란?

      • 분기점을 생성하고 독립적으로 코드를 변경할 수 있도록 도와주는 모델이다.
    • 기본적인 Branch 관리 관련 명령어

      • 사용가능한 Local Branch를 출력
      1
      $ git branch
      • Remote Branch에 대한 정보를 출력
      1
      $ git branch -r
      • 사용가능한 모든 Branch 정보를 출력
      1
      $ git branch -a
      • 새로운 Branch 끊기
      1
      $ git branch [new branch name]
      • 새로운 Branch를 끊고, 동시에 checkout하기
      1
      $ git checkout -b [new branch name]
      • 새로 만든 Branch 로 switch 하기
      1
      $ git switch [new branch name]
      • (Additional step)merge하기 전에 새로 생성한 branch와 master branch와 비교해서 달라진 부분을 비교해야 할 필요가 있다면 아래의 명령으로 변경된 부분을 확인한다.
      1
      $ git diff master [compared branch name]
      • master branch로 다시 이동을 해서 새로 생성한 branch를 merge하도록 한다.
      1
      $ git merge [새로 생성해서 작업한 branch 이름]
      • (Additional step)만약에 새로 생성한 remote branch를 repository에 push해서 관리를 해야 한다면, 아래와 같이 명령어를 입력한다.
      1
      $ git push origin [new branch name]
      • 새로 생성된 branch에서의 모든 작업은 끝났고, merge작업까지 마무리 되었기 때문에 삭제해준다.
      1
      $ git branch -D [new branch name]

      실습내용: master branch에서 hello.py파일을 생성하고, 파일내용의 수정은 iteration branch에서 작업을 한다. 그 후에 master branch로 이동을 해서 파일이 변경되어 있지 않음을 확인한다. (파일 수정 작업은 iteration branch에서 작업을 하였기 때문)
      master branch에 새로 끊어서 작업한 iteration branch를 merge해주기 위해서 master branch로 switch하고, 새로 끊은 branch에 대해서 merge 작업을 해준다.

      case study) 별도의 branch에서 파일 변경작업을 하다가 commit을 하지 않고 main branch로 이동을 하고, 별도로 끊은 branch를 삭제한 경우, 기존에 수정된 내용이 불필요하다면(변경사항이 의도하지 않게 넘어온 경우에는), 아래의 명령을 이용해서 이동한 main branch에서 이전에 작성했던 파일을 원래 상태로 돌릴 수 있다.

      1
      2
      3
      4
      $ git checkout -- [file name]
      예시) $ git checkout -- hello.py

      cf) git의 최신버전에서는 restore를 사용해서 위의 작업을 한다.

  • Branching models의 개념과 Pros & Cons

    branch를 관리하는 모델에는 다양한 종류가 있다.

    • git flow

      • (hotfix) - master - (release) - develop - feature
      • pros : 가장 많이 적용되며, 각 단계가 명확히 구분된다.
      • cons : 관리가 복잡하다.

        master에서 바로 branch를 끊어서 수정한 다음에 바로 push해주고자 할때 hotfix branch를 사용한다.

    • github flow

      • master - feature
      • pros : branch model의 단순화ㅏ, master의 모든 commit은 deploy할 수 있다.
      • cons : CI의 의존성이 높다. pull request를 통해 실수를 방지할 수 있다.
    • gitlab flow

      • production - pre-production - master - feature
      • pros : deploy, issue에 대한 대응이 가능하도록 보완되었다.
      • cons : git flow와 순서가 반대이다.(master-develop, production-master)

  • Git flow strategy

    git flow는 git 명령어를 간소화해서 사용할 수 있는 툴이다.

    이전에 git을 사용했을때에는 새로 끊은 branch에서 merge하고자하는 branch로 switch한 다음에 merge하고 merge된 branch를 삭제하는 이 일련의 작업을 일일이 해줘야 했는데, git flow를 사용하면 start finish 명령 한 번으로 처리를 해준다. 너무 편리한 것 같다.
    그래도 구 방식의 CLI가 얼마나 번거로운지 알기 때문에 현재 git flow가 얼마나 편한지 이해가 되는 것 같다.

    (git-flow reference site)
    http://danielkummer.github.io/git-flow-cheatsheet/

    mac에서는 간단하게 brew를 사용해서 git-flow를 설치할 수 있다.

    1
    $ brew install git-flow-avh

    편하긴 하지만, 아직 명령어 사용에 익숙하지 않기 때문에, 위의 홈페이지를 참고해서 명령어에 익숙해지도록 하자. :)


  • Rebase에 대한 이해

Rebase는 새로 끊은 branch의 base를 베이스가 되는 branch의 최신 point로 분기점을 이동하는 것을 말한다.

실제로 Rebase의 사용을 선호하는 기업(배달의 민족)도 있고, 그렇기 않은 기업도 있다. Rebase를 사용하게 되면, 새로 끊은 branch의 merge commit이 없는 상태로 branch가 붙기 때문에 merge commit과 새로 끊은 branch가 어느 시점에서 pruning되었고, 어떠한 작업으로 마무리가 되었는지 세부 과정을 확인하는 것이 필요하다면, 이러한 경우에는 rebase를 사용하지 않는 것이 좋다.

  • Rebase하는 방법

    • (1) rebase하고자 하는 해당 branch에서 stage에 수정한 파일을 올리고 rebase명령을 해준다.
    1
    2
    $ git add [file]
    $ git rebase --continue
    • (2) merge하고자 하는 base branch(master branch)로 switch한 뒤에, rebasing branch를 merge시켜준다.
    1
    $ git merge rebasing
    • Collaborate with your Co-worker

    실습내용

    Practice-flow : PM(Project Manager)는 Github에 repository를 새로 파고, 팀원들은 해당 repository를 fork해서 작업을 해준다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    (PM)
    1. github에서 새로운 repo를 생성하고 내 컴에 clone 한다.
    - remote 에서 repository를 만들고 clone했기 때문에 git init을 통해 git을 초기화 해 줄 필요가 없다.
    2. git flow init 후 develop에서 numguess.py를 만들고 add, commit, push
    3. 팀원에게 알린다.

    (DEV)
    1. 알림 받은 후, 방문하여 fork 한다.
    2. 팀장 repo에 방문하여 issue를 생성한다.
    3. fork한 나의 repo를 내 컴에 clone한다.
    4. git flow init 후, dev -> feature/{MYFEATURE} 브랜칭 하여 작업한다.
    (commit 시 발급한 issue 번호 매기기)
    5. feature finish 후 나의 develop으로 push 한다.
    6. create pull request 하고 팀장에게 알린다.

    (PM)
    4. pull request를 리뷰한다.
    5. 수정할 것을 지시한다.(DEV 7. 수정사항을 반영하여 다시 add,commit,push)
    6. merge한다.

    DEV
    8. PM repo 업데이트 발생시 PM의 develop을 pull한다.

    Repository에 collaborator를 추가해서 작업 (settings - Manage access - Invite collaborator)

    • 이 방법은 추천을 하지 않는다. 그 이유는 collaborator에 추가된 사람은 해당 repository를 소유한 사람과 같이 해당 repository에 대해서 모든 권한을 가지기 때문이다.

    • 이 방법은 큰 Open source project에서 pull request를 관리하는 권한으로만 Collaborator를 추가한다.

    위의 collaborator추가를 통한 repository 공유는 추천하지 않기 때문에 대안으로 나온 방법이 Pork & Merge이다.
    구체적인 순서는 위에서 작성한 순서를 따른다.

    commit message 작성

    팀장이 팀원을 위해 Repository에 파일을 생성시,
    ex) :

    1
    2
    3
    4
    5
    6
    feat: Create index.html

    TODO
    - semantic elements
    - web standard
    - seperaate css, js files into static/

    다음에 할 일을 위와 같이 TODO와 함께 작성을 해주면, 팀원이 참고해서 일을 하게 된다.

    push upstream set option에 대한 이해

    Clone한 경우에 만약에 main branch가 아닌, 별도의 branch에서 작업을 하는 내용이라면, push할때 -u 옵션을 사용해서 remote branch를 설정해줘야 한다.

    1
    2
    예) 현재 local에서 작업하는 내용을 remote의 develop branch로 push하는 경우,
    $ git push -u origin develop

    만약에 main/master branch에서 작업을 하는 경우에는 clone시에 이미 지정되어있는 부분이기 때문에 지정해주지 않아도 된다.

    1
    $ git branch --set-upstream <remote-branch>

    위와 같이 현재 local branch에 대한 remote branch를 설정합니다.

    설정을 해주게 되면, 향후에 $git pull명령에 대해서 remote-branch에서 현재 로컬 분기로 commit된 정보를 가져옵니다.

    위와 같이 명시적으로 입력을 하지 않고 처리하는 방법으로는 push할때 -u옵션을 사용하는 것이다.
    그러면 향후 Push / Pull 시도에 대한 upstream 연결이 자동으로 설정된다.

    1
    $ git push -u origin <local-branch>
    • fork한 PM의 repository의 Issue는 코드관련해서 구성원들끼리 communication하는 장이다.

      • 만약에 할당받은 업무에 대한 catch-up message는 작성하는 본문 내용에 자세하게 작성을 해줘야 한다.(업무의 연관성에 대해서)
      • 그럼 PM은 작성한 ISSUE 내용을 보고 Assignee에 적합한 사람이라면 업무할당으르 해준다. (+Label로 구체적인 업무 구분을 해준다.)
    • Commit을 할때에는 파일단위로 나눠서 commit을 하지 말고, 기능 단위로 파일들을 묶어서 해줘야 한다. 나중에 commit을 확인한 하는 개발자가 해당 commit을 보고 이 파일들의 수정을 통해서 어떤 기능구현이 가능했었는지 알 수 있도록 하기 위해서 이다.

    • Commit을 할때에는 Issue와 Pull request는 numbering이 되는데(Issue와 Pull request는 같이 진행이 된다), 이 번호를 commit log에 Issue번호를 같이 적어주게 되면 Commit - Issue - Pull request가 서로 연결이 된다. 따라서 이 commit message만 보더라도 해당 commit이 어떤 Issue를 해결했고, 어떤 Pull request와 연관이 되어있는지 이해할 수 있게 된다.

    1
    2
    3
    4
    5
    6
    7
    feat: Seperate css, js into static/

    solved: #1 (issue number)

    path
    - static/css/style.css
    - static/js/index.js
    • 하나의 작업을 하더라도 꼭 하나의 feature를 따서 작업을 하는 습관 들이기.

    • 팀원은 master(main) branch에 접근할 필요가 없고, Release 작업은 PM의 권한을 가지고 있는 개발자가 담당한다. 개발 담당자는 develop branch까지 merge한 내용을 fork한 본인의 branch에 push를 해주면 된다.

    1
    $ git push -u origin develop

  • 프로젝트 협업시에 참고하면 좋은 꿀 Tip

    • fork한 본인의 branch에 push를 한 뒤에 pull request 작성으르 하게 되면, 본문 작성시, ‘#’ 입력과 함께 Issue에 작성했던 Issue의 title 내용이 자동완성되는 것을 확인할 수 있다.(직접입력하는 것과 동일)

    • Issue를 먼저 만들고 Pull request를 만들어주는 것이 더 모양이 좋다. (선 Issue, 후 Pull request)

    • Pull request를 한 뒤에 PM(Project Manager) developer가 comment를 달아주면 팀원 developer는 해당 내용을 확인하고, 해당 Pull request는 merge되지 않고 open된 상태이기 때문에,
      수정하는 내용은 feature branch를 따서 작업을 해도 되고, develop branch에서 바로 작업을 해줘도 된다.
      변경사항에 대해서 파일을 수정한 다음에는 이전과 동일하게 add, commit을 해주면 된다. (comment의 title은 feat:로 해서 달아주면 된다.) commit을 해주고 fork한 본인의 repository의 developer branch에 push를 해주면 된다.

    • 수정작업을 한 뒤에는 다시 Pull request를 열 필요 없이, 기존의 Pull request를 확인하면 업데이트 한 사항을 확인할 수 있다.
      (Pull request를 안닫아주면, develop branch에서 작업한 다른 모든 내용들이 전부 open되어있는 pull request에 쌓이게 된다. 따라서 PM은 빨리 Pull request를 확인해서 닫아줘야 한다)

    • 다른 팀원들은 미리 PM의 remote를 별도로 등록해줘야 한다. 나중에 다른 팀원들의 내용이 PM의 repository에 merge된 후에 해당 내용을 당겨서 받아야 되기 때문에, 미리 등록을 해두는 것이 좋다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    $ git remote add pmorigin [PM Repository address]

    //연결되어있는 remote branch 확인 (origin, pmorigin)
    $ git remote -v

    $ git pull pmorigin develop

    //팀장은 본인(origin)의 repository 정보를 pull해주면 된다.
    $ git pull origin develop

(2021.02.22 업데이트)

로컬에서 작업중인 특정 파일을 수정 이전의 상태로 되돌리기(undo)

1
$ git checkout -- [target file]

(2021.05.25 업데이트)

local에서 commit한 내용 되돌리기

Git에서 이력을 되돌리는 방법에는 두 가지가 있는데, 바로 ResetRevert이다.

Reset은 시계를 다시 맞추는 것 처럼 돌아가려는 특정 commit 시점으로 재설정하고, 해당 commit 시점 이후의 이력은 사라지게 된다.

1
$ git reset <option> <return commit point>

option에는 hard, mixed, soft 세 가지가 있다.

우선 hard의 경우에는 돌아가려는 이력이후의 모든 내용을 지워버린다.

1
2
# 예시 a3bbb1c 시점으로 commit 시점을 되돌리고, 이후의 이력들은 삭제한다.
$ git reset --hard a3bbb1c

반면에 soft 옵션의 경우에는 돌아가려는 시점의 이력으로 되돌린다는 점에서는 hard 옵션과 같지만, 이후의 이력내용들은 지워지지 않고, 해당 내용의 index(or stage)는 그대로 존재하며, stage에 올라가 있는 상태이다.
따라서 바로 다시 commit을 할 수 있는 상태로 남아있다.

1
2
# 예시 a3bbb1c 시점으로 commit 시점을 되돌리고, 이후의 이력들은 남겨둔다.(stage에 올라가 있는 상태)
$ git reset --soft a3bbb1c

마지막으로 설명할 옵션인 mixed은 특정 option을 지정하지 않은 경우 적용되는 option이다.
이 옵션은 앞의 두 옵션과 같이 이력이 되돌려지지만, 이후의 이력들은 남겨둔다. soft 옵션과 다른 점은 남겨진 이력들이 stage에 올라가 있지 않고, commit을 하기 위해서는 변경된 내용을 stage 추가해야 되는 상태이다.

또한 되돌아가는 commit을 commit hash를 통해서 직접 지정을 할 수도 있고, 현재시점부터 몇 개의 커밋을 되돌릴 수 있다.

아래와 같이 입력을 하면 1개 이전의 이력으로 되돌아가며, 5개 이전의 이력으로 되돌리고 싶은 경우에는 HEAD~5와 같이 입력을 해주면 된다.

1
$ git reset HEAD~1

다음으로 정리할 내용은 Revert에 대한 내용이다.
Revert도 Reset과 마찬가지로 상태를 되돌린다는 특징을 가지고 있다. revert하고 현재 작성중인 코드를 보면 hard option을 제외한 옵션으로 reset을 한 것과 동일한 결과를 갖는다.
하지만 세부 이력을 살펴보면, 같지 않음을 알 수 있다.

reset으로 이력을 되돌린 경우에는 이전 이력들에 대한 내용이 stage에 올라가거나(soft) 올라가지 않은(mixed) 상태로 남아있지만, revert를 한 경우에는 이전에 commit한 이력들이 그대로 남아있는 상태에서 특정 commit 시점으로 되돌아간 상태가 된다. 되돌아간 commit 시점에 해당하는 내용만 삭제가 되고, 이후의 commit 내용들은 그대로 남아있게 된다.

1
2
# revert 예시
$ git revert a3bbb1c

만약에 되돌릴 commit이 여러개인 경우에는 범위를 줘서 revert를 할 수 있다. (reset의 기능과 같이 revert를 사용하고 싶다면 구간을 지정해서 revert를 해주면 된다)

1
2
# 범위를 지정해서 revert
$ git revert a3bbb3c..e10665e

reset과 revert 사용

만약에 이력들 중에 특정 commit만 취소하고 싶은 경우에는 reset을 사용해서 이후의 이력을 모두 제거하기 보다는 revert를 사용해서 해당 commit의 내용만 되돌리는 편이 좋다.
또한 이미 remote repository에 push를 한 경우에는 reset을 사용하게 되면, reset하기 이전으로 되돌리기 전까지 push를 할 수 없게 된다. (force 옵션의 사용을 제외)
따라서 이미 remote repository에 push를 한 상태라면, revert를 사용해서 이력을 되돌려야 한다.

revert를 사용하게 되면 특정 이력으로 되돌아감과 동시에 새로운 rollback에 대한 이력도 남기게 됨으로 좀 더 안전한 방법으로 생각될 수 있다. 특정 commit 시점으로 revert를 하게 되면, 해당 시점 이후의 commit들이 삭제되는 것이 아닌, 되돌아간 commit의 시점에 해당하는 내용만 삭제가 된다. (삭제된 내용은 별도의 revert commit 메시지로 남긴다)

그리고 혼자 사용하는 브랜치가 아닌 경우나 reset이후에 삭제될 commit들 중에 다른 사람이 작성한 commit이 있는 경우에는 revert를 사용해서 이력을 되돌려야 한다.