У нас есть Git-репозиторий с более чем 400 коммитами, первые пару десятков из которых были полны проб и ошибок.Мы хотим очистить эти коммиты, раздавив многих в один коммит.Естественно, 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 их» (т. Е. Используя стратегию по умолчанию, которая, если я правильно понимаю, документация рекурсивна, но я не уверен, какая рекурсивная стратегия используется), и это тоже нет работа.Кроме того, я должен отметить, что, используя закомментированный код в repo_squash_helper.sh, я сохранил исходный файл, над которым работает скрипт sed, и запустил против него скрипт sed, чтобы убедиться, что он делает то, что хотел (это было).Опять же, я даже не знаю, почему будет конфликтом, так что, похоже, не имеет большого значения, какая стратегия используется.Любой совет или понимание были бы полезны, но в основном я просто хочу, чтобы этот сквош работал.
Обновлен с дополнительной информацией из обсуждения с Джефроми:
Перед работой над нашим огромным "настоящим" хранилищем,Я использовал похожие скрипты в тестовом хранилище.Это был очень простой репозиторий, и тест работал без ошибок.
При сбое я получаю следующее сообщение:
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
, я получу очень похожее сообщение после еще нескольких коммитов.Если я сделаю это снова, я получу еще одно очень похожее сообщение после пары дюжин коммитов.Если я сделаю это еще раз, на этот раз он пройдет около ста коммитов и выдаст это сообщение:
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
«Оба измененных» бита звучат для меня странно, так как это был только результат выбора.Стоит также отметить, что, если я посмотрю на «конфликт», он сводится к одной строке, где одна версия начинается с символа [tab], а другая - с четырех пробелов.Это звучало так, как будто это может быть проблемой с тем, как я настроил свой конфигурационный файл, но в этом нет ничего подобного.(Я заметил, что для 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_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: Кто-нибудь может сказать мне, как добавить к этому вознаграждение? Я не вижу опции на этом экране ни в режиме редактирования, ни в режиме просмотра.