programing

내가 하는 일은 커밋을 지우는 것뿐인데 git-rebase에서 병합 충돌이 발생하는 이유는 무엇입니까?

newstyles 2023. 6. 28. 21:24

내가 하는 일은 커밋을 지우는 것뿐인데 git-rebase에서 병합 충돌이 발생하는 이유는 무엇입니까?

우리는 400개 이상의 커밋이 있는 Git 저장소를 가지고 있습니다. 그 중 처음 몇 개는 많은 시행착오를 겪었습니다.우리는 많은 사람들을 하나의 커밋으로 압축하여 이러한 커밋을 정리하고 싶습니다.당연히, 깃 리베이스는 가야 할 길인 것 같습니다.문제는 병합 충돌로 끝나고 이러한 충돌을 해결하기가 쉽지 않다는 것입니다.저는 커밋을 삭제하거나 재배치하는 것이 아니라 커밋을 삭제하는 것이기 때문에 충돌이 발생해야 하는 이유를 전혀 이해할 수 없습니다.아마도, 이것은 제가 git-rebase가 어떻게 그것을 찌그러뜨리는지 완전히 이해하지 못한다는 것을 보여줍니다.

사용 중인 스크립트의 수정 버전은 다음과 같습니다.


repo_message.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_proxy_proxy.sh(이 스크립트는 repo_proxy에서만 사용됩니다.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_message_list.txt: (이 파일은 repo_proxy_proxy에서만 사용됩니다.sh) s)


# 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 their" 옵션(즉, 문서를 올바르게 이해하는 경우 재귀적인 전략을 사용하지만 어떤 재귀적인 전략이 사용되는지는 확실하지 않음) 없이 이 작업을 수행했지만 역시 제대로 수행되지 않았습니다.또한 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:

종달새(제프롬이의 말에 영향을 받아)에 저는 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

저는 더 이상 "아무것도 저지를 수 없는" 기본적인 문제들을 이해하지 못하지만, 다른 갈등들은 여전히 남아 있습니다.

문제를 다시 생성하는 토이 저장소로 업데이트:

test_messages.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_sqash.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

추신: 네, 제가 emacs를 대체 편집기로 사용하는 것을 보면 움츠러드는 분들이 있다는 것을 압니다.

추신: 우리는 기지를 재배치한 후에 기존 저장소의 모든 복제본을 날려버려야 한다는 것을 알고 있습니다.("게시된 저장소는 게시된 후에 재배치하지 마십시오.")

P.P.P.S: 여기에 현상금을 추가하는 방법을 알려줄 수 있는 사람이 있나요?편집 모드인지 보기 모드인지에 관계없이 이 화면 어디에도 옵션이 표시되지 않습니다.

새 지점을 생성해도 괜찮으시다면 다음과 같이 문제를 처리했습니다.

메인이 되는 것:

# create a new branch
git checkout -b new_clean_branch

# apply all changes
git merge original_messy_branch

# forget the commits but have the changes staged for commit
git reset --soft main        

git commit -m "Squashed changes from original_messy_branch"

좋아요, 저는 답을 제시할 자신이 있습니다.편집을 해야 할 수도 있겠지만, 당신의 문제가 무엇인지 알 것 같습니다.

장난감 재현 사례에 병합이 있습니다. 더 나쁜 것은 충돌과 병합이 있습니다.그리고 당신은 합병을 통해 기반을 재조정합니다. 없이.-p(와) .-i), 병합은 무시됩니다.이는 기본 재배치가 다음 커밋을 선택하려고 할 때 충돌 해결에서 수행한 작업이 존재하지 않으므로 패치가 적용되지 않을 수 있다는 것을 의미합니다. (다음 이유로 병합 충돌로 표시됩니다.)git cherry-pick원래 커밋, 현재 커밋 및 공통 상위 항목 간에 3방향 병합을 수행하여 패치를 적용할 수 있습니다.)

했듯이, 아게도저댓언서것급처럼한에글희가쉽▁unfortun것럼처▁as언한급▁we,ately▁noted.-i그리고.-p사이가 좋지 않습니다.저는 편집/리워드 작업이 가능하다는 것을 알고 있으며, 순서 변경은 불가능합니다.하지만, 저는 그것이 스쿼시와 잘 작동한다고 생각합니다.이 문서는 문서화되어 있지 않지만 아래에 설명한 테스트 사례에 적합합니다.만약 여러분의 경우가 훨씬 더 복잡하다면, 여러분은 여러분이 원하는 것을 하는 데 많은 어려움을 겪을 수도 있습니다. 비록 그것이 여전히 가능하겠지만 말이죠. (도덕적 이야기: 정리하기)rebase -i 병합 전.)

A, B, C를 함께 뭉치려고 하는 아주 간단한 경우를 가정해 보겠습니다.

- o - A - B - C - X - D - E - F (master)
   \             /
    Z -----------

, ▁in, ▁there▁x,없면다▁now▁were.git rebase -i -p당신이 예상했던 대로 작동합니다.

