24

我有两个分支:主干,生产。我在主干中发现了一个问题,修复并提交了它,推送了它。现在它已经过测试,我需要将更改合并到生产分支中作为热修复。我尝试使用樱桃采摘。但是它不起作用,因为在一些我不想投入生产的重构过程中,修复程序中更改的文件在早些时候在主干中被重命名。

我不想合并所有东西,但只接受这个提交。樱桃挑选因“被我们删除”冲突而失败(当然,新文件甚至从未存在于生产分支中)。

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

4

7 回答 7

28

如果:

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

...那么您绝对应该考虑像这样更改您的 git 配置:

$ git config merge.renameLimit 999999

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

这应该可以解决问题,但是如果您重命名的文件很小并且分支之间的更改很大,您也可以使用该-X rename-threshold设置,例如将其从默认的 50% 降低到-X rename-threshold=25%.

于 2016-02-16T05:48:07.187 回答
14

我会为此使用好的旧补丁:

git show COMMIT_ID -- old/file/name.txt | patch new/file/name.txt
于 2012-03-19T16:02:24.373 回答
7

面对同样的问题,我问了一位同事他会怎么做,他的第一反应是:

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

对我来说就像一个魅力。

于 2017-02-24T12:15:30.643 回答
3

在分支之间重命名目录的情况下,要挑选对任意数量文件的更改:

git diff ... | sed -e 's|<old dir>|<new dir>|' | git apply -
于 2015-02-05T13:55:53.420 回答
1

我制作了一个 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 "$@"
于 2017-05-18T02:29:36.527 回答
0

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

于 2012-03-19T15:33:29.277 回答
0

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

我通过使用一系列变基来解决。我没有做过比这些更进一步的测试,所以使用风险自负!

有兴趣的可以去github看看:

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

于 2012-08-02T11:42:54.993 回答