Git으로 커밋을 부분적으로 따기


501

릴리스개발이라는 두 가지 지점에서 작업 하고 있습니다 .

릴리스 브랜치에 커밋 된 일부 변경 사항을 개발 브랜치 로 다시 통합해야한다는 것을 알았습니다 .

문제는 커밋을 모두 필요로하지 않으며 특정 파일의 일부 덩어리 만 필요하다는 것입니다.

git cherry-pick bc66559

트릭을 수행하지 않습니다.

내가 할 때

git show bc66559

나는 diff를 볼 수 있지만 실제로 현재 작업 트리에 부분적으로 적용하는 좋은 방법을 모릅니다.

답변:


792

여기서 당신이 원하는 핵심은 git add -p( -p과 동의어입니다 --patch)입니다. 이는 대화식으로 콘텐츠를 체크인하여 각 덩어리가 들어가야하는지 여부를 결정하고 필요한 경우 수동으로 패치를 편집 할 수 있도록합니다.

체리 픽과 함께 사용하려면 :

git cherry-pick -n <commit> # get your patch, but don't commit (-n = --no-commit)
git reset                   # unstage the changes from the cherry-picked commit
git add -p                  # make all your choices (add the changes you do want)
git commit                  # make the commit!

(git-cherry-pick에는 --no-commit 옵션이 있음을 상기시켜 준 Tim Henigan에게 감사 드리며 재설정해야한다는 점을 지적한 Felix Rabe에게 감사드립니다! 커밋에서 몇 가지만 남겨두고 싶다면 git reset <path>...해당 파일 만 스테이지 해제 할 수 있습니다 .)

물론 add -p필요한 경우 특정 경로를 제공 할 수 있습니다 . 당신이 패치로 시작하는 경우에는 대체 할 수 cherry-pick와 함께 apply.


정말로 git cherry-pick -p <commit>(그 옵션이 존재하지 않는)을 원한다면

git checkout -p <commit>

현재 커밋을 지정한 커밋과 비교하여 해당 diff의 덩어리를 개별적으로 적용 할 수 있습니다. (가) 당신의 부분에있다 병합 충돌 당기는하고 커밋에 관심이 아니에요 커밋이 옵션이 더 유용 할 수있다 (단, 있음. checkout다릅니다 cherry-pick: checkout시도 적용 <commit>완전히 내용의, cherry-pick의 DIFF 적용 부모로부터 지정된 커밋. 즉 checkout, 커밋뿐만 아니라 원하는 것 이상을 적용 할 수 있음을 의미합니다 .)


실제로 git 1.7.5.4의 조언을 따르면 'git add -p'는 이미 색인에 있기 때문에 '변경 사항 없음'이라고 말합니다. 'git add'전에 'git reset HEAD'를 수행해야합니다. 일부 옵션으로 재설정을 피할 수 있습니까?
Felix Rabe

@FelixRabe : 나는 실제로 어떤 점에서 놀라있어 cherry-pick -n분명 하지 않은 변경 사항을두고는 무대 - 협약이 있음을 확실히 --no-commit옵션이 중지 바로 변경이 연출 모두와 함께 즉, 커밋하기 전에. 답변에 재설정을 추가하겠습니다.
Cascabel

1
즉 @Blixt, 현재 지점을 다른 지점에 있지만없는 커밋이 ABCDEF을 경우, git checkout -p <F>않습니다 하지 그냥 당신이 ABCDEF 모두 함께 으깬 얻고 종류의 어떤 부분 당신이 원하는 것을에서 다음을 수행 할 수 있습니다, 당신에게 F의 변경을 얻을 . 이것을 F의 변화 중 일부로 나누는 것은 고통입니다. 반면에 git cherry-pick -n <F>F의 변경 사항 만 가져옵니다. 이러한 변경 중 일부가 충돌하는 경우 제대로 병합하는 방법을 알 수 있도록 도움이됩니다.
Cascabel

