4 협업

source: categories/study/git-beginner/git-beginner4.md

4.1 stash

  • 작업 하던 내용을 임시 저장
  • 브랜치에서 작업하다가 다른 브랜치로 변경해야 하는데 커밋은 하고 싶지 않은 경우
    이런 경우 로컬에 임시 저장을하는 것이 stash입니다.
    작업하던 파일이라함은 Modified 상태의 파일이라던가 Staged 상태인 파일을 말합니다.
    즉, 아직 커밋을 하지 않은 내 로컬에서 작업을 하던 파일들을 말하는 것입니다.
  • stack처럼 작동
    가장 마지막에 들어간 것이 가장 먼저나오는 식으로 동작합니다.
  • stash, pop을 많이 사용
  • 실습

      vi README.md (vi 편집기를 활용해 README.md 파일 수정)
    

    파일을 수정한 후 status 확인.

      git st
        
      ---
        
      On branch master
      Your branch is up to date with 'origin/master'.
        
      Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git checkout -- <file>..." to discard changes in working directory)
        
      modified: README.md
        
      no changes added to commit (use "git add" and/or "git commit -a")
    

    위 상태에서 git stash를 하면 modified 상태인 README.md가 저장이됩니다.

      git stash
      Saved working directory and index state WIP on master: 4f41a43 Modify README.md
    
      git st
        
      ---
        
      On branch master
      Your branch is up to date with 'origin/master'.
        
      nothing to commit, working tree clean
    

    위와 같이 modified 상태였던 파일이 사라진 걸 볼 수 있습니다.
    stash한 파일이 어디있는지 확인하는 명령어는 git stash list 입니다.

      git stash list
        
      ---
        
      stash@{0}: WIP on master: 4f41a43 Modify README.md
    
      vi README.md (vi 편집기를 활용해 README.md 파일을 한번 더 수정)
    
      git st
        
      ---
        
      On branch master
      Your branch is up to date with 'origin/master'.
        
      Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git checkout -- <file>..." to discard changes in working directory)
        
      modified: README.md
        
      no changes added to commit (use "git add" and/or "git commit -a")
    
      git stash
      Saved working directory and index state WIP on master: 4f41a43 Modify README.md
    
      git stash list
        
      ---
        
      stash@{0}: WIP on master: 4f41a43 Modify README.md
      stash@{1}: WIP on master: 4f41a43 Modify README.md
    
      git stash pop  (가장 마지막에 stash했던 내용들이 빠져나와 적용됨)
    
      git stash list
        
      ---
        
      stash@{0}: WIP on master: 4f41a43 Modify README.md
    
      git stash pop
        
      ---
        
      error: Your local changes to the following files would be overwritten by merge:
        
      README.md
        
      Please commit your changes or stash them before you merge.
      Aborting
    

    같은 파일을 고쳤기 때문에 충돌이 났습니다.
    변경된 내용을 먼저 커밋을 하거나 스테시를 해라. 라고 알려주고 있습니다.

      git ci -am 'pop 테스트'
      [master 1833e8f] pop 테스트
      1 file changed, 1 insertion(+)
    
      git stash pop
      git ci -am 'stash 실습'
      git st
        
      ---
        
      On branch master
      Your branch is ahead of 'origin/master' by 2 commits.
      (use "git push" to publish your local commits)
        
      nothing to commit, working tree clean
    
  • apply, drop 등의 옵션이 있음

    • apply: stack에 쌓여있는 것 중에 적용하고싶은 것을 골라서 적용할 수 있게 해줍니다.
    • drop: stack에 쌓여있는 것을 지우는 명령어.

4.2 merge

  • 협업의 핵심. 다른 브랜치와 현재 브랜치를 합쳐서 코드를 합침
  • 방식

    • fast-forward

      • 커밋들이 공통이고 대상 브랜치의 커밋만 증가 했을 경우 단순히 HEAD만 옮겨짐
        git co -b feature/a
        git lg
              
        ---
              
        * 24a6271 - (73 seconds ago) fast-forward exer - Country (origin/master)
        * 8788377 - (36 minutes ago) stash 실습 - Country (HEAD -> feature/a, master)
        * 1833e8f - (37 minutes ago) pop 테스트 - Countr
        ...
      
        git merge origin/master
              
        ---
              
        Updating 8788377..24a6271
        Fast-forward
        README.md | 4 ++++
        1file changed, 4 insertions(+)
      
        git lg
              
        ---
              
        * 24a6271 - (73 seconds ago) fast-forward exer - Country (HEAD -> feature/a, origin/master)
        * 8788377 - (36 minutes ago) stash 실습 - Country (master)
        * 1833e8f - (37 minutes ago) pop 테스트 - Countr
        ...
      

      이것이 fast-forward 방식입니다.
      단순히 HEAD의 위치를 최신으로 옮기는 방식입니다.

    • 3-way Merge

      • 두 갈래로 나온 변경들을 합쳐서 새로운 커밋을 만듦
        같은 파일을 수정했더라도 다른 줄을 수정했다면, 충돌 안일어나고 merge

      • conflict
        같은 파일 같은 줄을 수정하면 merge할 때 conflict 발생

          git merge origin/master
          git status
                    
          ---
                    
          On branch feature/a
          You have unmerged paths.
          (fix confilicts and run "git commit")
          (use "git merge --abort" to abort the merge)
                    
          Unmerged paths:
          (use "git add <file>..." to mark resolution)
                    
          both modified: README.md
                    
          no changes added to commit (use "git add" and/or "git commit -a")
        
          vi README.md
                    
          ---
                    
          ...
          <<<<<<< HEAD
          - fast-forward exer / my merge test
          =======
          - fast-forward exer / conflict test
          >>>>>>> origin/master
          ...
        
          git ci -am 'resolve conflict when merge'
        
    • squash

      • 대상 브랜치의 커밋들을 하나의 커밋으로 합쳐서 merge
      • git merge --squash master
  • 실습

    • 상황: 다른 사람이 master에서 같은 파일을 고침

