Git에서 특정 커밋을 병합하는 방법


1034

GitHub의 저장소에서 지점을 분기하고 나에게 특정한 것을 약속했습니다. 이제 원래 저장소에있는 좋은 기능이 있음을 알았습니다 HEAD.

이전 커밋없이 병합하고 싶습니다. 어떻게해야합니까? 모든 커밋을 병합하는 방법을 알고 있습니다.

git branch -b a-good-feature
git pull repository master
git checkout master
git merge a-good-feature
git commit -a
git push

github과 관련 하여이 작업을 수행하려는 경우이 기사 에서이 단계를 안내합니다. markosullivan.ca/how-to-handle-a-pull-request-to-github
johndpope

답변:


1173

' git cherry-pick'는 귀하의 답변이어야합니다.

기존 커밋이 도입 한 변경 사항을 적용합니다.

읽어 잊지 마세요 bdonlan 의 결과에 대해의 답을 체리 따기이 게시물에 :
"지점에서 모든 커밋을 당겨 다른 특정 커밋을 밀어" , 여기서

A-----B------C
 \
  \
   D

된다 :

A-----B------C
 \
  \
   D-----C'

이 커밋의 문제점은 git이 커밋에 모든 히스토리를 포함시키는 것을 고려한다는 것입니다.

C '는 다른 SHA-1ID를 가지고 있습니다.
마찬가지로, 체리가 한 지점에서 다른 지점으로 커밋을 고르는 것은 기본적으로 패치를 생성 한 다음 적용하여 기록을 잃어 버리는 것과 관련이 있습니다.

커밋 ID가 변경되면 git의 병합 기능이 손상됩니다 (그러나 사용하지 않는 경우 휴리스틱이 있지만).
더 중요한 것은 C가 실제로 B에 정의 된 함수를 사용했다면 함수 종속성을 무시한다는 것 입니다.


1
@ openid000 : "더 세밀한 나뭇 가지": 실제로 bdonlan이 그의 답변에서 제안한 것과 정확히 같습니다.
VonC

8
참고 : "git rebase"도 SHA-1을 변경합니다. "git rebase vs git merge ( stackoverflow.com/questions/804115/git-rebase-vs-git-merge ) 및"git workflow "( stackoverflow.com/questions/457927/… )를 참조하십시오. "합법적입니다.
VonC

1
"fine grained branch", "cherry-pick"및 "rebase"사이에 git을 사용하여 분기의 코드를 관리 할 수있는 모든 가능성이 있습니다.
VonC

@VonC "미세 나뭇 가지"예. 두 개의 지점이 있었으며 한 지점의 특정 시각화 모듈로 업그레이드했습니다. 이 모듈은 다른 모든 코드와 독립적이므로 Cherry-pick은 이러한 변경 사항을 다른 지점에도 적용하는 것이 편리했습니다
Cheeku

1
그러나 병합 할 때 커밋 C '와 C 모두 커밋 기록에서 우선합니다.
Rahul Shah

738

git cherry-pick을 사용하여 단일 커밋을 현재 분기에 자체적으로 적용 할 수 있습니다.

예: git cherry-pick d42c389f


68
체리 따기에 관한 이전 게시물에 +1 ( stackoverflow.com/questions/880957/… ). 나는 위의 자신의 대답으로 자유의 추출물을 복사했습니다.
VonC

4
아마 git cherry-pick d42c또는 git cherry-pick d42c3 작동합니다. 힘내는 똑똑하다. ;)
guneysus

2
치명적인 : 나쁜 개정
Ievgen Naida

2
방금이 명령을 수행했는데 제대로 작동하는 것 같지만 git status를 수행하면 "Commit Nothing, Working Tree clean"이라고 표시됩니다. 비트 버킷 웹 페이지에서 커밋 페이지를 새로 고치면 표시되지 않습니다. 그러나 git log를 실행하면 나타납니다. 그리고 수정 된 코드를 봅니다. 추가 단계를 수행해야하는지 누군가 설명 할 수 있습니까?
Ray

1
불행히도 이것은 질문에 대답하지 않습니다 : 실제로 병합을 생성하지는 않습니다. 를 가리키는 조상이 없습니다 d42c389f. OP는 병합 자체를 만드는 데 신경 쓰지 않았지만 그 차이는 때때로 중요합니다.
LarsH

29

예를 들어서 이해해 봅시다.

X <commit-id>를 가리키는 지점, master 가 있고 Y <sha1>을 가리키는 지점이 있습니다.

어디 Y <커밋 ID> = <마스터> 지점 커밋 - 몇 커밋

이제 Y 브랜치에 대해 마스터 브랜치와 새 브랜치 사이의 커밋을 갭 클로즈해야합니다. 다음은 우리가 따를 수있는 절차입니다.

1 단계:

git checkout -b local origin/new

여기서 local은 지점 이름입니다. 모든 이름을 지정할 수 있습니다.

2 단계:

  git merge origin/master --no-ff --stat -v --log=300

