Backport从重命名的文件更改

时间:2012-03-19 15:07:05

标签: git cherry-pick

我有两个分支:主干,生产。我在trunk中发现了一个问题,修复并提交了它,推了它。现在它已经过测试,我需要将更改合并到生产分支中作为热修复。我尝试使用樱桃挑选。但是它不起作用,因为修复程序中的更改文件在某些​​重构期间在先前在主干中重命名,我不想将其投入生产。

我不希望合并所有内容,但只接受此提交。樱桃选择失败了“我们删除”冲突(当然,新文件甚至从未存在于生产分支中)。

将更改带入旧文件的正确方法是什么?

7 个答案:

答案 0 :(得分:20)

如果:

  • 你期望/希望Git会检测到在trunk上移动或重命名文件,但它没有,并且
  • 您的存储库有合理数量的文件

...那么你一定要考虑改变你的git配置:

-X rename-threshold

在合并/樱桃选择期间,git可能会在找到合适的重命名匹配之前达到默认文件检查限制(我认为它是400或1000或类似的东西) 。提高此限制可能会导致merge / cherry-pick在搜索重命名的文件时花费更长时间,但它有助于避免我们删除""合并-挑战。

这应该可以解决问题,但是如果重命名的文件很小并且分支之间的变化很大,那么您也可以使用-X rename-threshold=25%设置,例如使用 jQuery.ajax({ type : 'POST', url : custom.ajax_url, dataType : 'json', data : { action : a, id : b, extra : d }, success : c }); 将其从默认的50%降低。

答案 1 :(得分:13)

我会用这个很好的旧补丁:

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

答案 2 :(得分:4)

面对同样的问题,我问了一位同事他会做什么,他的即时回应是:

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 :(得分:2)

如果目录在分支之间重命名,则可以选择对任意数量文件的更改:

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

答案 4 :(得分:0)

这有点棘手。例如,您可以从diff创建一个补丁并将其应用于旧文件。但是为了防止出现这些问题,我建议先在生产分支上进行修复,然后在那里进行测试,然后从生产中合并到主干。

答案 5 :(得分:0)

我遇到了同样的问题,并试图找到解决方案。

我通过使用一系列rebase解决了。 我没有进行任何进一步的测试,所以使用风险自负!

如果您有兴趣在github上查看它:

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

答案 6 :(得分:0)

我制作了一个shell脚本,试图在猜测文件移动时进行挑选(如果你重命名文件本身,只有当你将它移动到另一个文件夹时它才会起作用): 但是:如果提交添加新文件或者它本身重命名文件,它将失败。

#!/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 "$@"