簡體   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