如何通过一个简单的步骤将存储库中 *Foo* 的 *所有* 实例(内容、文件名和提交消息)批量替换为 *Bar*?
How to batch-replace *all* instances (content, filenames and commit messages) of *Foo* to *Bar* in a repo in a single, simple step?
假设我有一个名为 "Hammerstein" 的尚未发布的软件产品的大型存储库,由我是德国著名软件公司 "Apfel" 的员工编写。
有一天,"Apfel" 分拆出 Hammerstein 部门并将其出售给 more 著名公司 "Oráculo",该公司将 "Hammerstein" 重命名为"Reineta" 出于民族自豪感,决定将其开源。
协议要求 所有 对 "Hammerstein" 和 "Apfel" 的引用在存储库中替换为 "Oráculo" 和 "Reineta"。
必须替换所有文件名、所有提交消息、所有内容。
因此,例如:
src/core/ApfelCore/main.cpp
必须变成 src/core/OraculoCore/main.cpp
.
"Add support for Apfel Groupware Server"
的提交信息必须变成"Add support for Oraculo Groupware Server"
字符串ApfelServerInstance* local_apfel
、#define REINETA
和Url("http://apfel.de")
必须变成OraculoServerInstance* local_oraculo
、#define HAMMERSTEIN
等
这也适用于 不再在 HEAD
中的文件。
用最少的人工干预实现它的最简单和最无痛的方法是什么(以便它可以应用于批处理到可能大量 repositories/assets)?
- BFG 可以替换字符串,但它似乎只有
--delete-file
选项,而不是 --rename-file
,即使那样它也不会将模式作为参数
- This approach 似乎只适用于
HEAD
而不是整个历史;我没有运气将它与 --tree-filter
一起使用
in a single, simple step?
不是单一的,也不是那么简单,但有可能:
要更新提交消息,您需要使用 the --msg-filter
of git filter-branch
git filter-branch -f --msg-filter 'sed "s/Apfel/Oraculo/"' -- --all
注意--all
,以便filter in all commits of every branches。
您可能需要多次重复该命令以处理不同的情况。
移动文件(不使用--tree-filter),可参考this answer (and this article),并适配以构建新路径:
git filter-branch --index-filter 'git ls-files -s | \
sed "s,/ApfelCore/,/OraculoCore/," | \
GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && \
mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' \
-- --all
如前所述,BFG can replace all strings; see "How to substitute text from files in git history?"
java -jar bfg.jar --replace-text replacements.txt my-repo.git
The replacements.txt
file should contain all the substitutions you want to do, in a format like this (one entry per line)
Apfel==>Oraculo
apfel==>oraculo
REINETA==>HAMMERSTEIN
完全披露:我是 BFG Repo-Cleaner
的作者
正如您在问题中所说,BFG 支持使用 --replace-text
标志替换文件内容 - 但此标志不会扩展到文件 names 和提交消息。那么,要使 BFG 的 --replace-text
操作也扩展到这些代码库,需要对代码库进行哪些改动?
这归结为挂钩一些用于文件内容更改的新 Cleaner[V]
implementations, where V
is the type of thing you want to clean (a commit message, a directory listing), and the Cleaner
just has the job of producing a new, clean V
from an old, dirty V
. To perform the actual text change, you can re-use the same text-replacing function。
文件名
使用 Cleaner[Seq[Tree.Entry]]
- 'tree' 是 Git 调用文件夹 ('file tree') - 所以你只需更新每个 Tree.Entry
.
提交消息
使用 Cleaner[CommitNode]
- 同样,您只是替换 message
字段中的文本 - 请参阅 CommitMessageObjectIdsUpdater 以了解您要执行的操作的非常接近的示例.当你在那里时,如果你愿意,你可以对作者和提交者的电子邮件地址做一些事情(例如清除 ...@apfel.com
,我猜)。
速度
正如@VonC 在他的回答中提到的,filter-branch
可以 执行这两个替换(文件名和提交消息)但是 --msg-filter
标志应该相当快地完成提交消息更新,我相信 filter-branch
在像您这样的大型代码库中重命名文件会相当 非常慢 。 BFG 正是针对此类操作进行了优化,速度将提高几 100 倍。
BFG 在 https://www.bountysource.com/teams/bfg-repo-cleaner 接受捐赠 - 所以如果您愿意支持此功能的开发,或者如果您发现 BFG 对解决您的问题很有用问题,这就是你可以有所作为的地方。
假设我有一个名为 "Hammerstein" 的尚未发布的软件产品的大型存储库,由我是德国著名软件公司 "Apfel" 的员工编写。
有一天,"Apfel" 分拆出 Hammerstein 部门并将其出售给 more 著名公司 "Oráculo",该公司将 "Hammerstein" 重命名为"Reineta" 出于民族自豪感,决定将其开源。
协议要求 所有 对 "Hammerstein" 和 "Apfel" 的引用在存储库中替换为 "Oráculo" 和 "Reineta"。
必须替换所有文件名、所有提交消息、所有内容。
因此,例如:
src/core/ApfelCore/main.cpp
必须变成src/core/OraculoCore/main.cpp
."Add support for Apfel Groupware Server"
的提交信息必须变成"Add support for Oraculo Groupware Server"
字符串
ApfelServerInstance* local_apfel
、#define REINETA
和Url("http://apfel.de")
必须变成OraculoServerInstance* local_oraculo
、#define HAMMERSTEIN
等
这也适用于 不再在 HEAD
中的文件。
用最少的人工干预实现它的最简单和最无痛的方法是什么(以便它可以应用于批处理到可能大量 repositories/assets)?
- BFG 可以替换字符串,但它似乎只有
--delete-file
选项,而不是--rename-file
,即使那样它也不会将模式作为参数 - This approach 似乎只适用于
HEAD
而不是整个历史;我没有运气将它与--tree-filter
一起使用
in a single, simple step?
不是单一的,也不是那么简单,但有可能:
要更新提交消息,您需要使用 the --msg-filter
of git filter-branch
git filter-branch -f --msg-filter 'sed "s/Apfel/Oraculo/"' -- --all
注意--all
,以便filter in all commits of every branches。
您可能需要多次重复该命令以处理不同的情况。
移动文件(不使用--tree-filter),可参考this answer (and this article),并适配以构建新路径:
git filter-branch --index-filter 'git ls-files -s | \
sed "s,/ApfelCore/,/OraculoCore/," | \
GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && \
mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' \
-- --all
如前所述,BFG can replace all strings; see "How to substitute text from files in git history?"
java -jar bfg.jar --replace-text replacements.txt my-repo.git
The
replacements.txt
file should contain all the substitutions you want to do, in a format like this (one entry per line)
Apfel==>Oraculo
apfel==>oraculo
REINETA==>HAMMERSTEIN
完全披露:我是 BFG Repo-Cleaner
的作者正如您在问题中所说,BFG 支持使用 --replace-text
标志替换文件内容 - 但此标志不会扩展到文件 names 和提交消息。那么,要使 BFG 的 --replace-text
操作也扩展到这些代码库,需要对代码库进行哪些改动?
这归结为挂钩一些用于文件内容更改的新 Cleaner[V]
implementations, where V
is the type of thing you want to clean (a commit message, a directory listing), and the Cleaner
just has the job of producing a new, clean V
from an old, dirty V
. To perform the actual text change, you can re-use the same text-replacing function。
文件名
使用 Cleaner[Seq[Tree.Entry]]
- 'tree' 是 Git 调用文件夹 ('file tree') - 所以你只需更新每个 Tree.Entry
.
提交消息
使用 Cleaner[CommitNode]
- 同样,您只是替换 message
字段中的文本 - 请参阅 CommitMessageObjectIdsUpdater 以了解您要执行的操作的非常接近的示例.当你在那里时,如果你愿意,你可以对作者和提交者的电子邮件地址做一些事情(例如清除 ...@apfel.com
,我猜)。
速度
正如@VonC 在他的回答中提到的,filter-branch
可以 执行这两个替换(文件名和提交消息)但是 --msg-filter
标志应该相当快地完成提交消息更新,我相信 filter-branch
在像您这样的大型代码库中重命名文件会相当 非常慢 。 BFG 正是针对此类操作进行了优化,速度将提高几 100 倍。
BFG 在 https://www.bountysource.com/teams/bfg-repo-cleaner 接受捐赠 - 所以如果您愿意支持此功能的开发,或者如果您发现 BFG 对解决您的问题很有用问题,这就是你可以有所作为的地方。