다른 repository commit 합치기

박주엽·2021년 3월 7일
3

git % github

목록 보기
5/5

A와 B라는 레포가 있을 때 A에서 먼저 작업을 하고 B에도 같은 내용을 반영해야 되는 상황이다. 일반적으로 코드 복사 붙여넣기를 할 수 있지만 git으로도 커버 가능하다.

Remote로 추가하고 merge하기

cd repo1
git remote add repo2 ../repo2
// 태그까지 가져오면 태그 관리가 불편해진다
git fetch repo2 --no-tags
git merge --allow-unrelated-histories repo2/master # 또는 브렌치 이름

repo1 리포지토리에 repo2의 커밋을 추가할 경우에는 repo2의 특정 브랜치의 커밋을 머지 시킬 수 있습니다.

특정 브랜치의 특정 커밋을 가져오고 싶다면 Cherry-pick을 사용하는 것이 좋습니다.

Cherry-pick 사용하기

다음은 repo1 레포를 수정해서 커밋하고 repo2 레포에도 반영할 때 사용하는 모습이다.

// remote repo를 추가한다 
git remote add repo1 <remote path>

// (push나 pull을 하지 않고 fetch만사용
// pull은 가져오는 동시에 merge를 시도하기 때문이다
git fetch repo1 --no-tags

git cherry-pick <작업한 commit id>

이 때 repo1 레포와 repo2 레포에서 작업하는 파일 경로가 다르다면 cherry-pick을 멈추고 상대 레포의 파일이 추가된 상태가 된다.

Git fetch는 언제 사용할까?

리모트 저장소는 github나 bitbucket, gitlab과 같은 서비스를 말한다. 이러한 서비스를 통해 우리가 만든 프로젝트를 작업 컴퓨터가 아닌 인터넷 상에 올릴 수 있다.

리모트 저장소를 사용하는 이유

  • 다른 사람과 작업을 하기 위해
  • 작업 환경이 달라지는 것을 대비해서
  • 오픈 소스로 공유하기 위해서

위와 같은 이유로 git 레포지토리를 git remote 저장소에 저장할 수 있습니다. 또한 현재 리모트 저장소를 알기위해서 git remote -v라는 명령어를 사용할 수 있습니다.

원격 저장소에 올라가 있는 내용과 우리가 작업하는 컴퓨터에서의 git 내용이 다를 수 있다. git에서 local과 remote 저장소를 함께 연동하여 작업하는 경우 remote에 새로운 커밋이 발생했을 때 fetch와 pull을 이용하여 remote의 커밋 히스토리를 받아올 수 있습니다.

Git pull과 fetch의 차이점

git pull은 리모트 저장소의 내용을 가져올 때 가장 자주 사용하는 옵션이다. master 브랜치에 추가된 커밋이 있을 때 git pull origin(리모트 저장소) master(브랜치) 명령어를 사용하면 origin 저장소와 서로 다른 작업 내용이 있는지 확인한다. 만약 서로 다른 작업 내용이 있을 경우 이를 하나로 합치는 작업을 진행한다. 서로 같은 파일을 수정해서 충돌되는 내용이 있을 경우 merge는 실패하고 충돌이 발생한 부분이 표시가 된다. 충돌되는 부분이 없을 경우에는 자동으로 합쳐진다. pull은 remote의 히스토리를 가지고 오면서 local에 있는 내용을 함께 merge를 하기때문에 새로운 커밋을 업데이트하고 작업 환경 HEAD가 최신 커밋을 가리키게 됩니다.

fetch의 경우 pull과는 다르게 병합을 시도하지 않고 리모트 저장소의 최신 내용만 가져온다. 현재 작업하고있는 환경인 HEAD는 그대로 유지가 되고 기본적으로 브랜치와, 태그와 커밋을 업데이트하는데 가져오는 내용은 옵션에 따라서 달라진다.

  • 기본: origin
  • remote : 특정 remote
git fetch (remote 레포 이름)
  • 특정 branch
git fetch origin(remote 레포 이름) <branch>
  • —no-tags : 태그 목록은 가져오지 않기

git fetch로 다른 repo에서 commit 가져오기

remote repository를 추가

    git remote add <remote_name> <url_of_open_source_project>

정상적으로 추가 됬는지 확인

    git remote -v

remote repository의 코드를 병합하는데 사용할 브랜치를 생성

    git checkout -b <branch_name>

생성한 브랜치에 해당 remote 브랜치와 merge

    git fetch <remote_name>
    git merge <remote_name>/<remote's branch_name>

git patch

patch를 사용하면 특정 커밋을 모아서 해당 내역을 파일로 만들 수 있습니다. 또한 만들어진 패치 파일을 다른 브랜치나 작업환경에 적용할 수 있습니다. 이러한 특성을 활용해서 다른 레포에서 몇개의 커밋만 골라서 적용하고 싶을 때 유용하게 사용할 수 있습니다.

보통 git을 통해서 개발자들과 협업을 할 때는 로컬저장소에서 작업을 진행하고 작업한 내용(커밋)을 remote 저장소에 push하여 다른 개발자와 작업내용을 공유하며 진행합니다.

