У нас є сховище 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 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
, я отримую дуже схоже повідомлення після ще кількох доручень. Якщо потім я зроблю це ще раз, я отримую ще одне дуже схоже повідомлення через пару десятків доручень. Якщо я це зроблю ще раз, цього разу він проходить близько ста команд, і дає це повідомлення:
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 встановлений на істину, але очевидно, що git-клон зробив це автоматично. Я не зовсім здивований тим, враховуючи, що оригінальне джерело було на машині 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
PS: Так, я знаю, що деякі з вас плазують, коли бачите, як я використовую emacs як резервний редактор.
PPS: Ми знаємо, що нам доведеться підірвати всі наші клони наявного сховища після ребайз. (У рядку "Ви не будете перезавантажувати сховище після його опублікування".)
PPPS: Хто-небудь може сказати мені, як додати до цього суму? Я ніде не бачу опції на цьому екрані, чи перебуваю я в режимі редагування чи режимі перегляду.
rebase --interactive
- це свого роду перелік дій для спроби git. Я сподівався, що вам вдасться звести це до однієї сквош, яка викликала конфлікти, і уникнути всіх зайвих складностей ваших помічників. Інша інформація, яка відсутня, - це коли виникають конфлікти - коли git застосовує патчі, щоб сформувати сквош, або коли він намагається рухатись повз сквош і застосовувати наступний патч? (А ви впевнені, що нічого поганого з вашим GIT_EDITOR не виходить? Ще один голос за простий тестовий випадок.)
rebase -p
одно не користуєтесь )