코드 리뷰와 병합 방식
3. 코드 예제
예제 1: origin 준비와 CODEOWNERS, feat/order 커밋 — 01_review_merge.sh 발췌
git init -q --bare -b main "$ORIGIN"
cat > "$ORIGIN/hooks/pre-receive" <<'HOOK'
while read -r old new ref; do
if [ "$ref" = "refs/heads/main" ] && [ "$old" != "0000..0000" ]; then
if ! git merge-base --is-ancestor "$old" "$new"; then
echo "remote: 거부됨 - force push 금지" >&2; exit 1
fi
fi
done
HOOK
chmod +x "$ORIGIN/hooks/pre-receive"
git add README.md CODEOWNERS
commit_at "커밋1: README, CODEOWNERS 추가"
git push -u origin main== 1. origin(GitHub 저장소 역할) 준비: 브랜치 보호 훅 + CODEOWNERS ==
* [new branch] main -> main
== 2. feat/order 브랜치 커밋 두 개와 push ==
* [new branch] feat/order -> feat/order
cbed3f2 feat: 주문 수량 검증 추가
ff714d5 feat: 주문 합계 계산 추가예제 2: 리뷰 화면 재현과 CODEOWNERS 매칭 — 01_review_merge.sh 발췌
echo "-- suggestion 을 적용해 커밋 --"
cat > Order.java <<'EOF'
public class Order {
public int total(int price, int qty) {
if (qty <= 0) throw new IllegalArgumentException("qty");
return price * qty;
}
}
EOF
git add Order.java
commit_at "fix: 리뷰 suggestion 반영 - 수량 검증 추가"
# owner_of() 는 CODEOWNERS 패턴을 case 문으로 매칭한다(2.5 참고)
owner_of "Order.java"== 3. 리뷰 화면 재현: Comment / Approve / Request changes, suggestion ==
--- PR #1 리뷰 화면(텍스트 재현) ---
[park] Comment Order.java:3 "price 가 음수면 어떻게 되나요?"
[park] Request changes
Order.java:3
```suggestion
public int total(int price, int qty) {
if (qty <= 0) throw new IllegalArgumentException("qty");
return price * qty;
}
```
[lee] Approve "로직은 문제없습니다. park 의견 반영 후 병합하세요."
-- suggestion 을 적용해 커밋 --
b63f698 fix: 리뷰 suggestion 반영 - 수량 검증 추가
== 4. CODEOWNERS 매칭 확인 ==
* @team-core
*.java @backend-team
docs/* @doc-team
Order.java -> @backend-team
docs/guide.md -> @doc-team
README.md -> @team-core예제 3: 브랜치 보호 — force push 거부 — 01_review_merge.sh 발췌
git reset -q --hard HEAD~1
commit_at "chore: 배포 노트(재작성)"
echo "-- 재작성한 히스토리를 그냥 push 하면 (거절: non-fast-forward) --"
git push origin main || true
echo "-- --force 로 우회를 시도해도 서버 훅이 거절 --"
git push --force origin main || true== 5. 브랜치 보호: force push 거부와 정상 push ==
-- 재작성한 히스토리를 그냥 push 하면 (거절: non-fast-forward) --
! [rejected] main -> main (non-fast-forward)
-- --force 로 우회를 시도해도 서버 훅이 거절 --
remote: remote: 거부됨 - main 은 force push 를 허용하지 않습니다 (브랜치 보호 규칙)
! [remote rejected] main -> main (pre-receive hook declined)
-- 올바른 방법: 되돌리지 말고 원래 커밋 위에 새 커밋을 쌓는다 --
To WORK/origin.git
a89a4e8..5a06a5c main -> main일반 push 는 git 클라이언트가 먼저 non-fast-forward 로 거절합니다. --force 로 우회해도 서버의 pre-receive 훅이 한 번 더 막습니다.
예제 4: 병합 방식 3가지 비교 — 01_review_merge.sh 발췌
git switch -q int-merge
merge_at "Merge pull request #1 from feat/order: 주문 합계 계산" feat/order
git log --oneline --graph -6
git switch -q int-squash
squash_at feat/order "feat: 주문 합계 계산 (#1, squash merge)"
git log --oneline --graph -4
git switch -q int-rebase
git switch -q feat/order-copy
GIT_COMMITTER_DATE="$d" git rebase int-rebase
git switch -q int-rebase
git merge -q --ff-only feat/order-copy== 6. 병합 방식 3가지 비교: merge commit vs squash vs rebase ==
-- int-merge: 병합 커밋 하나, feat 커밋 3개 그대로 보존 --
* ea64577 Merge pull request #1 from feat/order: 주문 합계 계산
|\
| * b63f698 fix: 리뷰 suggestion 반영 - 수량 검증 추가
| * cbed3f2 feat: 주문 수량 검증 추가
| * ff714d5 feat: 주문 합계 계산 추가
* | 5a06a5c chore: CI 설정 추가
* | a89a4e8 chore: 배포 노트 초안
|/
-- int-squash: 커밋 1개, 부모도 1개(일반 커밋과 구분 안 됨) --
* 5c89b0c feat: 주문 합계 계산 (#1, squash merge)
* 5a06a5c chore: CI 설정 추가
... (이하 main 과 동일)
-- int-rebase: feat 커밋 3개가 해시를 새로 받아 한 줄로 이어짐 --
* 0501514 fix: 리뷰 suggestion 반영 - 수량 검증 추가
* 2092bbe feat: 주문 수량 검증 추가
* 9346569 feat: 주문 합계 계산 추가
* 5a06a5c chore: CI 설정 추가
... (이하 main 과 동일)같은 feat/order 를 세 방식으로 각각 병합했습니다. merge commit 만 병합 커밋이 남고, squash 는 커밋이 하나로 줄고, rebase 는 개수는 그대로인 채 해시만 바뀌어 한 줄로 이어집니다.