Изменения в бэкпорте из переименованного файла - PullRequest
22 голосов
/ 19 марта 2012

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

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

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

Ответы [ 7 ]

23 голосов
/ 16 февраля 2016

Если:

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

... тогда вам определенно стоит подумать об изменении конфигурации git следующим образом:

$ git config merge.renameLimit 999999

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

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

14 голосов
/ 19 марта 2012

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

git show COMMIT_ID -- old/file/name.txt | patch new/file/name.txt
5 голосов
/ 24 февраля 2017

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

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

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

3 голосов
/ 05 февраля 2015

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

git diff ... | sed -e 's|<old dir>|<new dir>|' | git apply -
1 голос
/ 18 мая 2017

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

#!/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 "$@"
0 голосов
/ 02 августа 2012

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

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

Если вам интересно, посмотрите его на github:

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

0 голосов
/ 19 марта 2012

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

...