如何使用git filter-branch将文件添加到特定的提交中?

lf5gs5x2  于 2023-05-21  发布在  Git
关注(0)|答案(2)|浏览(166)

我们需要在一个repo上的一个特定的过去提交中添加一些文件,我们准备重写历史,这样它就可以影响到从那个提交的孩子分支出来的所有分支。我们尝试使用git filter-branch,使用add,因为一旦我们将文件添加到提交中,它就不会被添加到子提交中,但是我们找不到合适的参数来阻止它影响一些并发的发散提交。见图片了解。
我们使用这个命令来处理红色提交,但是文件却出现在紫色提交上-为什么?- 它也出现在绿色提交中,我们不希望它影响代码路径,只是出现在红色提交中,然后通过所有子提交和合并继承。
git filter-branch --index-filter "cp C:/Users/asdf/Documents/IdeaProj ects/git-crypt-tests/.gitattributes . && git add .gitattributes" 72c7e292ddd134c04285f3530afc829fd38de4 28..HEAD
我理解错了什么?
谢谢你。

ua4mk5z4

ua4mk5z41#

看起来你认为当你写一个提交范围为A..B时,它会包括边界。但事实并非如此。这个符号是B ^A的缩写,即所有导致B的内容,但不包括所有直到A的内容。这将从范围中删除“下限”A。解决方案是写A~,意思是“A的祖先”:A~..B
此外,由于您确切地知道您想要添加文件到哪些提交以及您不想添加它们,因此您可以限制修订步行者仅列出想要的提交:

git filter-branch --index-filter "cp C:/Users/asdf/Documents/IdeaProjects/git-crypt-tests/.gitattributes . && git add .gitattributes" -- HEAD --not 72c7e29~ ":/Fix Prestapp"

也就是说,你说你希望所有的提交都指向HEAD,但不希望在72c7e29~之前,也不希望在消息以Fix Prestapp开头的提交之前。

3duebb1j

3duebb1j2#

这只是另一种通用的方式来重写任何提交树中的单个提交,而无需构建一个棘手的rev-list。
1.如果不存在,则在提交时创建标记-my-tag
1.说

git filter-branch --index-filter "cp \"<local-path-to-file>\" \"<sourcetree-path-to-dir>\" && git update-index --add \"<sourcetree-path-to-file>\"" -- my-tag --not my-tag^@

或者使用简写代替my-tag --not my-tag^@
my-tag^!
1.如果在步骤(1)中添加了标记,则删除该标记。
它更快,因为不需要知道提交树结构。
如果你想重写一个提交和它的子提交,那么你可以使用git replacegit replace --graft <commit> [<parent>…​])和git filter-repo脚本来将更改传播到子提交中:

更新所有子分支

git replace --graft <commit-child-1> <commit-child-1-parents>
git replace --graft <commit-child-2> <commit-child-2-parents>
...
git replace --graft <commit-child-N> <commit-child-N-parents>

提交修改和清理

git filter-repo --force
git for-each-ref --format="delete %(refname)" refs/replace | git update-ref --stdin

,其中:

  • <commit-child-*>-重写提交的子对象。
  • <commit-child-*-parents>-包含重写提交的提交列表。

所以,在一个简单的单子节点的情况下,它将只是一个带有一个提交的单个调用:

git replace --graft <purple-commit> <rewritten-red-commit>
git filter-repo --force
git for-each-ref --format="delete %(refname)" refs/replace | git update-ref --stdin

注:

如果你试图替换一个文件,并且它在下一个子提交中有更改,例如changelog.txt文件,那么你必须在每个下一个子提交中重写它,否则下一个提交将保留旧文件。在这种情况下,实际上使用git filter-repo与文件文本搜索和替换,而不是文件添加/替换或手动重写每个下一个子提交之前,调用git replace --graft ...

相关问题