Ответ 1
Я использовал бы старый старый патч для этого:
git show COMMIT_ID -- old/file/name.txt | patch new/file/name.txt
У меня два ветки: багажник, производство. Я нашел проблему в багажнике, исправил и совершил его, нажал. Теперь он был протестирован, и мне нужно объединить изменения в производственную отрасль в качестве исправления. Я стараюсь использовать вишневый кикер. Однако это не работает, потому что измененный файл в исправлении был переименован в соединительную линию ранее во время некоторого рефакторинга, который я не хочу приводить в действие.
Я не хочу слить все, но возьму только эту фиксацию. Вишневый выбор терпит неудачу с конфликтом "удалены нами" (конечно, новый файл никогда не существовал в производственной ветки).
Каков правильный способ внесения изменений в старый файл?
Я использовал бы старый старый патч для этого:
git show COMMIT_ID -- old/file/name.txt | patch new/file/name.txt
Если:
... тогда вам обязательно нужно будет изменить конфигурацию Git следующим образом:
$ git config merge.renameLimit 999999
Возможно, что во время слияния/вишни, Git бьет по умолчанию контрольный лимит файла (я думаю, это 400 или 1000 или что-то в этом роде), прежде чем он сможет найти подходящее совпадение переименования. Увеличение этого предела может привести к тому, что слияние/выбор вишни займет больше времени, пока он будет искать ваш переименованный файл, но он может помочь избежать проблем с "слиянием".
Это должно сделать трюк, но если ваш переименованный файл был небольшим и изменения между ветвями значительны, вы также можете играть с настройкой -X rename-threshold
, например. опустив его с 50% по умолчанию с помощью -X rename-threshold=25%
.
Столкнувшись с той же проблемой, я спросил коллегу, что он будет делать, и его мгновенный ответ:
git checkout production
git mv production-filename trunk-filename && git commit -m "Just fooling git"
git cherry-pick trunk-commit
git mv trunk-filename production-filename && git commit -m "Undo the damage"
# Now squash the 3 commits
git rebase -i HEAD~3
Работала как прелесть для меня.
Чтобы чередовать изменения в любом количестве файлов, в случае переименования каталога между ветвями:
git diff ... | sed -e 's|<old dir>|<new dir>|' | git apply -
Это довольно сложно. Например, вы можете создать патч из diff и применить его к старому файлу. Но в будущем, чтобы предотвратить эти проблемы, я бы рекомендовал сделать исправления в производственной ветки и сначала проверить ее там, а затем объединить с производством в магистраль.
Я испытываю ту же проблему и пытаюсь найти решение.
Я решил, используя последовательность переустановок. Я не проводил никаких дальнейших испытаний, кроме тех, которые используют на свой страх и риск!
Если вам интересно посмотреть на github:
Я сделал оболочку script, которая пытается сделать вишневый выбор при угадывании перемещения файла (он не работает, если вы переименовали сам файл, только если вы переместили его в другую папку): Однако: в настоящий момент это не удастся, если коммит добавляет новые файлы или сам переименовывает файлы.
#!/bin/bash
#
# Attemps to guess file moves (rename of folders) when cherry-pick'ing.
# Gaspard van Koningsveld
#
[ "$1" == "" ] && echo "usage: $0 <commit-hash-to-cherry-pick>" && exit 1
TMP_PATCH_FILE="temp-cherry-pick-patch"
function abort() {
echo "Aborting"
"rm" -f "$TMP_PATCH_FILE"
exit 1
}
function main() {
echo "Retreiving commit patch..."
"git" show "$1" > "$TMP_PATCH_FILE" || abort
echo "Matching renamed files..."
sedcmds=""
for oldfile in $("grep" -E '(--- a|\+\+\+ b)' "$TMP_PATCH_FILE" | "cut" -c 7- | "sort" | "uniq"); do
[ -f "$oldfile" ] && continue
renamefound=0
oldfilepart="$oldfile"
while [ $renamefound -eq 0 ]; do
possiblefiles=$("git" ls-files "**/$oldfilepart")
if [ "$possiblefiles" != "" ]; then
if [ $("wc" -l <<< "$possiblefiles") == "1" ]; then
echo " $oldfile > $possiblefiles"
sedcmds="$sedcmds s|/$oldfile|/$possiblefiles|g;"
break
else
echo " ERROR: More than one rename possibility found for file $oldfile:"
echo "$possiblefiles"
abort
fi
fi
prevoldfilepart="$oldfilepart"
oldfilepart="${oldfilepart#*/}"
if [ "$prevoldfilepart" == "$oldfilepart" ]; then
echo " ERROR: Could not find rename for $oldfile."
abort
fi
done
done
echo "Renaming files in patch..."
"sed" -i "$sedcmds" "$TMP_PATCH_FILE" || abort
echo "Applying patch as new commit..."
"sed" -i "s/^commit /From commit /;s/^Author: /From: /" "$TMP_PATCH_FILE" || abort
"git" am -3 "$TMP_PATCH_FILE"
"rm" -f "$TMP_PATCH_FILE"
}
main "[email protected]"