4.3 rebase1

rebase는 크게 두가지 기능을 합니다.

  1. 다른 브랜치와 병합 (3.6 Git 브랜치 - Rebase 하기)

    • 기능은 merge와 같음 (코드를 합침)

      merge로 합쳤을 땐 위와 같이 갈래가 나뉘어지는데 rebase로 합치면 fast-forward 방식으로 합쳐진것 마냥 갈래가 안나뉘어집니다.
      이는 실습하면서 보도록 하겠습니다.

    • 내 브랜치의 커밋을 대상 브랜치의 위(다음)으로 생성함
    • 깔끔한 로그를 유지할 수 있음
    • 실습

      • 상황: master의 변경들을 feature/c에서 rebase 해본다

        • 대상 브랜치의 커밋만 진행 (fast-forward)

            git br
                          
            ---
                          
              develop
            * master
          
            git lg
                          
            ---
                          
            4e06e1a - (22 hours ago) conflict test - Country (HEAD -> master, origin/master)
            73f4e09 - (22 hours ago) 3-way merge other - Country
            24a6271 - (22 hours ago) fast-forward exer - Country
            ...
          
            git br feature/c
          

          이 상태에서 master 브랜치에서 커밋을 몇번 진행한 다음에 feature/c 브랜치로 rebase하도록 하겠습니다.
          이같은 경우는 위에서 보여드린 fast-forward merge와 똑같습니다.

            vi README.md
            git ci -am 'rebase fast-forward'
            git lg
                          
            ---
                          
            c925bd6 - (1 second ago) rebase fast-forward - Country (HEAD -> master)
            4e06e1a - (22 hours ago) conflict test - Country (origin/master, feature/c)
            73f4e09 - (22 hours ago) 3-way merge other - Country
            24a6271 - (22 hours ago) fast-forward exer - Country
            ...
          
            git co feature/c
            git rebase master
                          
            ---
                          
            First, rewinding head to replay your work on top of it...
            Fast-forwarded feature/c to master.
          
            git lg
                          
            ---
                          
            c925bd6 - (32 seconds ago) rebase fast-forward - Country (HEAD -> feature/c, master)
            4e06e1a - (22 hours ago) conflict test - Country (origin/master)
            73f4e09 - (22 hours ago) 3-way merge other - Country
            24a6271 - (22 hours ago) fast-forward exer - Country
            ...
          

          지난번 fast-forward merge와 똑같습니다.

        • 두 브랜치 모두 커밋이 있지만 충돌이 나지 않음 (auto merging)
          이번엔 각 두 브랜치 모두 커밋이 있지만 충돌이 나지않는 auto merging 상태를 보겠습니다.
          같은 파일을 수정했더라도 다른 줄을 수정했을 경우, 아니면 서로 다른 파일을 수정했을 경우.

            git co master
            vi README.md
            git ci -am 'master rebase auto merge'
            git co feature/c
            vi README.md
            git ci -am 'feature/c rebase auto merge'
            git lg
                          
            ---
                          
            1e6a9c1 - (2 seconds ago) feature/c rebase auto merge - Country (HEAD -> feature/c)
            | a79a82c - (29 seconds ago) master rebase auto merge - Country (master)
            |/
            c925bd6 - (32 seconds ago) rebase fast-forward - Country
            4e06e1a - (22 hours ago) conflict test - Country (origin/master)
            73f4e09 - (22 hours ago) 3-way merge other - Country
            24a6271 - (22 hours ago) fast-forward exer - Country
            ...
          

          위 상태에서 merge 명령어를 통해 합치면 그래프의 갈래가 갈라져서 찍힐텐데 rebase는 다릅니다.

            git rebase master
                          
            ---
                          
            First, rewinding head to replay your work on top of it...
            Applying: feature/c rebase auto merge
          
            git lg
                          
            ---
                          
            e47ddc0 - (2 seconds ago) feature/c rebase auto merge - Country (HEAD -> feature/c)
            a79a82c - (29 seconds ago) master rebase auto merge - Country (master)
            c925bd6 - (32 seconds ago) rebase fast-forward - Country
            4e06e1a - (22 hours ago) conflict test - Country (origin/master)
            73f4e09 - (22 hours ago) 3-way merge other - Country
            24a6271 - (22 hours ago) fast-forward exer - Country
            ...
          

          merge때처럼 그래프가 합쳐져서 새로운 커밋이 생기는 것이 아니라 위와 같이 단순히 기록이 하나 더 쌓이는 식으로 merge되는 것을 볼 수 있습니다.
          rebase하기 전에 커밋 해시키가 1e6a9c1 이거였지만 rebase하고나면 e47ddc0로 바뀝니다. 즉, 커밋을 다시해서 쌓아올리는 것과 같습니다.

        • 두 브랜치 모두 커밋이 있고 충돌이 남 (conflict)
          현재 feature/c 브랜치입니다.
          같은 파일 같은 줄을 수정해 충돌이 일어나게합니다.

            git lg
                          
            ---
                          
            e47ddc0 - (2 seconds ago) feature/c rebase auto merge - Country (HEAD -> feature/c)
            a79a82c - (29 seconds ago) master rebase auto merge - Country (master)
            c925bd6 - (32 seconds ago) rebase fast-forward - Country
            4e06e1a - (22 hours ago) conflict test - Country (origin/master)
            73f4e09 - (22 hours ago) 3-way merge other - Country
            24a6271 - (22 hours ago) fast-forward exer - Country
            ...
          
            git co master
            git rebase feature/c
                          
            ---
                          
            e47ddc0 - (2 seconds ago) feature/c rebase auto merge - Country (HEAD -> master, feature/c)
            a79a82c - (29 seconds ago) master rebase auto merge - Country
            c925bd6 - (32 seconds ago) rebase fast-forward - Country
            4e06e1a - (22 hours ago) conflict test - Country (origin/master)
            73f4e09 - (22 hours ago) 3-way merge other - Country
            24a6271 - (22 hours ago) fast-forward exer - Country
            ...
          
            vi README.md
            git ci -am 'master rebase conflict'
            git co feature/c
            vi README.md
            git ci -am 'feature/c rebase conflict'
            git lg
                          
            ---
                          
            02cb0c3 - (1 seconds ago) feature/c rebase conflict - Country (HEAD -> feature/c)
            | 314e412 - (22 seconds ago) master rebase conflict - Country (master)
            |/
            e47ddc0 - (2 seconds ago) feature/c rebase auto merge - Country
            a79a82c - (29 seconds ago) master rebase auto merge - Country
            c925bd6 - (32 seconds ago) rebase fast-forward - Country
            4e06e1a - (22 hours ago) conflict test - Country (origin/master)
            73f4e09 - (22 hours ago) 3-way merge other - Country
            24a6271 - (22 hours ago) fast-forward exer - Country
            ...
          
            git rebase master
                          
            ---
                          
            First, rewinding head to replay your work on top of it...
            Applying: feature/c rebase conflict
            Using index info to reconstruct a base tree...
            M     README.md
            Falling back to patching base and 3-way merge...
            Auto-merging README.md
            CONFLICT (content): Merge conflict in README.md
            error: Failed to merge in the changes.
            Patch failed at 0001 feature/c rebase conflict
            Use 'git am --show-current-patch' to see the failed patch
                          
            Resolve all conflict manually, mark them as resolved with                         (충돌을 해결하고 mark를 해라)
            "git add/rm <conflicted_files>", then run "git rebase --continue".                (add 또는 rm(삭제)로 mark를 하라는 것, 그리고난 다음에 git rebase --continue를 해라.)
            You can instead skip this commit: run "git rebase --skip".                        (또는 너는 skip을 할 수 있다. git rebase --skip 명령어를 통해)
            To abort and get back to the state before "git rebase", run "git rebase --abort". (또는 되돌리고 싶다면 git rebase --abort 명령어를 실행하면된다.)
          
          • --abort: rebase를 중단. 원래 상태로 돌아감
          • --continue: 충돌난 파일들을 add 또는 rm으로 표시한 다음에 rebase를 계속 진행. 다음 단계로 넘어감
          • --skip: 대상 브랜치의 내용으로 적용
            git st
                          
            ---
                          
            rebase in progress; onto 314e412
            You are currently rebasing branch 'feature/c' on '314e412'.
              (fix conflicts and then run "git rebase --continue")
              (use "git rebase --skip" to skip this patch)
              (use "git rebase --abort" to check out the original branch)
                            
            Unmerged paths:
              (use "git reset HEAD <file>..." to unstage)
              (use "git add <file>..." to mark resolution)
                            
                both modified: README.md
                              
            no changes added to commit (use "git add" and/or "git commit -a")
          
            git rebase --abort
            git st
                          
            ---
                          
            nothing to commit, working tree clean
          

          이렇게 --abort를 하면 rebase 명령어를 실행하기 전으로 돌아갈 수 있습니다.
          이 상황에서 다시 rebase를 해보겠습니다.

            git rebase master
                          
            ---
                          
            First, rewinding head to replay your work on top of it...
            Applying: feature/c rebase conflict
            Using index info to reconstruct a base tree...
            M     README.md
            Falling back to patching base and 3-way merge...
            Auto-merging README.md
            CONFLICT (content): Merge conflict in README.md
            error: Failed to merge in the changes.
            Patch failed at 0001 feature/c rebase conflict
            Use 'git am --show-current-patch' to see the failed patch
                          
            Resolve all conflict manually, mark them as resolved with                         (충돌을 해결하고 mark를 해라)
            "git add/rm <conflicted_files>", then run "git rebase --continue".                (add 또는 rm(삭제)로 mark를 하라는 것, 그리고난 다음에 git rebase --continue를 해라.)
            You can instead skip this commit: run "git rebase --skip".                        (또는 너는 skip을 할 수 있다. git rebase --skip 명령어를 통해)
            To abort and get back to the state before "git rebase", run "git rebase --abort". (또는 되돌리고 싶다면 git rebase --abort 명령어를 실행하면된다.)
          

          아까랑 똑같이 충돌이 나겠죠?
          이번엔 충돌을 다 해결한 다음에 --continue를 해보도록 하겠습니다.

            vi README.md
                          
            ---
                          
            ...
            <<<<<<< HEAD
            master - rebase conflict
            =======
            feature/c rebase conflict
            >>>>>>> feature/c rebase conflict
            ...
          

          충돌난 부분을 수정을하고..

            git add README.md
          

          이때 중요한점은 add만 하셔야됩니다. 커밋을 하시면 안됩니다.
          위와 같이 add를 하시고 상태를 보면..

            git st
                          
            ---
                          
            rebase in progress; auto 314e412
            You are currently rebasing branch 'feature/c' on '314e412'.     (넌 지금 rebase 중이야)
              (all conflicts fixed: run "git rebase --continue")            (충돌이 해결됐다면 git rebase --continue 명령어를 실행해)
                            
            Changes to be committed:
              (use "git reset HEAD <file>..." to unstage)
                            
                modified: README.md
          
            git rebase --continue
                          
            ---
                          
            Applying: feature/c rebase conflict
          
            git lg
                          
            ---
                          
            0c05019 - (4 minutes ago) feature/c rebase conflict - Country (HEAD -> feature/c)
            314e412 - (22 seconds ago) master rebase conflict - Country (master)
            e47ddc0 - (2 seconds ago) feature/c rebase auto merge - Country
            a79a82c - (29 seconds ago) master rebase auto merge - Country
            c925bd6 - (32 seconds ago) rebase fast-forward - Country
            4e06e1a - (22 hours ago) conflict test - Country (origin/master)
            73f4e09 - (22 hours ago) 3-way merge other - Country
            24a6271 - (22 hours ago) fast-forward exer - Country
            ...
          

          충돌 해결 후 rebase를 하면 위와 같이 깔끔하게 커밋 기록들이 쌓인 것을 확인할 수 있습니다.

  2. 커밋 여러개 수정하기
    커밋은 한 작업 단위별로 커밋을 한다고 했습니다.
    그리고 하나하나의 커밋들이 모여 로그를 만듭니다.
    그런데 그 커밋을 수정하는 기능이 rebase입니다.

    • 주의

      • push해서 누군가 사용하고 있는 커밋을 rebase 하면 안됨 (헬게이트가 열림)
      • 왜냐하면 누군가는 그 해당 커밋을 기반으로 작업을 했을 텐데 그 기반을 바꿔 버리는 것이기 때문.
        그렇게되면 서로 충돌이 일어나고 엄청 무시무시한 일이 발생하게될 것.
      • push를 했더라도 아직 merge되지 않았고 다른 사람이 사용하지 않는 브랜치라면 (보통 feature 브랜치) 마음대로 rebase를 해도 무방
    • -i: 대화형 모드
      대화형 모드를 사용하며 rebase를 해볼겁니다.

    • 가장 위에 있는 커밋이 오래된 것 (git st와 반대)
      git status는 가장 옛날게 밑에있고 가장 최신이 위에 있는데 rebase 대화 명령창에서는 제일 최근 것이 아래에있고 가장 옛날게 위로옵니다.

    • 옵션

      • --abort : rebase를 중단. 원래 상태로 돌아감
      • --continue : rebase를 계속 진행. 다음 단계로 넘어감
      • --skip : 대상 브랜치의 내용으로 적용
    • 커밋 목록에서의 옵션

      • p, pick = use commit
      • r, reword = use commit, but edit the commit message
      • e, edit = use commit, but stop for amending
      • s, squash = use commit, but meld into previous commit
      • f, fixup = like "squash", but discard this commit's log message
      • x, exec = run command (the rest of the line) using shell

      저희는 간단히 f, 즉, fixup 옵션만 사용하도록 하겠습니다.

    • 실습

      • 상황: 커밋 하나를 한 뒤, 오타가 있어서 추가 커밋을 함. 그리고 추가 작업까지 한 상태
        그럼 총 3개의 커밋이 생길 것이고, 그 상황에서 3개의 커밋을 수정해보도록 하겠습니다.

          git co master
          git br -D feature/c
          git lg
                    
          ---
                    
          314e412 - (22 seconds ago) master rebase conflict - Country (HEAD -> master)
          e47ddc0 - (2 seconds ago) feature/c rebase auto merge - Country
          a79a82c - (29 seconds ago) master rebase auto merge - Country
          c925bd6 - (32 seconds ago) rebase fast-forward - Country
          4e06e1a - (22 hours ago) conflict test - Country (origin/master)
          73f4e09 - (22 hours ago) 3-way merge other - Country
          24a6271 - (22 hours ago) fast-forward exer - Country
          ...
        
          vi README.md
          git ci -am 'rebase 1.'
          vi README.md
          git ci -am 'rebase 2.'
          vi README.md
          git ci -am 'rebase 3.'
          git lg
                    
          ---
                    
          613f574 - (2 seconds ago) rebase 3. - Country                             -|
          666cabf - (19 seconds ago) rebase 2. - Country                             |- 이 3개의 커밋을 합치고 싶습니다.
          ffc33d2 - (49 seconds ago) rebase 1. - Country                            -|  의미없는 커밋들이 많은 것도 안좋기 때문에 이 3개의 커밋은 합쳐도되는 상황이라고 해봅시다.
          314e412 - (22 seconds ago) master rebase conflict - Country (HEAD -> master)
          e47ddc0 - (2 seconds ago) feature/c rebase auto merge - Country
          a79a82c - (29 seconds ago) master rebase auto merge - Country
          c925bd6 - (32 seconds ago) rebase fast-forward - Country
          4e06e1a - (22 hours ago) conflict test - Country (origin/master)
          73f4e09 - (22 hours ago) 3-way merge other - Country
          24a6271 - (22 hours ago) fast-forward exer - Country
          ...
        
          git rebase -i @~3    // <-- @는 HEAD와 똑같습니다. ~3은 최신 3개의 커밋을 수정하겠다 라는 뜻입니다.
        

        위와 같이 명령어를 실행하면

          pick ffc33d2 rebase 1.
          pick 666cabf rebase 2.
          pick 613f574 rebase 3.
                    
          # Rebase 314e412..613f574 onto 314e412 (3 commands)
          #
          # ...
        

        가장 오래된 커밋이 제일 위에있고 가장 최신 커밋이 아래에 있습니다.
        status랑 반대로 되어있습니다.
        이 상황에서 저희가 해볼 것은 f, 즉, fixup입니다.
        fixup은 squash를 하는데 커밋 메시지까지 버려버립니다. (커밋 여러개를 합치니까 메시지는 유지할 수가 없지)

          pick ffc33d2 rebase 1.
          f 666cabf rebase 2.
          f 613f574 rebase 3.
                    
          # Rebase 314e412..613f574 onto 314e412 (3 commands)
          #
          # ...
        

        위와 같이 2번째 커밋과 3번째 커밋을 f로 하고 저장을해서 종료합니다.

          git lg
                    
          ---
                    
          c2bb430 - (3 seconds ago) rebase 1. - Country (HEAD -> master)
          314e412 - (22 seconds ago) master rebase conflict - Country 
          e47ddc0 - (2 seconds ago) feature/c rebase auto merge - Country
          a79a82c - (29 seconds ago) master rebase auto merge - Country
          c925bd6 - (32 seconds ago) rebase fast-forward - Country
          4e06e1a - (22 hours ago) conflict test - Country (origin/master)
          73f4e09 - (22 hours ago) 3-way merge other - Country
          24a6271 - (22 hours ago) fast-forward exer - Country
          ...
        

        확인해보면 3개의 커밋이 아닌 1개의 커밋밖에 남아있지 않은 것을 확인하실 수 있습니다.

          cat README.md
        

        README.md 파일을 확인해보면 3개 커밋의 모든 내용이 다 들어가있는 것을 확인할 수 있습니다.

