Loading the catalog…
Loading the catalog…
Git_Day.3 merge 와 rebase 를 이력 그림으로 비교하고, 언제 무엇을 쓸지 정리한 날. 그리고 main 에서 실수로 작업했을 때 수습하는 순서. Day.2 마지막에 merge 와 rebase 의 차이를 간단히 봤다. 오늘은 커밋 이력이 어떻게 달라지는지 를 그림으로 이해하고, 실무에서 어느 쪽을 쓰는지까지 정리했다. 1. 상황 설정 두 브랜치가 첫 커밋 A 에서 갈라져서 각자 커밋을 쌓았다고 하자. A - B - C : 나 (me) A - D : main (친구가 추가한 커밋) $ git log --oneline --graph --all * 3c37e34 D | * 608de9a C | * b086d41 B |/ * b67a30e A 이 두 갈래를 하나로 합치는 방법이 merge 와 rebase 다. (해시값은 실습할 때마다 다르다) 2. Merge: 합치기 분리되어 있던 브랜치가 main에 통합되는 느낌. merge 는 두 브랜치의 끝을 하나로 합치는 새 커밋(머지 커밋) 을 만든다. $ git switch main # 합쳐질 곳(받는 쪽)으로 이동 $ git merge me -m "Merge me into main" $ git log --oneline --graph * 5b8cb26 Merge me into main ← 두 갈래를 잇는 새 커밋 |\ | * 608de9a C | * b086d41 B * | 3c37e34 D |/ * b67a30e A 기존 커밋 B , C , D 는 그대로 보존 되고 해시도 바뀌지 않는다. 이력에 갈라졌다가 합쳐진 흔적 이 남는다. 합쳐진 결과를 담는 새 커밋(해시코드도 새로 생긴다) 이 하나 생긴다. 어느 브랜치에서 실행하나 필기에는 "merge는 보통 main에서 실행한다. 합쳐질 브랜치에서 실행해야 하기 때문"이라고 적었다. 정확히 말하면 merge 는 "지금 있는 브랜치"에 "지정한 브랜치"를 가져와 합친다. 그래서 결과를 받을 쪽 브랜치로 먼저 이동한 뒤 실행한다. $ git switch main $ git merge me # main 에 me 를 합친다 → main 이 바뀐다 반대로 me 에서 git merge main 을 하면 me 에 main 을 합치는 것이라서 me 브랜치에 머지 커밋이 생기고 main 은 그대로다. $ git switch me $ git merge main -m "Merge main into me" * 3c3a7be Merge main into me ← me 브랜치에 생긴다 |\ | * 3c37e34 D (main 은 D 에 그대로 머물러 있다) * | 608de9a C * | b086d41 B |/ * b67a30e A 어느 쪽이 맞는 것은 아니고 "어디에 합칠 것인가" 에 따라 정한다. 기능 브랜치를 main 에 합치는 경우가 많아서 main 에서 실행하는 일이 많은 것이다. 3. Rebase: 베이스를 다시 잡기 베이스를 다시 잡는다 고 이해하면 좋다. rebase 는 내 브랜치가 갈라져 나온 지점(베이스)을 최신 커밋 위로 옮기는 작업이다. 내 커밋들을 최신 커밋 뒤에 다시 이어 붙인다. rebase 전 rebase 후 (me 에서 git rebase main) A - B - C : 나 A - D - B' - C' : 나 A - D : main A - D : main 나 에서 git rebase main 을 하면 A (기존 베이스) → D ( 새로 잡힌 베이스 ) → B → C 순서로 이어진다. $ git switch me $ git rebase main Successfully rebased and updated refs/heads/me. $ git log --oneline --graph * 5d49e3f C * a5ab0df B * 3c37e34 D * b67a30e A 이력이 일직선 이 되었다. 그리고 해시를 비교해 보면 이렇다. 커밋 rebase 전 rebase 후 B b086d41 a5ab0df C 608de9a 5d49e3f D 3c37e34 3c37e34 (그대로) 내 커밋( B , C )의 해시코드가 새 값으로 바뀐다. 커밋은 "부모가 누구냐"까지 포함해서 해시가 정해지는데, rebase로 부모가 A 에서 D 로 바뀌었기 때문에 내용은 같아도 새 커밋으로 다시 만들어지는 것 이다. 이후 main 에 합치면 이렇게 된다. $ git switch main $ git merge me Updating 3c37e34..5d49e3f Fast-forward ← 머지 커밋 없이 main 이 앞으로 이동만 한다 rebase 를 먼저 해 두면 main 은 이미 내 브랜치의 조상이라서 새 커밋 없이 포인터만 앞으로 이동(fast-forward) 한다. 최종 이력이 일직선으로 깔끔하게 남는다. 4. Merge와 Rebase 비교 구분 merge rebase 새 커밋 머지 커밋이 생긴다 머지 커밋이 생기지 않는다 기존 커밋 해시 그대로 새 값으로 바뀐다 이력 모양 갈라지고 합쳐지는 흔적이 남는다 일직선 이력의 의미 실제로 일어난 일 그대로 기록 깔끔하게 다시 쓴 이력 필기에는 "새 커밋이 생기느냐, 아니냐의 차이"라고 정리돼 있다. 보충하면 rebase도 내 커밋을 복제해서 새로 만든다 는 점에서 커밋이 새로 생기긴 한다. 다만 merge처럼 두 갈래를 잇는 합치기용 커밋 이 따로 생기지 않는다는 뜻으로 이해하면 맞다. 5. 실무에서는 무엇을 쓰나 기준은 "그 브랜치를 다른 사람이 가져갔는가" 다. 상황 선택 이유 GitHub에 push해서 다른 사람이 pull 받은 브랜치 merge rebase는 해시를 바꾸기 때문에 남들의 이력과 꼬일 수 있다 혼자 가지고 있는 push 안 한 로컬 브랜치 rebase 이력이 깔끔하게 남는다 이미 push한 브랜치를 rebase하면 어떻게 되는지 확인했다. 원격에 있는 feat 브랜치를 main 위로 rebase하고 push해 보았다. $ git rebase main # 해시가 바뀐다 $ git push ! [rejected] feat -> feat (non-fast-forward) error: failed to push some refs to '../origin.git' hint: Updates were rejected because the tip of your current branch is behind ... 거부된다. 원격에는 옛 해시( 608de9a )의 커밋이 있고 로컬에는 새 해시( 5d49e3f )의 커밋이 있어서 서로 이어지지 않기 때문이다. 억지로 올리려면 강제 푸시가 필요한데, 그러면 같은 브랜치를 받아 간 다른 사람의 이력이 어긋난다. $ git push --force-with-lease # 강제 푸시 (원격이 내가 아는 상태일 때만 덮어씀) + 608de9a...5d49e3f feat -> feat (forced update) Day.2의 push -f 가 위험하다고 한 이유가 바로 이것이다. --force-with-lease 는 -f 보다 안전한 강제 푸시 옵션으로, 내가 마지막으로 본 이후 원격에 다른 사람이 새로 올린 커밋이 있으면 거부 한다. 그래도 혼자 쓰는 브랜치에서만 쓰는 것이 좋다. rebase 중 충돌이 나면 같은 파일의 같은 부분을 두 브랜치가 다르게 고쳤으면 rebase 도중에 멈춘다. $ git rebase main CONFLICT (content): Merge conflict in f.txt error: could not apply 20b6447... me edit hint: Resolve all conflicts manually, mark them as resolved with ... 충돌난 파일을 직접 고친 뒤 git add 파일 , git rebase --continue 로 이어 간다. 하기 싫으면 git rebase --abort 로 rebase를 시작하기 전 상태로 되돌린다. 시작 전으로 안전하게 돌아오니 처음에는 --abort 를 기억해 두면 마음이 편하다. 6. 실수 수습: main에서 작업해 버렸을 때 main 에서 작업하면 안 되는데 커밋하기 전에 깨달았다면 이 순서로 한다. main 에서 실수로 작업했다. (커밋하기 전) 새 브랜치로 이동 해서 git add , git commit 한다. GitHub에 올린다. $ git status -s # main 에서 작업 중인 상태 M a.txt ?? feature.txt $ git branch --show-current main $ git switch -c feature/login # 새 브랜치 생성 + 전환 Switched to a new branch 'feature/login' $ git status -s # 작업 내용이 그대로 따라왔다 M a.txt ?? feature.txt $ git add . $ git commit -m "feature: login" $ git push -u origin feature/login # 새 브랜치를 GitHub에 올린다 핵심은 git switch -c 가 아직 커밋하지 않은 변경 사항을 그대로 가지고 새 브랜치로 넘어간다는 점이다. 커밋 전이라서 아직 main 에는 아무 기록도 남지 않았고, 새 브랜치에서 커밋하면 이 작업은 새 브랜치에만 기록된다. 확인해 보면 main 으로 돌아갔을 때 git status 가 깨끗하고 feature.txt 도 보이지 않는다. 이미 main 에 커밋까지 해 버린 경우는 이 방법만으로는 부족하다. 그때는 Day.1의 reset 으로 main 의 커밋을 되돌리는 작업이 같이 필요하다. 이 날 노트는 커밋 전 상황까지만 다뤘다. 7. 파일 만들기 명령어 실습할 때 쓰는 echo 리다이렉트도 한 번 더 정리했다. (Day.2의 echo 참고) 명령어 의미 echo 텍스트 > 파일명 파일을 만들고 내용을 쓴다 (이미 있으면 덮어씀) echo 텍스트 >> 파일명 파일 끝에 내용을 추가 마무리 merge 는 두 브랜치를 잇는 머지 커밋 을 만들고, 기존 커밋은 그대로 보존된다. 이력에 갈라진 흔적이 남는다. rebase 는 베이스를 최신 커밋 위로 옮겨서 내 커밋을 다시 이어 붙인다. 이력이 일직선이 되지만 내 커밋의 해시가 바뀐다. 이미 push해서 남들이 받아 간 브랜치는 merge , 혼자 쓰는 push 전 로컬 브랜치는 rebase 를 쓴다. merge는 결과를 받을 브랜치로 이동해서 실행한다. rebase 중에 충돌이 나면 해결 후 --continue , 포기할 때는 --abort 다. main 에서 커밋 전에 실수로 작업했다면 git switch -c 새브랜치 로 옮겨서 커밋하고 push한다. Tags : Git merge rebase 브랜치 GitHub 커밋이력 협업 개발자 학습기록
What RADAR observed and classified to build this opportunity. It is what the source published, not a verification that the offer is still active.
Git_Day.3. Git_Day.3 merge 와 rebase 를 이력 그림으로 비교하고, 언제 무엇을 쓸지 정리한 날. 그리고 main 에서 실수로 작업했을 때 수습하는 순서. Day.2 마지막에 merge 와 rebase 의 차이를 간단히 봤다. 오늘은 커밋 이력이 어떻게 달라지는지 를 그림으로 이해하고, 실무에서 어느 쪽을 쓰는지까지 정리했다. 1. 상황 설정 두 브랜치가 첫 커밋 A 에서 갈라져서 각자 커밋을 쌓았다고 하자. A - B - C : 나 (me) A - D : main (친구가 추가한 커밋) $ git log --oneline --graph --all * 3c37e34 D | * 608de9a C | * b086d41 B |/ * b67a30e A 이 두 갈래를 하나로 합치는 방법이…
Open source