마스터 브랜치에서 새 브랜치로 커밋을 병합하고 병합중인 실제 <n> 개의 커밋에서 한 줄 설명으로 로그 메시지의 병합 커밋을 만듭니다.

Git 병합에 대한 자세한 정보 및 매개 변수는 다음을 참조하십시오.

git merge --help

또한 특정 커밋을 병합 해야하는 경우 다음을 사용할 수 있습니다.

git cherry-pick <commit-id>

Y3d 문장에서 정의를 변경 했 습니까? "이제 Y 지점에 대한 말을"대 "나는 Y를 가리키는 새로운 지점을 가지고", Y와 같은 소리는 커밋로 사용하고 다음 분기가되었다
Purefan

어떻게 병합하고 싶은 지점의 특정 커밋 지점에서이를 수행 할 수 있는지
Kulbhushan Singh

3

필자의 유스 케이스에서도 CI CD가 필요했다. 우리는 개발 및 마스터 분기와 함께 git flow를 사용했습니다. 개발자는 직접 변경 사항을 병합하여 기능 분기의 풀 요청을 통해 개발 또는 개발할 수 있습니다. 그러나 마스터하기 위해 개발 지점의 안정적인 커밋 만 Jenkins를 통해 자동화 된 방식으로 병합합니다.

이 경우 체리 픽을하는 것은 좋은 선택이 아닙니다. 그러나 commit-id에서 local-branch를 만든 다음 해당 local-branch를 병합하여 mvn clean verify (우리는 maven 사용)를 수행합니다. 성공하면 localCheckout = true 옵션 및 pushChanges = false와 함께 maven 릴리스 플러그인을 사용하여 프로덕션 버전 아티팩트를 넥서스로 릴리스하십시오. 마지막으로 모든 것이 성공하면 변경 사항과 태그를 원점으로 보냅니다.

샘플 코드 스 니펫 :

수동으로 완료하면 마스터 상태라고 가정합니다. 그러나 jenkins에서는 repo를 체크 아웃하면 기본 분기 (구성 된 경우 마스터)에 있습니다.

git pull  // Just to pull any changes.
git branch local-<commitd-id> <commit-id>  // Create a branch from the given commit-id
git merge local-<commit-id>  // Merge that local branch to master.
mvn clean verify   // Verify if the code is build able
mvn <any args> release:clean release:prepare release:perform // Release artifacts
git push origin/master  // Push the local changes performed above to origin.
git push origin <tag>  // Push the tag to origin

이것은 당신에게 두려움이없는 합병이나 갈등을 완전히 통제 할 것입니다.

더 나은 옵션이 있으면 언제든지 조언하십시오.


3

주요 답변 은 특정 커밋에서 현재 분기로 변경 사항적용하는 방법을 설명합니다 . 그것이 "병합 방법"의 의미라면 체리 픽을 사용하십시오.

그러나 실제로 병합 을 원한다면, 즉 현재 브랜치의 기존 커밋과 변경 사항을 적용 하려는 커밋 과 같은 두 부모와 의 새로운 커밋을 원한다면 체리 픽은 그것을 달성하지 못합니다.

예를 들어 빌드 프로세스에서 자식 태그를 사용하여 최신 태그를 기반으로 버전 문자열을 자동으로 설정하는 경우 (예 :) 실제 병합 기록을 갖는 것이 바람직 할 수 있습니다 git describe.

cherry-pick 대신 actual을 수행 한 git merge --no-commit다음 원하지 않는 변경 사항을 제거하기 위해 인덱스를 수동으로 조정할 수 있습니다.

브랜치에 A있고 브랜치 끝에 커밋을 병합하려고 한다고 가정하십시오 B.

git checkout A
git merge --no-commit B

이제 두 개의 부모, 현재 팁 커밋 A및 의 커밋을 만들도록 설정했습니다 B. 그러나 B 브랜치에서 이전 커밋의 변경 사항을 포함하여 원하는 것보다 더 많은 변경 사항이 적용될 수 있습니다. 원치 않는 변경 사항을 취소 한 다음 커밋해야합니다.

(작업 디렉토리의 상태와 색인을 병합하기 전의 상태로 다시 설정하는 쉬운 방법이있을 수 있으므로 처음에 원하는 커밋을 선택하기위한 슬레이트가 깨끗합니다. 나는 깨끗한 상태를 달성하는 방법을 모르겠어요. git checkout HEAD그리고 git reset HEAD모두이 방법의 목적을 물리 치고, 병합 상태를 제거 할 것이다.)

따라서 원치 않는 변경 사항을 수동으로 취소하십시오. 예를 들어

git revert --no-commit 012ea56

원치 않는 커밋마다 012ea56.

조정이 끝나면 커밋을 만듭니다.

git commit -m "Merge in commit 823749a from B which tweaked the timeout code"

이제 원하는 변경 사항 만 있고 조상 트리에 기술적으로 B에서 병합했음을 표시합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.