(git) 특정 브랜치 특정 커밋들 줄줄이 그대로 다른 브랜치에 복사하기

엽토군·2024년 10월 8일
0

1분 코드 스니펫

목록 보기
10/10

tl;dr

git checkout X
git format-patch A..B --stdout | git am

문제

어딘가에 커밋 A와 커밋 B가 존재하고, 이 두 커밋은 같은 브랜치 Y에서 연결돼 있다고 가정하자.
그리고 이 커밋들과 별 상관없는 브랜치 X가 존재한다고 가정하자.
A에서 B까지의 변경점을 브랜치 X에 반영하려면 어떻게 해야 할까?

푸념

개인적으로는 지금까지 내내 체리픽을 했다.
하나씩... 하나씩...
한두 번이라면 괜찮겠는데 이 짓을 여러 번 하자니 현타가 진하게 왔다.
충돌이 나는 건 둘째 문제고 뭔가 이러다가 하나쯤 빼먹을 거 같단 말이지.
왜 한두 번이 아니냐? 지금 다니는 회사 소스의 마스터가 사실상 2개라서 그렇다. 당장 고객들에게 나가야 하는 master가 있고, 장기적으로 QA 제대로 해본답시고 하고 있는 qa 브랜치가 있다. master 브랜치에서 시작한 기능브랜치를 qa 브랜치에 올려야 테스트를 받을 텐데... 그러자면 브랜치를 새로 따서 체리픽을 하나씩... 하나씩... 하고 앉았어야 했던 것이다.

이게 답일 리가 없다.

해법

이상적인 상황에서, 즉 단순히 체리픽만 정신 차리고 쭉 하기만 하면 되고 딱히 충돌은 안 나는 상황에서, git의 format-patch와 am은 아주 좋은 선택인 것 같다.

git-format-patch

git format-patch A..B --stdout
  • 매뉴얼
  • 아무 옵션도 주지 않으면 아무 일도 일어나지 않는다. 최소한 <since><common-diff-options>를 줘야 한다. 여기서는 A..B로 diff option을 주었다.
  • --stdout 옵션을 주면 내용을 표준 출력으로 얻는다. 이걸 > 리디렉션해서 파일에 쓰거나 | 파이프를 태우는 것이 가능하다.
  • 출력은 대충 이렇게 생겼다.
From 01eb483369999ab17ef862bd2c4e45888956c288 Mon Sep 17 00:00:00 2001
From: yuptogun <eojin1211@hanmail.net>
Date: Tue, 8 Oct 2024 11:07:37 +0800
Subject: [PATCH 1/4] foo bar

---
 foo/bar/dee.php | 44 +----------------------------------
 foo/bar/meh.php | 40 +++++++++++++++++++++++++++++++
 2 files changed, 40 insertions(+), 44 deletions(-)

diff --git a/foo/bar/dee.php b/foo/bar/meh.php
index 91bab80d..22923896 100644
--- a/foo/bar/dee.php
+++ b/foo/bar/meh.php
@@ -402,46 +402,4 @@
             </div>
         </div>

이하 생략

git-am

git am
  • 매뉴얼
  • apply from mailbox의 줄임말이다. 사실 format-patch도 커밋간의 diff를 메일 형식으로 만들어주는 기능이다. 아래 여담 참조
  • 상기 예제에서는 |로 출력을 전달받아 그대로 썼다. 그게 편하니까. 하지만 정 필요하다면 파일을 받은 다음 <mbox>에 파일을 줘도 된다.
# 만들어낸 예제라서 좀 억지스럽긴 하다. 하지만 bitbucket pipeline이 출동한다면 어떨까? 빗! 버! 킷!
git checkout X
git format-patch A..B -o ~/foo.patch
scp ~/foo.patch me@backupserver:/backup/patches
git am ~/foo.patch

여담

혹시 '이렇게 해도 되는 거 아닌가?' 하셨던 분이 계실지 모르겠다.

git checkout X
git diff A..B | git apply

되긴 된다. 근데 문제가 뭐냐면 커밋이 "복사"가 안된다. A에 남겼던 소중한 커밋메시지, B를 커밋했던 날짜, 그 사이에 있었던 삽질 이력 등등이 전혀 남지 않고 그냥 unstaged changes만 한무더기 들어오고 끝난다.

git diff는 단순히 최종 변경만 전체적으로 제공하지만, format-patch는 author가 누구인지 커밋 메시지가 무엇인지도 다 제공한다. 그래서 format-patch를 am했을 때는 결과적으로 커밋이 줄줄이 사탕으로 복사되는 효과를 얻을 수 있는 것이다.

신기하네요 그쵸?

profile
5년차 PHP 개발자입니다.

0개의 댓글