У нас есть репозиторий Git с более чем 400 коммитами, первая пара десятков из которых была много проб и ошибок. Мы хотим очистить эти коммиты, раздавив многие из них в одну фиксацию. Естественно, что git -rebase - это путь. Моя проблема заключается в том, что она заканчивается конфликтами слияния, и эти конфликты нелегко разрешить. Я не понимаю, почему вообще должны быть какие-либо конфликты, так как я просто раздавил коммиты (не удаляя или не переставляя их). Скорее всего, это показывает, что я не совсем понимаю, как git -ребаза делает свои squashes.
Здесь приведена модифицированная версия скриптов, которые я использую:
repo_squash.sh(это фактически запущенный script):
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(этот script используется только 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 script, и запускал sed script против него, чтобы убедиться, что он делает то, что я хотел это делать (было). Опять же, я даже не знаю, почему возник конфликт, поэтому, похоже, это не так важно, какая стратегия используется. Любые советы или проницательность были бы полезны, но в основном я просто хочу, чтобы эта раздача работала.
Обновлено с дополнительной информацией из обсуждения с 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
, я получаю очень похожее сообщение после нескольких коммитов. Если я сделаю это снова, я получаю еще одно очень похожее сообщение после того, как пара дюжины коммитов. Если я сделаю это еще раз, на этот раз он пройдет около сотни коммитов и даст это сообщение:
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:
На жаворонке (под влиянием комментариев Jefromi) я решил сделать change my repo_squash.sh следующим:
rm -rf repo_squash
git clone repo repo_squash
cd repo_squash/
git rebase --strategy theirs -i bd6a09a484b8230d0810e6689cf08a24f26f287a
И тогда я просто принял оригинальные записи, как есть. I.e, "rebase" не должен был ничего менять. Это закончилось тем же самым результатом, описанным ранее.
Обновление № 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 [email protected]{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 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 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: Может ли кто-нибудь сказать мне, как добавить щедрость к этому? Я не вижу вариант в любом месте на этом экране, находится ли я в режиме редактирования или режиме просмотра.