4.4 pull request 실습

pull request는 앞글자만따서 pr이라고 많이 부르는데, 이 pr은 Git 자체 기능이 아니라 GitHub에서 제공하는 기능입니다.
실무에선 GitHub을 사용해 pr을 올립니다.
왜냐하면 그 과정에서 코드리뷰도하고 코드 분석을 한다던지, 테스트 등의 검증과정이 다 끝난 다음에 코드를 합치도록 하게하기 위해서 pr을 활용하고 있습니다.

  • 상황1: conflict 발생하지 않음

    • feature/d 브랜치에서 commit & push

        git co -b feature/d
        vi README.md
        git ci -am 'pr exer'
        git push
              
        ---
              
        fatal: The current branch feature/d has no upstream branch.
        To push the current branch and set the remote as upstream, use
              
          git push --set-upstream origin feature/d
      
        git push --set-upstream origin feature/d
      

      위의 올린 원격저장소로 가서 보시면 feature/d 브랜치가 올라온 것을 보실 수 있을겁니다.

      그럼 여기서 compare & pull request 버튼을 누르시면됩니다.

      feature/d 브랜치에서 master 브랜치로 합칠건데, 위 사진 보시면 Able to merge 합칠 수 있는 상태라고 나옵니다.
      그리고 제목엔 저희가 작성한 커밋 메시지가 나오고, 추가적으로 필요한 내용들은 Leave a comment 부분에 남기시면 됩니다.
      오른쪽에 caption (Reviewers, Assignees 등) 이런 것도 활용하면 실무에서 유용하게 쓸 수 있습니다.

      Assignees 설정해보고.. Labels는 해당 pr이 어떤 내용을 담고있는지 표시해주는 역할입니다.

      아래 보시면 이렇게 바뀐 내용들도 확인할 수 있습니다.

      이렇게 pr을 올리면 pull request 탭에서 pr이 하나 생겼고, 이 pr을 다른 누군가가 보고 코드리뷰도하고 그럴 수 있는 것입니다.

      코드리뷰도 끝났고 그런 상태에서 위의 Merge pull request 버튼을 누르면, feature/d 브랜치가 master 브랜치로 합쳐지게됩니다.
      지금 상태를 확인해보면

        git lg
              
        ---
              
        2977241 - (1 seconds ago) pr exer - Country (HEAD -> feature/d, origin/feature/d)
        c2bb430 - (3 seconds ago) rebase 1. - Country (origin/master, master)
        314e412 - (22 seconds ago) master rebase conflict - Country 
        e47ddc0 - (2 seconds ago) feature/c rebase auto merge - Country
        a79a82c - (29 seconds ago) master rebase auto merge - Country
        c925bd6 - (32 seconds ago) rebase fast-forward - Country
        4e06e1a - (22 hours ago) conflict test - Country (origin/master)
        73f4e09 - (22 hours ago) 3-way merge other - Country
        24a6271 - (22 hours ago) fast-forward exer - Country
        ...
      

      위 상태에서 위의 Merge pull request 버튼을 눌러 merge를 하게되면, 해당 pr은 merged 즉, 머지가 되었다고 나오고

      master에서 합쳐진 내용들을 확인할 수 있습니다.

        git co master
        git pull
        git lg
              
        ---
              
        87a0d74 - (31 seconds ago) Merge pull request #1 from hyungju-lee/feature/d - country (HEAD -> master, origin/master)
        | 2977241 - (1 seconds ago) pr exer - Country (origin/feature/d, feature/d)
        |/ 
        c2bb430 - (3 seconds ago) rebase 1. - Country (origin/master, master)
        314e412 - (22 seconds ago) master rebase conflict - Country 
        e47ddc0 - (2 seconds ago) feature/c rebase auto merge - Country
        a79a82c - (29 seconds ago) master rebase auto merge - Country
        c925bd6 - (32 seconds ago) rebase fast-forward - Country
        4e06e1a - (22 hours ago) conflict test - Country (origin/master)
        73f4e09 - (22 hours ago) 3-way merge other - Country
        24a6271 - (22 hours ago) fast-forward exer - Country
        ...
      
  • 상황2: conflict 발생 > 로컬에서 해결하고 다시 push

    • master 브랜치에서 README 파일 변경 commit & push
    • feature/e 브랜치에서 README 파일 변경 commit & push

        git co -b feature/e
        vi README.md
        git ci -am 'feature pr conflict'
        git push
              
        ---
              
        fatal: The current branch feature/d has no upstream branch.
        To push the current branch and set the remote as upstream, use
              
          git push --set-upstream origin feature/e
      
        git push --set-upstream origin feature/e
      
        git co master
        vi README.md (충돌이 나게하려면 같은 줄에 수정)
        git ci -am 'master pr conflict'
        git lg
              
        ---
              
        e9284f0 - (8 seconds ago) master pr conflict - Country (HEAD -> master, origin/master)
        | 60f6d0c - (20 seconds ago) feature pr conflict - Country (origin/feature/e, feature/e)
        |/
        87a0d74 - (31 seconds ago) Merge pull request #1 from hyungju-lee/feature/d - country
        |\
        | 2977241 - (1 seconds ago) pr exer - Country (origin/feature/d, feature/d)
        |/ 
        c2bb430 - (3 seconds ago) rebase 1. - Country (origin/master, master)
        314e412 - (22 seconds ago) master rebase conflict - Country 
        e47ddc0 - (2 seconds ago) feature/c rebase auto merge - Country
        a79a82c - (29 seconds ago) master rebase auto merge - Country
        c925bd6 - (32 seconds ago) rebase fast-forward - Country
        4e06e1a - (22 hours ago) conflict test - Country (origin/master)
        73f4e09 - (22 hours ago) 3-way merge other - Country
        24a6271 - (22 hours ago) fast-forward exer - Country
        ...
      

      이 상태에서 pr을 해보도록 하겠습니다.

      이번에는 Can't autumatically merge라고 떴습니다.
      이 말은 즉, 자동으로 머지할 수 없다 라는 뜻입니다.
      하지만 그래도 Don't worry, you can still create the pull request. 여전히 pr은 올릴 수 있다고합니다.
      이 상태에서 pr을 올리면

      이렇게 충돌이 발생하여 자동으로 머지를 할 수 없는 상태입니다.
      아까는 바로 Merge pull request 버튼을 누를 수 있었는데 지금은 비활성화되어있고 Resolve conflicts 버튼이 활성화되어있습니다.

      여기서 주의사항이 Resolve conflicts 이 기능은 웬만하면 사용하시지 않는 것이 좋습니다.

      왜냐하면 Resolve conflicts 이 기능은 깃헙에서 제공하는 기능인데, 웹에서 진행돼서 코드 편집기의 도움을 받을 수도 없고
      Resolve conflicts 이 과정을 통하면 자연스럽게 master 브랜치를 feature/e 브랜치로 머지를하고,
      그 다음에 충돌을 해결하고 다시 master로 머지를 하는..

      그렇기 때문에 정확히 어떻게 돌아가는지 눈으로보기도 힘들고, 무엇보다도 master 브랜치를 feature/e 브랜치로 머지해선 안되는 상황도 있을겁니다.
      이런 여러가지 상황을 고려했을 때 pr을 했을 때 conflicts가 발생하면 여기서 Resolve conflicts 이걸 눌러서 conflicts를 해결하는 것이 아니라
      로컬에 돌아와서 conflicts를 해결하는 것을 추천드립니다.

      Resolve conflicts 버튼 누르면 어떻게 되는건지만 보도록 하겠습니다.

      위에서 수정을하고 Mark as resolved 버튼을 눌러서 수정해도 됩니다.
      하지만 이 기능은 웬만하면 추천드리진 않습니다~!
      로컬에서 수정해봅시다.

        git co feature/e
      

      feature/e 브랜치를 체크아웃한 상태에서 master 브랜치를 머지하거나 rebase 해야됩니다.
      rebase를 한번 해보도록 하겠습니다.

        git rebase master
              
        ---
              
        First, rewinding head to replay your work on top of it...
        Applying: feature/c rebase conflict
        Using index info to reconstruct a base tree...
        M     README.md
        Falling back to patching base and 3-way merge...
        Auto-merging README.md
        CONFLICT (content): Merge conflict in README.md
        error: Failed to merge in the changes.
        Patch failed at 0001 feature/c rebase conflict
        Use 'git am --show-current-patch' to see the failed patch
              
        Resolve all conflict manually, mark them as resolved with                       
        "git add/rm <conflicted_files>", then run "git rebase --continue".              
        You can instead skip this commit: run "git rebase --skip".                       
        To abort and get back to the state before "git rebase", run "git rebase --abort".
      

      당연히 충돌이 나겠죠?

        git st
              
        ---
              
        rebase in progress; onto e9284f0
        You are currently rebasing branch 'feature/e' on 'e9284f0'.
          (fix conflicts and then run "git rebase --continue")
          (use "git rebase --skip" to skip this patch)
          (use "git rebase --abort" to check out the original branch)
                
        Unmerged paths:
          (use "git reset HEAD <file>..." to unstage)
          (use "git add <file>..." to mark resolution)
                
            both modified: README.md
      
        vi README.md
        git add README.md
        git st
              
        ---
              
        rebase in progress; onto e9284f0
        You are currently rebasing branch 'feature/e' on 'e9284f0'.
          (all conflicts fixed: run "git rebase --continue")
                
        Changes to be committed:
          (use "git reset HEAD <file>..." to unstage)
                
            modified: README.md
      
        git rebase --continue
        git lg
              
        ---
              
        6b0be84 - (5 seconds ago) feature pr conflict - Country (HEAD -> feature/e)
        e9284f0 - (8 seconds ago) master pr conflict - Country (origin/master, master)
        | 60f6d0c - (20 seconds ago) feature pr conflict - Country (origin/feature/e)
        |/
        87a0d74 - (31 seconds ago) Merge pull request #1 from hyungju-lee/feature/d - country
        |\
        | 2977241 - (1 seconds ago) pr exer - Country (origin/feature/d, feature/d)
        |/ 
        c2bb430 - (3 seconds ago) rebase 1. - Country
        314e412 - (22 seconds ago) master rebase conflict - Country 
        e47ddc0 - (2 seconds ago) feature/c rebase auto merge - Country
        a79a82c - (29 seconds ago) master rebase auto merge - Country
        c925bd6 - (32 seconds ago) rebase fast-forward - Country
        4e06e1a - (22 hours ago) conflict test - Country (origin/master)
        73f4e09 - (22 hours ago) 3-way merge other - Country
        24a6271 - (22 hours ago) fast-forward exer - Country
        ...
      
        git push
              
        --- 
              
        To https://github.com/hyungju-lee/git-exer.git
        ! [rejected]        feature/e -> feature/e (non-fast-forward)
        error: failed to push some refs to 'https://github.com/hyungju-lee/git-exer.git'
        ...
      

      그런데 git push를 하니까 에러가 났습니다.
      그 이유는 rebase를 하면서 커밋이 달라졌기 때문입니다.
      원격 저장소에있는 origin/feature/e 브랜치의 커밋엔 60f6d0c 커밋이 있는데, rebase한 로컬 feature/e 브랜치의 커밋 로그엔 60f6d0c이 없고 다른 내용이 쌓였기 때문입니다.

      그런데 보통 feature/e와 같은 feature 브랜치는 개인이 작업하는 브랜치이고 rebase를 한 이유는 conflict를 해결하기 위함이었습니다.
      그렇기때문에 이러한 상황에서는 강제 push를 쓰셔도됩니다.

        git push -f
      

      이렇게하면 충돌이 났던것도 해결이돼서 합칠 수 있게 되었습니다.