갈등이 생기면 일이 좀 더 까다로워집니다.스퀴즈는 괜찮지만 병합을 다시 만들 때 충돌이 다시 발생합니다. 다시문해인추에다가음한스덱을 git rebase --continue다음으로 이동합니다. (물론 원래 병합 커밋에서 버전을 체크아웃하여 다시 해결할 수 있습니다.)

레포에서 사용하도록 설정한 경우(rerere.enabledtrue로 설정), 이렇게 하면 훨씬 쉬워집니다. Git는 충돌이 발생했을 때의 기록된 해상도를 다시 사용할 수 있으며, 올바르게 작동하는지 확인하고 파일을 인덱스에 추가한 다음 계속하기만 하면 됩니다.(한 걸음 더 멀리, 켜기만 하면 됩니다.rerere.autoupdate그러면 병합이 실패하지 않도록 추가할 수 있습니다.).하지만 리레레를 활성화한 적이 없기 때문에 충돌 해결을 직접 수행해야 합니다.*

또는 git-contrib의 스크립트를 시도할 수 있습니다. 이 스크립트는 "기존 병합 커밋에서 데이터베이스를 다시 삭제"합니다. 기본적으로 모든 병합 커밋을 체크아웃하고 병합을 시도하며 병합이 실패할 경우 결과를 가져와 표시합니다.git-rerere시간이 많이 걸릴 수도 있고, 실제로 사용해 본 적은 없지만, 큰 도움이 될 수도 있습니다.

저는 비슷한 요구 사항을 찾고 있었습니다. 즉, 개발 부서의 중간 커밋을 폐기하는 것이 이 절차가 저에게 효과적이라는 것을 알게 되었습니다.
가 근무하는 에서.

git reset –hard mybranch-start-commit
git checkout mybranch-end-commit . // files only of the latest commit
git add -a
git commit -m”New Message intermediate commits discarded”

비올라 우리는 지점의 시작 커밋에 최근 커밋을 연결했습니다!병합 충돌 문제가 없습니다!나의 학습 연습에서 나는 이 단계에서 이 결론에 도달했습니다. 목적을 위한 더 나은 접근법이 있습니까?

병합 커밋 중 일부를 포함한 긴 커밋 분기에서 정확히 하나의 커밋을 만들려면 모든 변경 사항을 유지한 상태에서 분기를 첫 번째 커밋 전 지점으로 재설정한 다음 다시 지정하는 것이 가장 쉬운 방법입니다.

git reset $(git merge-base origin/master @)
git add .
git commit

를 바꿉니다.origin/master당신이 분기한 지점의 이름과 함께.

add .새로 추가된 파일은 재설정 후 추적되지 않은 것으로 나타나기 때문에 필요합니다.

수동 개입을 최소화하는 위의 @hlidka의 훌륭한 답변을 바탕으로 분기에 없는 마스터에 대한 새로운 커밋을 보존하는 버전을 스쿼시에 추가하고 싶었습니다.

저는 이것들이 쉽게 분실될 수 있다고 믿기 때문입니다.git reset예를 들어 단계를 수행합니다.

# create a new branch 
# ...from the commit in master original_messy_branch was originally based on. eg 5654da06
git checkout -b new_clean_branch 5654da06

# apply all changes
git merge original_messy_branch

# forget the commits but have the changes staged for commit
# ...base the reset on the base commit from Master
git reset --soft 5654da06       

git commit -m "Squashed changes from original_messy_branch"

# Rebase onto HEAD of master
git rebase origin/master

# Resolve any new conflicts from the new commits

:-X및 전략 옵션이 대화형 기본 재배치에서 사용될 때 무시되었습니다.

commit db2b820e2b28da268cc88adff076b396392dfe(2013년 7월, git 1.8.4+),

대화형 기본 재배치에서 병합 옵션 무시 안 함

전략 및 은 병합있 해옵다지수정다서에서 할 수 .git rebase하지만 그와 함께-- interactive그들은 완전히 무시당했습니다.

사인 오프 바이: 아르노 폰테인

은 것은그를 의미합니다.-X이제 전략은 대화형 리베이스뿐만 아니라 일반 리베이스에서도 작동하며, 이제 초기 스크립트가 더 잘 작동할 수 있습니다.

저는 1) 로컬 지점에서 병합 충돌을 해결하고, 2) 더 많은 작은 커밋을 추가하고, 3) 기본을 다시 설정하고 병합 충돌을 발생시키는 더 단순하지만 유사한 문제에 부딪혔습니다.

나를 위해.git rebase -p -i master의 분쟁 위에 앉힐 수 .그것은 원래의 갈등 해결책을 계속 약속했고 다른 사람들을 맨 위에 앉힐 수 있게 해주었습니다.

누군가에게 도움이 되길 바랍니다!

언급URL : https://stackoverflow.com/questions/3133449/why-does-git-rebase-give-me-merge-conflicts-when-all-im-doing-is-squashing-comm