프로젝트 단위로 볼 떄 대게 remote 저장소로 push하는 권한은 아무에게나 부여되지 않고 같은 프로젝트 팀원들에게만 권한이 부여되고 이 인증 절차를 remote 저장소에 SSH Key를 등록하게 됩니다.

이러한 방식으로 git을 활용했을때 대형 오픈소스 프로젝트를 진행할 수 없습니다. 오픈소스이지만 push 권한을 아무에게나 부여할 수 없기 때문입니다.

큰 오픈소스 프로젝트의 경우 remote 저장소에 소스코드를 직접 push할 수 있는 권한을 가진 개발자를 Commitor 라고 부르고 Commitor에게 자신이 로컬 저장소에서 작업한 코드를 간접적으로 제공하여 프로젝트에 기여하는 개발자들을 Contributor라고 합니다.

Contributor들이 오픈소스 프로젝트에 기여하나 push 권한을 갖지 못하기 때문에 이런 상황에서 유용하게 사용할 수 있는 기능이 Patch입니다.

Patch 기능은 commit을 하나의 Patch 파일로 만들 수 있고, 해당 파일을 이메일 등을 통해 Commitor에게 전달하고 내용을 검토한 뒤 반영합니다.

요즘은 github, bitbucket 등과 같은 remote 저장소의 Pull Request 기능을 많이 이용합니다.

remote 저장소가 서비스 장애가 생겼을 때 개발자들이 서로 작업내용을 공유하는데도 쓰일 수 있습니다.

patch 만들기

git diff 명령어

특별한 옵션 없이 내용을 저장할 패치 파일 이름만 지정하면 이미 git으로 커밋되어 있는 내용에서 변경된 내용을 패치 파일에 저장합니다.

git diff > diff_patch.patch

git diff 명령어의 옵션에 따라서 커밋1과 커밋2 사이에 변경된 내용을, 버전1과 버전2 사이에 변경된 내용을 저장할 수 있습니다. 아래는 diff 명령어로 만든 패치 파일의 내용입니다.

diff --git a/test.c b/test.c
index cd42e6c..ce8ebcb 100644
--- a/test.c
+++ b/test.c
@@ -1,7 +1,7 @@
 #include <stdio.h>

 int main(void) {
-       printf("Hello Ben");
+       printf("Hello Ben tely");
        return 0;
 }

format-patch (추천되는 방법)

우리가 원하는 것은 몇개의 커밋을 골라서 패치를 만드는 것이니 해당 명령어를 소개해드리겠습니다. 먼저 아래 명령어는 하나의 커밋만 골라서 패치파일을 만들어줍니다.

git format-patch cc1dde0dd --stdout > foo.patch

HEAD로부터 몇개의 commit을 지정해서 Patch로 만들수도 있습니다.

git format-patch -"HEAD로 부터 생성할 commit 수" --stdout > foo.patch

만약 커밋의 범위를 정해서 패치파일을 만들고 싶다면 아래와 같이 할 수 있습니다.

git format-patch cc1dde0dd^..6de6d4b06 --stdout > foo.patch

이렇게 하면 처음 지정한 커밋 부터 두 번째 커밋 해시까지의 내용이 패치 파일에 기록됩니다. 커밋 내용이 띄엄띄엄 떨어져있을 경우에는 format-patch를 여러 번 실행해야할 것 같습니다. 이 때는 cherry-pick이 편리합니다.

diff 명령어와는 다르게 format-patch 명령으로 만든 Patch 파일은 커밋한 사람의 정보와 커밋 로그가 포함되어 있습니다. 아래는 format-patch로 만든 패치 파일의 일부 내용입니다.

From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
From: Jessica Smith <jessica@example.com>
Date: Sun, 6 Apr 2008 10:17:23 -0700
Subject: [PATCH 1/2] add limit to log function

Limit log functionality to the first 20

patch 적용하기

git apply 명령어 (diff 사용한 경우)

현재 디렉토리를 기준으로 해당 패치 파일의 내용을 적용합니다.

git apply store_inquiry_qa.patch

patch 명령어를 사용하는 방법도 있는데 그 보다 apply 명령어가 훨씬 더 꼼꼼하게 비교한다. git diff 로 생성한 Patch 파일에 파일을 추가하거나, 파일을 삭제하고, 파일의 이름을 변경하는 내용이 들어 있으면 이런 것도 그대로 적용할 수 있다. patch 명령어로는 할 수 없는 작업이다.

git am 명령어 (format-patch 사용한 경우)

$ git am test.patch
Applying: add limit to log function

patch가 성공하면 자동으로 새로운 커밋이 하나 만들어집니다. 이메일의 From 과 Date 에서 저자 정보가, 이메일의 제목과 메시지에서 커밋 메시지가 추출돼 사용됩니다. 예를 들어 위의 mbox 예제 파일을 적용해서 생성되는 커밋은 아래와 같습니다. 패치를 적용하는 과정에서 충돌이 발생한 경우 merge 할 때와 같이 충돌을 수정해줘야합니다.

$ git log --pretty=fuller -1
commit 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
Author:     Jessica Smith <jessica@example.com>
AuthorDate: Sun Apr 6 10:17:23 2008 -0700
Commit:     Scott Chacon <schacon@gmail.com>
CommitDate: Thu Apr 9 09:19:06 2009 -0700

   add limit to log function

   Limit log functionality to the first 20

0개의 댓글