변경이 파일 추가 일 때이 문제가 발생했습니다. 이 git reset(가) 파일을 개최 제거 것과는 add -p단지 '를 추가하는 것도'을 말할 것이다.
Ian Grainger


36

원하는 변경 사항이 변경하려는 지점의 헤드에 있다고 가정하면 git checkout을 사용하십시오.

단일 파일의 경우 :

git checkout branch_that_has_the_changes_you_want path/to/file.rb

여러 파일의 경우 데이지 체인 :

git checkout branch_that_has_the_changes_you_want path/to/file.rb path/to/other_file.rb

5
변경 사항뿐만 아니라 전체 파일이 복사됩니다.
제레미 목록

1
이 답변은 지금까지 다른 답변과 마찬가지로 큰 단점이 있습니다. 변경의 원래 작성자를 유지하지 않고 대신 이름으로 커밋합니다. 변화가 좋으면 누군가의 신용을 훔치고, 변화가 나쁘면 스스로를 불 태우고있는 것입니다. git cherry-pick -p를 가질 수있는 방법이없는 것 같고 여전히 존재하지 않습니다.
pfalcon

15

바탕 마이크 Monkiewicz 것은 당신은 또한 제공된 SHA1 / 지점에서 체크 아웃에 하나 이상의 파일을 지정할 수 있습니다 대답합니다.

git checkout -p bc66559 -- path/to/file.java 

그러면 현재 버전의 파일에 적용 할 변경 사항을 대화식으로 선택할 수 있습니다.


5
파일의 현재 버전이 해당 버전과 크게 다르면 문제가됩니다. 커밋에 나타나지 않는 관련없는 많은 변경 사항이 프롬프트됩니다. 또한 실제로 원하는 변경 내용은 원래의 차이가 아니라 현재의 차이로 "가장 변한 형태"로 나타날 수 있습니다. 원하는 원래 차이가 충돌 할 수 있으며 제대로 병합되어야합니다. 여기서는 그런 기회가 없습니다.
Kaz

1

명령 행에 파일 목록을 지정하고 단일 원자 명령으로 모든 작업을 수행하려면 다음을 시도하십시오.

git apply --3way <(git show -- list-of-files)

--3way: 패치가 제대로 적용되지 않으면 Git은 병합 충돌을 일으켜 실행할 수 있습니다 git mergetool. 생략 --3way하면 Git은 깨끗하게 적용되지 않는 패치를 포기하게됩니다.


0

"부분적으로 체리 따기"가 "파일 내에서 일부 변경 사항을 선택하지만 다른 것을 버리는 것"을 의미하는 경우 다음을 가져 와서 수행 할 수 있습니다 git stash.

  1. 전체 체리 따기를하십시오.
  2. git reset HEAD^ 전체 체리 피킹 커밋을 스테이지되지 않은 작업 변경으로 변환합니다.
  3. 이제 git stash save --patch: 대화식으로 원하지 않는 재료를 숨기고 선택하십시오.
  4. 힘내는 작업 복사본에서 숨김 변경 사항을 롤백합니다.
  5. git commit
  6. 원치 않는 변경 사항을 숨기십시오 git stash drop.

팁 : 원치 않는 변경 사항을 숨기면 이름 git stash save --patch junk을 지정하면 (6) 지금 잊어 버리면 나중에 숨김 상태를 인식하게됩니다.


체리 픽을 선택한 다음 재설정하면 숨길 것이 없습니다. 위에서 말했듯이 --no-commit으로 체리 픽을 선택하거나 --hard HEAD ~로 재설정해야합니다. 원하지 않는 것을 선택하여 부정적으로 진행하고 있습니다. 상기 허용 된 해결책은 긍정적 또는 부정적 접근을 허용한다.
Pierre-Olivier Vares

0

사용 git format-patch의 부분 밖으로 슬라이스가 당신에 대해 및 관리 커밋 git am다른 지점에 적용하는

git format-patch <sha> -- path/to/file
git checkout other-branch
git am *.patch
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.