Почему переоснова мерзавца дает мне конфликты слияния, когда все, что я делаю, давит фиксации?

У нас есть репозиторий Мерзавца с более чем 400 фиксациями, первая пара, дюжина которой было много эмпирических. Мы хотим очистить эти фиксации путем сплющивания многих вниз в единственную фиксацию. Естественно, переоснова мерзавца кажется способом пойти. Моя проблема состоит в том, что это заканчивается с конфликтами слияния, и эти конфликты не легко разрешить. Я не понимаю, почему должны быть любые конфликты вообще, так как я просто давлю фиксации (не удаление или реконструкция). Очень вероятно это демонстрирует, что я не полностью понимаю, как переосновной мерзавцем делает, давит.

Вот измененная версия сценариев, которые я использую:


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

Я оставлю "новое сообщение" содержанием Вашему воображению. Первоначально, я сделал это без "-стратегия их" опция (т.е. использование стратегии по умолчанию, которая, если я понимаю, документация правильно является рекурсивной, но я не уверен, какая рекурсивная стратегия используется), и это также не работало. Кроме того, я должен указать, что с помощью закомментированного кода в 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 приводит к чистому рабочему каталогу. Если я затем делаю a git rebase --continue, Я получаю очень похожее сообщение еще после нескольких фиксаций. Если я затем делаю это снова, я получаю другое очень похожее сообщение после пары дюжины фиксаций. Если я делаю это все снова и снова, на этот раз это проходит приблизительно сто фиксаций и приводит к этому сообщению:

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

"Оба измененных" бита звучат странными мне, так как это было просто результатом выбора. Также стоит отметить, что, если я смотрю на "конфликт", он сводится к одной строке с одной версией, начинающей его с [вкладка] символ и другой с четырьмя пробелами. Это казалось, что могла бы быть проблема с тем, как я настроил свой файл конфигурации, но нет ничего подобного в нем. (Я действительно отмечал, что core.ignorecase имеет значение true, но очевидно клон мерзавца сделал это автоматически. Я не полностью удивлен тем рассмотрением, что первоисточник был на машине 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

Я больше не заставляю "ничего фиксировать" переосновные проблемы, но меня все еще оставляют с другими конфликтами.

Обновление с игрушечным репозиторием, который воссоздает проблему:

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

P.S.: Да, я знаю, что некоторые из Вас съеживаются, когда Вы видите, что я использую emacs в качестве редактора нейтрализации.

P.P.S.: Мы действительно знаем, что должны будем сдуть все наши клоны существующего репозитория после переосновы. (Вроде "Вас не буду повторно основывать репозиторий после того, как он будет опубликован".)

P.P.P.S: кто-либо может сказать мне, как добавить щедрость к этому? Я не вижу опции нигде на этом экране, являюсь ли я в режиме представления или режиме редактирования.

126
задан Ben Hocking 29 June 2010 в 15:36
поделиться

1 ответ

Хорошо, я достаточно уверен, чтобы дать ответ. Возможно, придется его отредактировать, но я думаю, что знаю, в чем ваша проблема.

В вашем тестовом примере игрушечного репо есть слияние - хуже того, слияние с конфликтами. И вы переставляете через слияние. Без -p (который не полностью работает с -i ) слияния игнорируются. Это означает, что все, что вы делали в разрешении конфликтов , отсутствует , когда rebase пытается выбрать следующую фиксацию, поэтому его патч может не применяться. (Я считаю, что это показано как конфликт слияния, потому что git cherry-pick может применить патч, выполнив трехстороннее слияние между исходной фиксацией, текущей фиксацией и общим предком.)

К сожалению, как мы отмечали в комментариях, -i и -p (сохранять слияния) не очень хорошо уживаются. Я знаю, что редактирование / переписывание работает, а перестановка - нет. Однако я полагаю , что он отлично работает с кабачками. Это не задокументировано, но сработало для тестовых случаев, которые я описываю ниже. Если ваш случай намного сложнее, у вас могут возникнуть проблемы с выполнением того, что вы хотите, хотя это все еще возможно. (Мораль истории: очистить с помощью rebase -i перед слиянием .)

Итак, давайте предположим, что у нас есть очень простой случай, когда мы хотим сжать вместе A, B и C:

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

Теперь, как я уже сказал, если в X не было конфликтов, git rebase -i -p работает, как и следовало ожидать.

Если возникают конфликты, все становится немного сложнее.Он отлично справится со сжатием, но затем, когда он попытается воссоздать слияние, конфликты повторится снова. Вам придется решить их снова, добавить в индекс, а затем использовать git rebase --continue , чтобы продолжить. (Конечно, вы можете решить их снова, проверив версию из исходной фиксации слияния.)

Если у вас есть rerere включен в вашем репо ( rerere.enabled установить значение true), это будет намного проще - git сможет re использовать решение re corded re , когда у вас изначально были конфликты, и все, что вам нужно сделать, это проверить его, чтобы убедиться, что он работает правильно, добавить файлы в индекс и продолжить. (Вы можете пойти еще дальше, включив rerere.autoupdate , и он добавит их за вас, так что слияние даже не завершится ошибкой). Однако я предполагаю, что вы никогда не включали rerere, поэтому вам придется решать конфликт самостоятельно. *

* Или вы можете попробовать rerere-train.sh из git-contrib, который пытается «обновить базу данных на основе существующих коммитов слияния» - в основном, он проверяет все коммиты слияния, пытается их слить, и, если слияние не удается, захватывает результаты и показывает их git-rerere . Это могло занять много времени, и я никогда этим не пользовался, но это может быть очень полезно.

64
ответ дан 24 November 2019 в 00:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: