我想用一些代码重新格式化和其他代码过滤器来重放git repo ......是的,我知道这样做的所有风险。
不幸的是,这需要很长时间,不可能长时间冻结工作。我知道如何在某个时候重播分支。
我正在寻找的是如何从另一个回购重播分支并获得resume
的想法。
基本上是伪代码中的算法:
starting_sha = very_last
if resume {
starting_sha = last_applied_sha
}
for_each sha = commit --reversed from starting_sha to the HEAD {
git checkout sha
apply some changes to the code
git commit to target repo with metadata from sha
update last_applied_sha = sha
}
显然,我可以很容易地实现这样的脚本,但是git commit to target repo with metadata from sha
是我希望我不需要自己处理的事情。
我希望有一些git filter-branch
类型的功能可以让我这样做,而不需要自己处理标签和任何其他内部。
答案 0 :(得分:2)
1。通过克隆源来设置目标存储库。
$ git clone <sourceRepo>
2。查看相关分支。将branchname
替换为实际的分支名称(同样在以下所有步骤中)。
$ git checkout branchname
3。使用filter-branch
和--tree-filter
进行初始重写,使用--tag-name-filter
更新流程中的代码。这只是一个示例过滤器,它在匹配“* .txt”glob的所有文件中替换第一次出现的“text”和“modified”。
$ git filter-branch --tree-filter 'sed -i "s/text/modified/" *.txt' --tag-name-filter cat -- branchname
4。创建一个标记以保留最后一个源和目标转速的记录。
$ git tag lastsourcerev origin/branchname
$ git tag lasttargetrev branchname
现在,无论何时从源代码库更新到新修订版,都可以使用以下步骤。它们只将树过滤器应用于新的提交,并将新的(重写的)提交移植到现有的(以前重写的)提交。
1。从源代码中获取新的提交/标记:
$ git fetch origin
2。重置为源分支的新提示。
$ git reset --hard origin/branchname
3。使用额外filter-branch
应用--parent-filter
以将新提交移植到现有提交。请注意,我们需要-f
(强制)选项作为前一个filter-branch
命令refs/original
。 --parent-filter
使用存储最后源和目标转速的标签。整个filter-branch
仅限于上次处理的源rev和最新的源提交(我们将branchname
重置为)之间的提交。
$ git filter-branch -f --tree-filter 'sed -i "s/text/modified/" *.txt' --tag-name-filter cat --parent-filter "sed s/$(git rev-parse lastsourcerev)/$(git rev-parse lasttargetrev)/g" -- lastsourcerev..branchname
4。将跟踪代码更新为新情况:
$ git tag -f lastsourcerev origin/branchname
$ git tag -f lasttargetrev branchname
根据需要重复这些步骤。一旦不再进行更新,就可以删除lastsourcerev
和lasttargetrev
帮助程序标记。
请注意,通过将分支重置为源之间的某些中间提交和提交为lastsourcerev
的记录,可以将更新过程任意分割为更小的增量。同样,初始重写可以通过创建一个分支来分割,该分支指向来自源的中间提交并将其记录为lastsourcerev
,然后应用更新步骤以进一步。
另请注意,此过程仅依赖于filter-branch
,以避免任何有关标记重写或合并提交的问题,这些问题会导致重新设置新的传入提交,否则将不可避免地导致这些问题。
作为shell脚本打包,增量更新部分可能如下所示:
#!/bin/sh
REMOTE=origin
LOCAL_BRANCH=master
REMOTE_BRANCH=origin/master
SOURCE_REV_TAG=lastsourcerev
TARGET_REV_TAG=lasttargetrev
TREE_FILTER='sed -i "s/text/modified/" *.txt'
set -e
git fetch "$REMOTE"
if [ $(git rev-parse "$SOURCE_REV_TAG") = $(git rev-parse "$REMOTE_BRANCH") ]
then
echo "no new commits, nothing to do"
exit 0
fi
git checkout "$LOCAL_BRANCH"
git reset --hard "$REMOTE_BRANCH"
git filter-branch -f --tree-filter "$TREE_FILTER" \
--tag-name-filter cat \
--parent-filter "sed s/$(git rev-parse "$SOURCE_REV_TAG")/$(git rev-parse "$TARGET_REV_TAG")/g" \
-- "$SOURCE_REV_TAG"..
git tag -f "$SOURCE_REV_TAG" "$REMOTE_BRANCH"
git tag -f "$TARGET_REV_TAG"
出现的唯一边缘情况是没有新的提交可用。在这种情况下,git reset --hard
会将本地分支更新为远程分支,但是不会应用过滤步骤,因为不会重写转速。上面的脚本通过检查源rev跟踪标记是否指向与远程分支相同的提交来处理它。
答案 1 :(得分:0)
您可以应用git filter-branch
而不是交互式rebase,它将访问您的repo的每次提交并应用您想要的任何实用程序(或代码重新格式化)。
由于filter-branch是一个本地操作,因此不需要另一个&#34;另一个&#34; repo:你把它应用到你的回购的本地克隆 请注意它does not support a pause/resume workflow,因此您需要让它处理完成。
参见&#34; Reformatting Your Codebase with git filter-branch&#34; (以 Elliot Chance )为例:
git filter-branch --tree-filter 'phpcbf $(\
git show $GIT_COMMIT --name-status | egrep ^[AM] |\
grep .php | cut -f2)' -- --all
对于每次提交,仅查找添加/修改的文件,隔离php文件并应用格式化工具。
这并不妨碍任何人在此期间提交 您的协作者需要克隆新的(格式化的)仓库,在新仓库的(新格式化的)分支历史记录之上添加他们自己的远程,获取和重新定位他们自己的提交(只有新的提交)。 /> 换句话说,每个协作者都要完成一个协调步骤,以便整合重组期间完成的工作。
如果没有,则需要反转该过程,并且您的新repo必须添加旧的repo(每个人都有推送,假设最近的提交格式正确)作为远程(名为&#39; {{1} }&#39;):
oldRepo
cd /path/to/new/repo
git remote add oldRepo /path/to/old/central/repo
git fetch oldRepo
)git branch --contains
这将在分支上检测到旧提交的父级后重播所有提交&#39; git rebase --onto abranch acommit~ oldRepo/abranch
&#39;到新的repo oldRepo/abranch
(由于在重新编写新的repo时它们已完成并被推送,因此缺少提交)