4.5 reset

  • 상태를 이전 커밋으로 reset 시킴
  • 옵션에 따라서 몇 커밋 이전 / 어느 단계(Staged, Modified, Unmodified)까지 reset 할지를 결정
  • show: 커밋 정보를 보여줌

    • HEAD == @, ~ == ^

        git show HEAD
              
        ---
              
        commit 37162dda66e77e7f178f8446ff63a3531f8ff656 (HEAD -> master)
        Author: Country <beegizee1220@gmail.com>
        Date: Sun July 04 20:54:58 2021 +0900
              
          3
                
        diff --git a/README.md b/README.md
        index 2d91fda..b4e9ada 100644
        --- a/README.md
        +++ b/README.md
        @@ -1,5 +1,6 @@
         1
         2
        +3
              
         Country와 함께하는 Git 교실
         - master & feature pr conflict
      
        git show @
              
        ---
              
        commit 37162dda66e77e7f178f8446ff63a3531f8ff656 (HEAD -> master)
        Author: Country <beegizee1220@gmail.com>
        Date: Sun July 04 20:54:58 2021 +0900
              
          3
                
        diff --git a/README.md b/README.md
        index 2d91fda..b4e9ada 100644
        --- a/README.md
        +++ b/README.md
        @@ -1,5 +1,6 @@
         1
         2
        +3
              
         Country와 함께하는 Git 교실
         - master & feature pr conflict
      

      HEAD@는 똑같습니다.

        git show @~   (~ 표시를 했기 때문에 HEAD가 가리키는 커밋의 바로 직전 커밋 기록이 나옵니다.)
              
        ---
              
        commit a86df006e464224d736bd90653ee67c4befb204c
        Author: Country <beegizee1220@gmail.com>
        Date: Sun July 03 20:54:58 2021 +0900
              
          2
                
        diff --git a/README.md b/README.md
        index 7591bf5..2d91fda 100644
        --- a/README.md
        +++ b/README.md
        @@ -1,4 +1,5 @@
         1
        +2
              
         Country와 함께하는 Git 교실
         - master & feature pr conflict
      
        git show @^   (^ 표시를 했기 때문에 HEAD가 가리키는 커밋의 바로 직전 커밋 기록이 나옵니다.)
              
        ---
              
        commit a86df006e464224d736bd90653ee67c4befb204c
        Author: Country <beegizee1220@gmail.com>
        Date: Sun July 03 20:54:58 2021 +0900
              
        2
              
        diff --git a/README.md b/README.md
        index 7591bf5..2d91fda 100644
        --- a/README.md
        +++ b/README.md
        @@ -1,4 +1,5 @@
         1
        +2
              
         Country와 함께하는 Git 교실
         - master & feature pr conflict
      

      ~^도 같습니다.

    • ex) HEAD~, HEAD^, @~, @^ : 한 커밋 이전
    • @~2: 2커밋 이전

        git show @~2
              
        ---
              
        commit 47d07b9e735881dec78c246d408bcabd007d5316
        Author: Country <beegizee1220@gmail.com>
        Date: Sun July 03 20:54:58 2021 +0900
              
          1
              
        diff --git a/README.md b/README.md
        index 096bd23..7591bf5 100644
        --- a/README.md
        +++ b/README.md
        @@ -1,3 +1,5 @@
        +1
        +
              
         Country와 함께하는 Git 교실
         - master & feature pr conflict
         - rebase 1.2.
      
  • 옵션

    • --soft

      • commit 명령만 되돌림 (Staged 상태가 됨)
      • HEAD만 해당 커밋으로 돌림

          vi README.md
          git ci -am 'Commit for reset exer'
          git reset --soft @^
          git st
                    
          ---
                    
          On branch develop
          Changes to be committed:
          (use "git reset HEAD <file>..." to unstage)
                    
          modified:   README.md
        
    • --mixed (기본)

      • commit 명령도 되돌리고, add 명령까지 되돌림 (Modified 상태가 됨)

          git ci -am 'Commit for reset exer'
          git reset --mixed @~1
          git st
                    
          ---
                    
          On branch develop
          Changes not staged for commit:
            (use "git add <file>..." to update what will be committed)
            (use "git checkout -- <file>..." to discard changes in working directory)
                    
            modified:   README.md    
        
    • --hard

      • commit 명령도 되돌리고, add 명령도 되돌리고, 워킹 디렉토리까지 되돌림 (Unmodified 상태가 됨)
      • 워킹 디렉토리까지 되돌려 버리기 때문에 복구가 불가능!

          git ci -am 'Commit for reset exer'
          git reset --hard @^
          git st
                    
          ---
                    
          On branch develop
          nothing to commit, working tree clean
        
      • 3단계 전 커밋으로 돌아가기

          git reset --hard @~3
        
Note

주의 3대장

타인과 같이 사용하는 브랜치에선 절대 사용하면 안되는 명령어입니다.

  1. push -f
  2. rebase
  3. reset --hard

4.6 cherry-pick

  • 다른 커밋을 가져옴
  • 커밋의 수가 적다면 mergerebase보다 간결하고 깔끔한 트리를 유지할 수 있음

      git co master
      git co -b feature/f
      vi README.md
      git ci -am 'Cherry-pick test'
        
      git co master
      git cherry-pick <hash번호>
    
  • 실습

      git co -b feature/f
      vi README.md
      git ci -am 'Cherry-pick test'
      git lg
        
      ---
        
      4e07a78 - (2 seconds ago) Cherry-pick test - Country (HEAD -> feature/f)
      ...
    
      git co master
      git cherry-pick 4e07a78
        
      ---
        
      [master 33278ac] Cherry-pick 4e07a78
      ...
    
      git lg
        
      ---
        
      33278ac - (74 seconds ago) Cherry-pick test - Country (HEAD -> master)
      | 4e07a78 - (2 seconds ago) Cherry-pick test - Country (HEAD -> feature/f)
      |/
      ...
    

    다른 브랜치의 커밋을 가져오지만 hash 번호는 바뀝니다.
    feature/f의 내용을 다 가져와서 필요없다면 지우시면 됩니다.

      git br -D feature/f
    

    그런데 보통 cherry-pick은 실무에선 잘 사용안합니다.
    pr을 보낸 후 코드리뷰를 거쳐 merge를 하는 것이 일반적이기 때문입니다.

    그럼 cherry-pick은 언제 사용하느냐.

    release/2 브랜치에서 feature/v2 브랜치를 생성해야되는데 실수로 develop에서 feature/v1 브랜치를 생성했다면,
    다시 release/2 브랜치에서 feature/v2 브랜치를 생성한 후 실수로 생성한 feature/v1 브랜치의 내용을 cherry-pick합니다.
    이럴때 주로 사용.

4.7 tag

  • 릴리즈를 하기 위한 브랜치 같은 것
  • GitHub에서 Release를 만들면서 하면 편함
-- 이때까지 작업한 것을 push
git push
  • GitHub 실습

    • releases 클릭
    • create a new release

      • 태그 이름: v1.0.0
      • 기준 브랜치: master
      • title과 content 작성

tag는 예전에 브랜치 전략을 설명드릴 때 말씀드린적이 있습니다.

tag라는 것은 브랜치와 비슷한데 특정 배포 버전을 나타내기위해 사용하는 것입니다.
그래서 보통 master에서 따서 tag를 만듭니다.
0.1, 0.2, 1.0 이런식으로 숫자로 따서 tag를 만듭니다.

tag도 생성하는 명령어가 있긴한데 로컬에선 딱히 쓸일이 없기 때문에 직접 GitHub에서 release를 만들면서 tag를 만드는 것을 테스트해보겠습니다.

release 탭을 눌러주시고.. 이 release도 깃 자체의 기능이 아니라 GitHub에서 제공해주는 기능입니다.

release라는 것은 말 그대로 특정 버전을 만들어서 배포를 할 것을 말합니다.
그래서 이 release 하나마다 tag를 만들어서 release를 생성하게됩니다.
위에서 create new release 버튼을 누르시고

그럼 어떤 브랜치에서 따서 tag를 만들것인지를 정할 수 있습니다.

이런식으로 만들어서 Publish release를 해줍니다.
이렇게해주면 release가 만들어지고 v1.0.0이란 이름의 tag가 하나 만들어질 것입니다.

보시면 Releases 탭에서 하나의 release가 생긴 것을 볼 수 있고

Tags로 가시면 release에서 만들었던 tag도 같이 연동이돼서 나오는 것을 볼 수 있습니다.
이렇게 release를 생성하고, 또 이 tag를 가지고 실무에선 배포를 하게됩니다.