우리는 400 개가 넘는 커밋을 가진 Git 저장소를 가지고 있는데, 그 중 첫 12 개는 많은 시행 착오를 겪었습니다. 많은 커밋을 단일 커밋으로 스쿼시하여 커밋을 정리하고 싶습니다. 당연히 git-rebase는 갈 길입니다. 내 문제는 병합 충돌로 끝나고 이러한 충돌을 해결하기 쉽지 않다는 것입니다. 커밋을 삭제하거나 재 배열하지 않기 때문에 왜 충돌이 발생 해야하는지 이해하지 못합니다. 아마도 이것은 git-rebase가 과즙을 어떻게 수행하는지 완전히 이해하지 못하고 있음을 보여줍니다.
사용중인 스크립트의 수정 된 버전은 다음과 같습니다.
repo_squash.sh (실제로 실행되는 스크립트) :
rm -rf repo_squash
git clone repo repo_squash
cd repo_squash/
GIT_EDITOR=../repo_squash_helper.sh git rebase --strategy theirs -i bd6a09a484b8230d0810e6689cf08a24f26f287a
repo_squash_helper.sh (이 스크립트는 repo_squash.sh에서만 사용됨) :
if grep -q "pick " $1
then
# cp $1 ../repo_squash_history.txt
# emacs -nw $1
sed -f ../repo_squash_list.txt < $1 > $1.tmp
mv $1.tmp $1
else
if grep -q "initial import" $1
then
cp ../repo_squash_new_message1.txt $1
elif grep -q "fixing bad import" $1
then
cp ../repo_squash_new_message2.txt $1
else
emacs -nw $1
fi
fi
repo_squash_list.txt : (이 파일은 repo_squash_helper.sh에서만 사용됨)
# Initial import
s/pick \(251a190\)/squash \1/g
# Leaving "Needed subdir" for now
# Fixing bad import
s/pick \(46c41d1\)/squash \1/g
s/pick \(5d7agf2\)/squash \1/g
s/pick \(3da63ed\)/squash \1/g
나는 "새 메시지"내용을 당신의 상상에 맡기겠습니다. 처음에는 "--strategy theirs"옵션없이이 작업을 수행했습니다 (즉, 기본 전략을 사용하여 문서를 올바르게 이해하는 경우 재귀 적이지만 어떤 재귀 적 전략이 사용되는지 잘 모르겠습니다). 작동하지 않습니다. 또한 repo_squash_helper.sh의 주석 처리 된 코드를 사용하여 sed 스크립트가 작동하는 원본 파일을 저장하고 sed 스크립트를 실행하여 원하는 작업을 수행했는지 확인했습니다. 그랬습니다). 다시 말하지만, 왜 충돌 이 일어날 지조차 알지 못하므로 어떤 전략이 사용되는지는 중요하지 않습니다. 조언이나 통찰력이 도움이 될 수 있지만 대부분이 스쿼시 작업을 원합니다.
Jefromi와의 토론에서 추가 정보로 업데이트되었습니다.
방대한 "실제"리포지토리에서 작업하기 전에 테스트 리포지토리에서 비슷한 스크립트를 사용했습니다. 매우 간단한 저장소였으며 테스트는 깨끗하게 진행되었습니다.
실패했을 때 나타나는 메시지는 다음과 같습니다.
Finished one cherry-pick.
# Not currently on any branch.
nothing to commit (working directory clean)
Could not apply 66c45e2... Needed subdir
이것은 첫 번째 스쿼시 커밋 후 첫 번째 선택입니다. 실행 git status
하면 깨끗한 작업 디렉토리가 생성됩니다. 그런 다음을 수행 git rebase --continue
하면 몇 가지 커밋 후에 매우 비슷한 메시지가 나타납니다. 그런 다음 다시 수행하면 수십 개의 커밋 후에 매우 비슷한 메시지가 나타납니다. 다시 한 번 수행하면 이번에는 약 100 개의 커밋을 거쳐 다음 메시지가 나타납니다.
Automatic cherry-pick failed. After resolving the conflicts,
mark the corrected paths with 'git add <paths>', and
run 'git rebase --continue'
Could not apply f1de3bc... Incremental
그런 다음을 실행하면 다음을 git status
얻습니다.
# Not currently on any branch.
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: repo/file_A.cpp
# modified: repo/file_B.cpp
#
# Unmerged paths:
# (use "git reset HEAD <file>..." to unstage)
# (use "git add/rm <file>..." as appropriate to mark resolution)
#
# both modified: repo/file_X.cpp
#
# Changed but not updated:
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# deleted: repo/file_Z.imp
"수정 된"비트는 이상하게 들립니다. 왜냐하면 이것은 선택의 결과 일뿐입니다. "충돌"을 살펴보면 하나의 버전이 [탭] 문자로 시작하고 다른 하나는 4 개의 공백이있는 한 줄로 요약됩니다. 구성 파일을 설정하는 방법에 문제가있는 것처럼 들리지만 그 안에는 아무것도 없습니다. (core.ignorecase가 true로 설정되어 있지만 git-clone이 자동으로 수행 한 것으로 나타났습니다. 원래 소스가 Windows 시스템에 있다는 점을 고려해도 전혀 놀랍지 않습니다.)
file_X.cpp를 수동으로 수정하면 나중에 다른 충돌로 인해 실패합니다. 이번에는 한 버전이 존재한다고 생각하는 파일 (CMakeLists.txt)과 한 버전이 존재하지 않아야한다고 생각합니다. 내가이 파일을 원한다고 말 함으로써이 갈등을 고치면 (약간의 커밋) 나중에 약간의 변경 사항이있는 또 다른 갈등 (이 동일한 파일에서)이 발생합니다. 그것은 여전히 갈등의 약 25 %입니다.
또한이 프로젝트가 svn 저장소에서 시작되었다는 것이 매우 중요하기 때문에 지적해야합니다. 초기 기록은 해당 svn 저장소에서 가져온 것 같습니다.
업데이트 # 2 :
나는 Jefromi의 의견에 영향을받는 종달새에서 repo_squash.sh를 다음과 같이 변경하기로 결정했습니다.
rm -rf repo_squash
git clone repo repo_squash
cd repo_squash/
git rebase --strategy theirs -i bd6a09a484b8230d0810e6689cf08a24f26f287a
그런 다음 원래 항목을 그대로 수락했습니다. 즉, "리베이스"는 변경되지 않아야합니다. 그것은 앞에서 설명한 것과 같은 결과로 끝났습니다.
업데이트 # 3 :
또는 전략을 생략하고 마지막 명령을 다음과 같이 바꾸면
git rebase -i bd6a09a484b8230d0810e6689cf08a24f26f287a
더 이상 "커밋 할 사항 없음"rebase 문제가 발생하지 않지만 여전히 다른 충돌이 남아 있습니다.
문제를 재현하는 장난감 저장소로 업데이트하십시오.
test_squash.sh (실제로 실행되는 파일) :
#========================================================
# Initialize directories
#========================================================
rm -rf test_squash/ test_squash_clone/
mkdir -p test_squash
mkdir -p test_squash_clone
#========================================================
#========================================================
# Create repository with history
#========================================================
cd test_squash/
git init
echo "README">README
git add README
git commit -m"Initial commit: can't easily access for rebasing"
echo "Line 1">test_file.txt
git add test_file.txt
git commit -m"Created single line file"
echo "Line 2">>test_file.txt
git add test_file.txt
git commit -m"Meant for it to be two lines"
git checkout -b dev
echo Meaningful code>new_file.txt
git add new_file.txt
git commit -m"Meaningful commit"
git checkout master
echo Conflicting meaningful code>new_file.txt
git add new_file.txt
git commit -m"Conflicting meaningful commit"
# This will conflict
git merge dev
# Fixes conflict
echo Merged meaningful code>new_file.txt
git add new_file.txt
git commit -m"Merged dev with master"
cd ..
#========================================================
# Save off a clone of the repository prior to squashing
#========================================================
git clone test_squash test_squash_clone
#========================================================
#========================================================
# Do the squash
#========================================================
cd test_squash
GIT_EDITOR=../test_squash_helper.sh git rebase -i HEAD@{7}
#========================================================
#========================================================
# Show the results
#========================================================
git log
git gc
git reflog
#========================================================
test_squash_helper.sh (test_sqash.sh에서 사용) :
# If the file has the phrase "pick " in it, assume it's the log file
if grep -q "pick " $1
then
sed -e "s/pick \(.*\) \(Meant for it to be two lines\)/squash \1 \2/g" < $1 > $1.tmp
mv $1.tmp $1
# Else, assume it's the commit message file
else
# Use our pre-canned message
echo "Created two line file" > $1
fi
추신 : 네, 이맥스를 폴백 편집기로 사용하는 것을 보았을 때 여러분 중 일부가 울부 짖는 것을 알고 있습니다.
PPS : 리베이스 후 기존 리포지토리의 모든 클론을 날려 버려야한다는 것을 알고 있습니다. ( "저장소를 게시 한 후에 저장소를 리베이스하지 않아야한다"는 내용과 함께)
PPPS : 누구나 현상금을 추가하는 방법을 알려줄 수 있습니까? 편집 모드 또는보기 모드에 관계 없이이 화면의 어느 곳에서도 옵션이 표시되지 않습니다.
rebase --interactive
이들은 git이 시도하는 조치 목록입니다. 충돌을 일으키는 단일 스쿼시로 이것을 줄이고 도우미 스크립트의 모든 추가 복잡성을 피할 수 있기를 바랍니다. 다른 누락 된 정보는 충돌이 발생할 때입니다-git이 스쿼시를 형성하기 위해 패치를 적용 할 때 또는 스쿼시를 지나서 다음 패치를 적용하려고 할 때? (그리고 당신은 GIT_EDITOR kludge에 아무런 문제가 없다고 확신하십니까? 간단한 테스트 사례에 대한 또 다른 투표입니다.)
rebase -p
어쨌든 사용하지 않더라도 )