2012-03-19 2 views
17

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

Я не хочу слить все, но возьму только эту фиксацию. Вишневый выбор терпит неудачу с конфликтом «удалил нас» (конечно, новый файл никогда не существовал в производственной ветви).

Каков правильный способ внесения изменений в старый файл?

ответ

11

Я хотел бы использовать хороший старый патч для этого:

git show COMMIT_ID -- old/file/name.txt | patch new/file/name.txt 
+1

Да, это работает для меня. Однако было бы интересно найти лучшее решение, особенно в случае, если есть несколько переименованных файлов. – kan

0

Это довольно сложно. Например, вы можете создать патч из diff и применить его к старому файлу. Но в будущем, чтобы предотвратить эти проблемы, я бы рекомендовал делать исправления в производственной отрасли и сначала проверить ее там, а затем объединить с производством в багажник.

+0

Да, я понимаю, что, однако, не всегда можно предсказать, что будет входить в hot-fix. Я пытаюсь сделать это через 'format-patch' /' apply-patch', но он ничего не делает (никаких ошибок, никаких изменений тоже). Пожалуйста, дайте намек на правильный способ его использования. – kan

+2

Ознакомьтесь с разделом «Переименовать обработку в git» в этом посте http://blogs.atlassian.com/2011/10/confluence_git_rename_merge_oh_my/ – ralphtheninja

0

Я испытываю такую ​​же проблему и попытались найти решение.

Я решил использовать последовательность переустановок. Я не делал никаких дальнейших испытаний, чем эти, поэтому используйте на свой страх и риск!

Если вы как раз заинтересованы посмотреть на него на GitHub:

https://github.com/fraschfn/cherry-pick

2

Чтобы вишню забрать изменения в любом количестве файлов, в случае каталога переименовывать между ветвями:

git diff ... | sed -e 's|<old dir>|<new dir>|' | git apply - 
14

Если:

  • Вы ожидали/надеялись, что Git обнаружит движение или переименование файл на стволе, но это не так, и
  • Ваше хранилище имеет разумное количество файлов

... то вы должны обязательно рассмотреть вопрос о смене GIT конфигурации, как это:

$ git config merge.renameLimit 999999 

Возможно, что во время слияния/вишни, git бьет по умолчанию по умолчанию (я думаю, что это 400 или 1000 или что-то в этом роде), прежде чем он сможет найти подходящее совпадение переименования. Увеличение этого предела может привести к тому, что слияние/выбор вишни займет больше времени, пока он будет искать ваш переименованный файл, но он может помочь избежать проблем с объединением «удаленных нами».

Это должно сделать трюк, но если ваш переименованный файл был небольшим, а изменения между ветвями значительны, вы также можете сыграть с настройкой -X rename-threshold, например. опустив его с 50% по умолчанию на -X rename-threshold=25%.

+2

Примечание для 'rename-threshold' для других пользователей - это включает все изменения с течением времени. У меня было слияние, где исходное переименование изменило две строки в файле, но поскольку он был сильно изменен * после * этой точки, git все еще не обнаружил сходство файлов, не уменьшая «переименование-порог». – zebediah49

3

Столкнувшись с такой же проблемой, я спросил коллегу, что он будет делать, и его мгновенный ответ был:

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 

Работал как шарм для меня.

+2

Это работало от меня. Я использовал графический интерфейс, но выполнял те же шаги. Мне потребовалось минутку, чтобы понять, что это делает, поэтому я перечислю следующие шаги: 1. Переименуйте файлы/каталоги в ветке назначения, чтобы они соответствовали ветке источника и фиксации. 2. Черрипик переход от ветви источника к ветке назначения. 3. Переименуйте файлы/каталоги в ветке назначения назад, как они были изначально и совершили. 4. Сквош эти 3 фиксации в одну фиксацию. – Tolli

0

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

#!/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]" 
Смежные вопросы