繁体   English   中英

将Git存储库从ISO-8859-1切换为源代码文件的UTF-8编码

[英]Switching a Git repository from ISO-8859-1 to UTF-8 encoding for source code files

我将在本周末使用快速导出将大型Mercurial项目转换为Git。 我已经多次测试了,结果很好。

我们还希望将我们的源代码编码(许多德语注释/字符串文字与Umlauts)从ISO-8859-1转换为UTF-8(repo中的所有其他非java文件应保持原样),并且Git迁移为我们提供了一个机会,因为每个人都需要再次克隆。 但是,我找不到一个好的方法。

  1. 我已经尝试过git filter-tree --tree-filter ...方法来评论SO 然而,虽然这似乎是理想的,但由于存储库的大小(大约200000次提交,18000个代码文件),它将花费比我周末更多的时间。 我已经尝试运行它(在一个高度优化的版本中,文件列表被分块并且子列表并行转换(使用GNU并行 ))直接来自具有72个内核的Linux VM上的64GB tmpfs卷,但它仍然会需要几天......
  2. 或者,我尝试了一种简单的方法,我只需在任何活动分支上单独执行转换并提交更改。 但是,结果并不令人满意,因为在合并或挑选转换前提交时,我几乎总会遇到冲突。
  3. 现在我再次但未运行的方法1试图重写所有分支的完整历史记录( --all<rev-list> ),但都只是一些过去的承诺是承诺从目前活跃的分支到达和不可到达(希望)所有当前分支的前身( branch-a branch-b branch-c --not old-tag-before-branch-abc-forked-off as <rev-list> )。 它仍在运行,但我担心我不能真正相信结果,因为这似乎是一个非常糟糕的主意。
  4. 我们可以像在方法2中那样使用正常提交来切换主分支中的编码,但是这也将使得从/掌握灾难的挑选修复。 它会引入许多编码问题,因为开发人员在主转换和非转换分支之间切换时肯定会忘记更改其IDE设置。

所以现在,我觉得最好的解决办法就是坚持使用ISO-8859-1。

有没有人有想法? 有人提到, reposurgeon可能基本上接近1使用其transcode操作,其性能比git filter-tree --tree-filter ...但我不知道它是如何工作的。

git filter-branch树过滤git filter-branch本质上很慢。 它的工作原理是将每个提交提取到一个临时目录中的完整树中,让您更改每个文件,然后找出您更改的内容并从您留下的每个文件中进行新提交。

如果您通过快速导出/快速导入导出和导入, 那么就是转换数据的时间:在将文件写入内容之前,您在文件系统中将扩展的文件数据放在内存中,而不是文件系统形式。出口/进口管道。 而且, git fast-import本身就是一个shell脚本,因此在那里插入过滤是微不足道的,而hg-fast-export是一个Python程序,因此在那里插入过滤也很简单。 显而易见的地方就在这里 :只需重新编码d

您可以考虑使用git filter-branch --index-filter -as,而不是--tree-filter (这是默认值)。 这个想法是使用--index-filter ,没有结帐步骤(即每次迭代都没有(重新)填充工作树)。

所以你可以考虑为git filter-branch --index-filter编写一个过滤git filter-branch --index-filter ,它将使用git ls-files东西:

  1. 调用git ls-files --cached --stage并遍历每个条目。

    仅考虑那些具有100644文件模式的文件 - 即普通文件。

  2. 对于每个条目运行的东西

     sha1=`git show ":0:$filename" \\ | iconv -f iso8859-1 -t utf-8 \\ | git hash-object -t blob -w --stdin` git update-index --cacheinfo "10644,$sha1,$filename" --info-only 
  3. 冲洗,重复。

我想要的另一种方法是从不同的角度解决问题:由git fast-export生成并由git fast-import消耗的流的格式是纯文本¹(只需将导出器的输出传输给less或另一个寻呼机并查看你自己)。

您可以使用您喜欢的PL编写一个过滤器来解析流,重新编码任何data块。 流的组织方式使得不使用SHA-1哈希,因此您可以随时重新编码。 我唯一明显的问题是data块没有关于它们将在结果提交中表示哪个文件的信息(如果有的话),所以如果你的历史记录中有非文本文件,你可能需要采用基于猜测的方法。关于每个数据blob的内容,或者通过记住它看到的blob并决定在看到将文件名分配给(某些)blob的commit记录后重新编码它们中的哪一个来使处理器更复杂。


¹用git-fast-import(1) -run git help fast-import

我有完全相同的问题,解决方案基于@kostix回答使用filter-branch--index-filter选项作为基础,但是,有一些额外的改进。

  1. 使用git diff --name-only --staged来检测暂存区域的内容
  2. 迭代此列表并过滤:
    1. git ls-files $filename ,即它不是已删除的文件
    2. git show ":0:$filename" | file - --brief --mime-encoding的结果git show ":0:$filename" | file - --brief --mime-encoding git show ":0:$filename" | file - --brief --mime-encoding不是binary ,即它是一个文本文件,也不是UTF-8编码的
  3. 对每个文件使用检测到的mime编码
  4. 使用iconv转换文件
  5. 使用git ls-files $filename --stage | cut -c 1-6检测文件模式 git ls-files $filename --stage | cut -c 1-6

这是我的bash函数的外观:

changeencoding() {
    for filename in `git diff --name-only --staged`; do
        # Only if file is present, i.e., filter deletions
        if [ `git ls-files $filename` ]; then
            local encoding=`git show ":0:$filename" | file - --brief --mime-encoding`
            if [ "$encoding" != "binary" -a  "$encoding" != "utf-8" ]; then
                local sha1=`git show ":0:$filename" \
                    | iconv --from-code=$encoding --to-code=utf-8 \
                    | git hash-object -t blob -w --stdin`
                local mode=`git ls-files $filename --stage | cut -c 1-6`
                git update-index --cacheinfo "$mode,$sha1,$filename" --info-only
            fi
        fi
    done
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM