我有两个分支:主干,生产。我在主干中发现了一个问题,修复并提交了它,推送了它。现在它已经过测试,我需要将更改合并到生产分支中作为热修复。我尝试使用樱桃采摘。但是它不起作用,因为在一些我不想投入生产的重构过程中,修复程序中更改的文件在早些时候在主干中被重命名。
我不想合并所有东西,但只接受这个提交。樱桃挑选因“被我们删除”冲突而失败(当然,新文件甚至从未存在于生产分支中)。
将更改带入旧文件的正确方法是什么?
我有两个分支:主干,生产。我在主干中发现了一个问题,修复并提交了它,推送了它。现在它已经过测试,我需要将更改合并到生产分支中作为热修复。我尝试使用樱桃采摘。但是它不起作用,因为在一些我不想投入生产的重构过程中,修复程序中更改的文件在早些时候在主干中被重命名。
我不想合并所有东西,但只接受这个提交。樱桃挑选因“被我们删除”冲突而失败(当然,新文件甚至从未存在于生产分支中)。
将更改带入旧文件的正确方法是什么?
如果:
...那么您绝对应该考虑像这样更改您的 git 配置:
$ git config merge.renameLimit 999999
在合并/樱桃选择期间,git 可能会在找到合适的重命名匹配之前达到默认文件检查限制(我认为它是 400 或 1000 或类似的东西)。提高此限制可能会导致合并/樱桃选择在搜索您重命名的文件时花费更长的时间,但它可以帮助避免“被我们删除”的合并挑战。
这应该可以解决问题,但是如果您重命名的文件很小并且分支之间的更改很大,您也可以使用该-X rename-threshold
设置,例如将其从默认的 50% 降低到-X rename-threshold=25%
.
我会为此使用好的旧补丁:
git show COMMIT_ID -- old/file/name.txt | patch new/file/name.txt
面对同样的问题,我问了一位同事他会怎么做,他的第一反应是:
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 -
我制作了一个 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 "$@"
这有点棘手。例如,您可以从差异创建补丁并将其应用于旧文件。但是将来为了防止这些问题,我建议先在生产分支上进行修复并在那里进行测试,然后从生产分支合并到主干。
我遇到了同样的问题,并试图找到解决方案。
我通过使用一系列变基来解决。我没有做过比这些更进一步的测试,所以使用风险自负!
有兴趣的可以去github看看: