다음과 같은 저장소 레이아웃이 있습니다.
- 마스터 지점 (생산)
- 완성
- 일
내가 달성하고자하는 것은 작업 지점에서 다양한 커밋을 선택하여 통합 지점으로 병합하는 것입니다. 나는 git을 처음 접했고 저장소를 엉망으로 만들지 않고 정확하게 수행하는 방법 (한 작업에서 커밋 범위의 체리 선택)을 알 수 없습니다. 이것에 대한 조언이나 생각이 있습니까? 감사!
다음과 같은 저장소 레이아웃이 있습니다.
내가 달성하고자하는 것은 작업 지점에서 다양한 커밋을 선택하여 통합 지점으로 병합하는 것입니다. 나는 git을 처음 접했고 저장소를 엉망으로 만들지 않고 정확하게 수행하는 방법 (한 작업에서 커밋 범위의 체리 선택)을 알 수 없습니다. 이것에 대한 조언이나 생각이 있습니까? 감사!
답변:
다양한 커밋에 관해서는 체리 따기 이다 이었다 실용적이지.
마찬가지로 아래 언급 에 의해 키스 김 , 힘내 1.7.2+은 커밋의 범위를-선택 벚꽃 할 수있는 기능을 도입 (그러나 당신은 여전히 알 필요가 미래의 병합에 따기 체리의 결과 )
git cherry-pick "은 다양한 커밋
(예 :"cherry-pick A..B
"및"cherry-pick --stdin
") 을 고르는 방법을 배웠습니다git revert
."rebase [-i]
"도 마찬가지입니다. 그러나 " "는 더 나은 시퀀싱 컨트롤" "을 지원하지 않습니다 .
"
cherry-pick A..B
"형식에서A
보다 오래된 것이어야합니다B
.
순서가 잘못되면 명령이 자동으로 실패 합니다.
당신은 선택하려면 범위 B
를 통해 D
(포함)을 그 것이다 B^..D
.
그림은 " 이전 커밋 범위에서 분기를 생성합니까? "를 참조하십시오 .
이것은
B
루트 커밋이 아니라고 가정합니다 .unknown revision
그렇지 않으면 " "오류가 발생합니다.
참고 : Git 2.9.x / 2.10 (2016 년 3 분기) 기준으로 고아 브랜치 (빈 헤드)에서 직접 커밋 범위를 직접 선택할 수 있습니다 . " git에서 기존 브랜치를 고아로 만드는 방법 "을 참조하십시오 .
원래 답변 (2010 년 1 월)
A는 rebase --onto
당신이 당신의 통합 지점의 상부에 커밋의 지정된 범위를 재생 곳으로, 더 나은 것 찰스 베일리는 여기에 설명 .
(또한, 대한 모습 "여기에 한 가지를 기반으로 주제 분기를 이식 얼마나 또 다른"는에서 자식 REBASE man 페이지 의 실제적인 예를 보려면 git rebase --onto
)
현재 지점이 통합 인 경우 :
# Checkout a new temporary branch at the current location
git checkout -b tmp
# Move the integration branch to the head of the new patchset
git branch -f integration last_SHA-1_of_working_branch_range
# Rebase the patchset onto tmp, the old location of integration
git rebase --onto tmp first_SHA-1_of_working_branch_range~1 integration
그것은 다음 사이의 모든 것을 재생합니다 :
first_SHA-1_of_working_branch_range
(따라서 ~1
) : 재생하려는 첫 번째 커밋integration
"( working
분기 에서 재생하려는 마지막 커밋을 가리킴 )" tmp
"( integration
이전에 가리키는 위치 를 가리킴)
해당 커밋 중 하나가 재생 될 때 충돌이있는 경우 :
git rebase --continue
"를 실행하십시오 .git rebase --skip
" 를 실행하십시오 .git rebase --abort
"로 모든 것을 취소하십시오 (그리고 integration
지점에 지점을 다시 넣으십시오 tmp
)그 후 rebase --onto
, integration
다시 마지막에 될 것입니다 ( "입니다 통합 브랜치의 커밋 tmp
"지점 + 모든 재생 커밋)
체리 따기 또는를 사용하면 여기에 설명 된대로rebase --onto
후속 병합에 영향을 미칩니다 .
순수한 " cherry-pick
"솔루션은 여기 에서 논의 되며 다음과 같은 내용이 포함됩니다.
패치 방식을 사용하려면 "git format-patch | git am"및 "git cherry"을 선택할 수 있습니다.
현재git cherry-pick
커밋 단 하나의 수락,하지만 당신은 범위를 선택하려면B
를 통해D
그 것이다B^..D
자식 용어에서, 그래서
git rev-list --reverse --topo-order B^..D | while read rev
do
git cherry-pick $rev || break
done
어쨌든, 커밋 범위를 "재생"해야 할 때 "replay"라는 단어 rebase
는 Git 의 " "기능 을 사용하도록 강요해야합니다 .
-m
옵션 이 필요한 부모가있는 커밋이있는 경우 해당 커밋을 어떻게 처리합니까? 또는 이러한 커밋을 필터링하는 방법이 있습니까?
-m
는 -m
이 체리 피킹을 위해 선택한 매개 변수가 참조하는 메인 라인을 선택하여 처리합니다 .
-m
체리 피킹 범위의 커밋 범위에서 부모 커밋에 도달했을 때만 옵션을 전달하는 방법이 내 질문에 더 잘 표현되어 있다고 생각 합니까? 지금 내가 전달하는 경우 -m
처럼 git cherry-pick a87afaaf..asfa789 -m 1
그것은 범위 내의 모든 커밋에 적용됩니다.
error: Commit 8fcaf3b61823c14674c841ea88c6067dfda3af48 is a merge but no -m option was given.
실제로 당신이 그냥 할 수 있다는 것을 깨달았을 git cherry-pick --continue
것입니다.하지만 괜찮을 것입니다 (그러나 부모 커밋은 포함되지 않을 것입니다)
git v1.7.2부터 cherry pick은 다양한 커밋을 허용 할 수 있습니다.
git cherry-pick
커밋 범위를 선택하는 법을 배웠습니다 (예 :cherry-pick A..B
및cherry-pick --stdin
)git revert
. 그러나 이것들은 더 나은 시퀀싱 컨트롤rebase [-i]
이 지원하지 않습니다 .
cherry-pick A..B
커밋되지 않습니다 (당신이 필요 A~1..B
그것을 위해), 자동 REBASE처럼 계속되지 않습니다 자식 충돌이있는 경우 수행 (1.7.3.1의 같은 이상)
git cherry-pick A..B C
순진하게 예상대로 작동하지 않는다는 점에 유의하는 것이 좋습니다 . 범위 내의 모든 것을 고르지 않고 A..B
커밋 하지 않습니다 C
! 이렇게하려면 먼저, 두 라인으로 분할해야 git cherry-pick A..B
하고 git cherry-pick C
. 따라서 범위가있을 때마다 별도로 실행해야합니다.
2 개의 지점이 있다고 가정 해 봅시다.
"branchA": 복사하려는 커밋을 포함합니다 ( "commitA"에서 "commitB"로)
"branchB": 커밋을 "branchA"에서 전송할 지점
1)
git checkout <branchA>
2) "commitA"및 "commitB"의 ID를 얻습니다.
삼)
git checkout <branchB>
4)
git cherry-pick <commitA>^..<commitB>
5) 충돌이있는 경우 해결하고 입력하십시오.
git cherry-pick --continue
체리 픽 프로세스를 계속합니다.
실제로 분기를 병합하고 싶지 않습니까? 작업 브랜치에 원하지 않는 최근 커밋이있는 경우 원하는 시점에 HEAD를 사용하여 새 브랜치를 만들 수 있습니다.
이제 어떤 이유로 든 커밋 범위를 선택하고 싶다면 우아한 방법은 패치 세트를 가져 와서 새로운 통합 브랜치에 적용하는 것입니다.
git format-patch A..B
git checkout integration
git am *.patch
이것은 기본적으로 git-rebase 가하는 일이지만 게임을 할 필요가 없습니다. 병합해야 할 경우 추가 --3way
할 수 있습니다 git-am
. 지침을 그대로 따르는 경우,이 작업을 수행하는 디렉토리에 다른 * .patch 파일이 없는지 확인하십시오.
A^
포함 해야합니다 A
.
VonC의 코드 를 간단한 bash 스크립트로 감싸서 git-multi-cherry-pick
쉽게 실행했습니다.
#!/bin/bash
if [ -z $1 ]; then
echo "Equivalent to running git-cherry-pick on each of the commits in the range specified.";
echo "";
echo "Usage: $0 start^..end";
echo "";
exit 1;
fi
git rev-list --reverse --topo-order $1 | while read rev
do
git cherry-pick $rev || break
done
현재 타사 코드와 사용자 정의가 모두 동일한 svn 트렁크에 혼합 된 프로젝트 기록을 재구성 할 때 이것을 사용하고 있습니다. 이제 핵심 사용자 지정 코드, 타사 모듈 및 사용자 지정 내용을 자체 자식 분기로 분할하여 향후 사용자 지정 내용을 더 잘 이해하고 있습니다. git-cherry-pick
같은 저장소에 두 개의 나무가 있지만 공유 조상이 없기 때문에이 상황에서 도움이됩니다.
위의 모든 옵션은 병합 충돌을 해결하라는 메시지를 표시합니다. 팀에 적용한 변경 사항을 병합하는 경우 개발자의 병합 충돌을 해결하고 진행하기가 어렵습니다. 그러나 "git merge"는 한 번에 병합을 수행하지만 다양한 수정 버전을 인수로 전달할 수 없습니다. "git diff"및 "git apply"명령을 사용하여 rev의 병합 범위를 수행해야합니다. 패치 파일에 파일이 너무 많으면 "git apply"가 실패한다는 것을 알았습니다. 따라서 파일 당 패치를 만든 다음 적용해야합니다. 스크립트는 소스 분기에서 삭제 된 파일을 삭제할 수 없습니다. 드문 경우이지만 대상 브랜치에서 해당 파일을 수동으로 삭제할 수 있습니다. 패치를 적용 할 수없는 경우 "git apply"의 종료 상태는 0이 아닙니다.
아래는 스크립트입니다.
enter code here
#!/bin/bash
# This script will merge the diff between two git revisions to checked out branch
# Make sure to cd to git source area and checkout the target branch
# Make sure that checked out branch is clean run "git reset --hard HEAD"
START=$1
END=$2
echo Start version: $START
echo End version: $END
mkdir -p ~/temp
echo > /tmp/status
#get files
git --no-pager diff --name-only ${START}..${END} > ~/temp/files
echo > ~/temp/error.log
# merge every file
for file in `cat ~/temp/files`
do
git --no-pager diff --binary ${START}..${END} $file > ~/temp/git-diff
if [ $? -ne 0 ]
then
# Diff usually fail if the file got deleted
echo Skipping the merge: git diff command failed for $file >> ~/temp/error.log
echo Skipping the merge: git diff command failed for $file
echo "STATUS: FAILED $file" >> /tmp/status
echo "STATUS: FAILED $file"
# skip the merge for this file and continue the merge for others
rm -f ~/temp/git-diff
continue
fi
git apply --ignore-space-change --ignore-whitespace --3way --allow-binary-replacement ~/temp/git-diff
if [ $? -ne 0 ]
then
# apply failed, but it will fall back to 3-way merge, you can ignore this failure
echo "git apply command filed for $file"
fi
echo
STATUS=`git status -s $file`
if [ ! "$STATUS" ]
then
# status is null if the merged diffs are already present in the target file
echo "STATUS:NOT_MERGED $file"
echo "STATUS: NOT_MERGED $file$" >> /tmp/status
else
# 3 way merge is successful
echo STATUS: $STATUS
echo "STATUS: $STATUS" >> /tmp/status
fi
done
echo GIT merge failed for below listed files
cat ~/temp/error.log
echo "Git merge status per file is available in /tmp/status"
Vonc에 대한 명확한 설명을 읽은 후 며칠 전에 테스트했습니다.
dev
: ABCDEFGHIJtarget
: ABCDE
도 않고H
dev_feature_wo_E_H
git checkout dev
git checkout -b dev_feature_wo_E_H
git rebase --interactive --rebase-merges --no-ff D
내가 rebase 편집기의 drop
앞 E
과 H
뒤에 놓은 곳commit
dev_feature_wo_E_H
대상에 분기를 복사하는 단계 입니다.git checkout target
git merge --no-ff --no-commit dev_feature_wo_E_H
commit
cherry-pick
전날 에 너무 많이했기 때문에git cherry-pick
강력하고 단순하지만
merge
초기 커밋과 중복 커밋의 충돌을 해결해야 할 때 하나 또는 두 개의 cherry-pick
경우 "체리 피킹"해도 괜찮지 만 더 자세한 것은 너무 복잡하고 지점이 너무 복잡해집니다.git rebase --onto