簡體   English   中英

如何動態更改以 Git 存儲庫結尾的行

[英]How to change the line ending in a Git repo dynamically

我有一個在 Windows 上簽出的 Git 存儲庫。 當我安裝 Git 時,我選擇了“使用 CRLF 作為本地行尾”,因此 repo 被克隆並檢出所有以 CRLF 作為行尾的文件。 這給我帶來了一些問題,因為我有很多 bash 腳本並且我在 WSL 中使用了 Ubuntu bash。 我已經編輯了全局.gitconfig文件以將行結尾更改為與遠程 repo 一致。 但是我的文件仍然以 CRLF 行結尾。 在不刪除 repo 目錄並重新克隆的情況下,將所有這些更改回原始行結尾的最佳方法是什么?

但是我的文件仍然以 CRLF 行結尾。

如果存儲庫內提交中的文件具有 CRLF 行結尾,則該文件的該版本將永遠保持這種狀態。 任何現有提交的任何部分都不能更改。

如果存儲庫內提交中的文件具有僅 LF 行結尾,則該文件的該版本將永遠保持這種狀態。 但是,您可以在提取該文件時選擇希望 Git 在工作樹中放置的結尾。

如果您已經提取了文件,則 Git 已經完成了轉換。 Git 現在認為一切正常,即使您剛剛更改了轉換設置。

因此,如果更改轉換設置,則必須強制 Git 重新提取文件。 在所有版本的 Git 中一致執行此操作的最簡單方法是從工作樹中刪除文件,然后運行git checkout -- path/to/file 因為文件從工作樹中消失了,Git 將被迫再次提取它。 這次將應用更新的 EOL 轉換。

(另一種方法是更改​​文件,然后運行相同的git checkout ,或者在 Git 2.23 或更高版本中使用git restore 。通過告訴 Git 應該丟棄您的文件版本,並且 Git 看到您的版本文件確實“錯誤”,因為它與索引副本不匹配,因為您更改了它,Git 將被迫重新提取索引副本。)

這可能對你來說就足夠了,也可能不夠。 如果沒有,請繼續閱讀。

關於 Git 行尾轉換的知識

我自己堅信“永遠不要使用 Windows,這樣你就永遠不需要讓你的版本控制系統用行結尾搞砸”的哲學,但是如果你在其他陣營並且這樣做,有一些事情需要知道想讓 Git 搞砸行尾。 其中最重要的是:Git 中存儲的內容,以及您在處理Git 中獲取的文件時使用的內容,不一定是同一件事。

要了解其工作原理,請記住 Git 存儲提交而不是直接存儲文件。 這些提交中文件來自 Git 的index ,而不是來自您的工作樹。 文件索引副本的格式與 Git 用於永久凍結提交的內部格式相同:數據是預壓縮的。 因此,索引中每個文件的副本已經與您在工作樹中使用的副本顯着不同,因為您的工作樹中的副本不是 Git blob 對象,並且通常不是 zlib 壓縮的。

Git 在將提交復制到您的工作樹之前將提交讀入索引。 對文件運行git add壓縮和 blob 化文件,以便將其存儲在 Git 的索引中。 就在這個轉換點,當 Git 正在壓縮和 Git 化一個文件 ( git add ) 或 de-Git-ifying 和解壓縮一個文件 ( git checkout-index或等效的) 時,Git 插入額外的轉換操作是微不足道的。

因此,Git 在這一點上做了它的事情。 Git 可以做的事情——唯一直接內置的事情——是,在離開索引的路上,Git 可以用\\r\\n行結尾替換\\n -only 行結尾,並在進入索引的路上, Git 可以用\\n -only 行結尾替換\\r\\n行結尾。

換句話說,你可以安排Git在存儲文件之前丟掉一些回車,而在提取文件時加入一些回車。 如果您同時執行這兩項操作,您將在工作樹中獲得 CRLF 行結尾,並在提交中獲得僅換行符行結尾。

如果您願意,您可以讓 Git 只執行其中一項:特別是,使用crlf=input設置,您可以告訴 Git:在工作樹到索引復制操作中只做一次轉換。

如果您選擇在提取文件時讓 Git 進行轉換,這里唯一可用的轉換是將 LF-only 轉換為 CRLF 您不能將 CRLF 結尾變成僅 LF 結尾。 如果在 Git 中提交的文件具有 CRLF 結尾,則工作樹中提取的文件將具有 CRLF 結尾。

同樣,這些轉換中的每一個都只發生在一個方向:

  • 指數→工作樹:可選,替換\\n\\r\\n
  • 工作樹 → 索引:可選,用\\r\\n替換\\r\\n \\n

您選擇的core.autocrlf.gitattributes指令是:

  • text-text ,和/或core.autocrlf :哪些文件
  • eol=...和/或core.eol :獲得哪種治療
  • crlf=input : 在哪個操作上

一旦文件被處理和轉換——通過將它復制到索引或從索引復制——Git 通過從操作系統獲取關鍵數據來將索引的副本標記為“匹配工作樹的副本”:文件的大小和其他lstat系統調用值。 由於不同的操作系統以不同的粒度存儲不同的數據,因此這里的確切細節有所不同。

強制進行新轉換的簡單方法是刪除文件的一個或另一個副本: rm filegit rm --cached file破壞工作樹或索引副本,所以現在git checkout -- filegit add file將創建一個新git add file

當您運行git commit ,文件索引副本中的任何字節都會進入 Git 進行的新提交。 這個新提交現在一直被凍結:索引中的字節現在在提交中,永遠(或只要提交本身繼續存在)。 沒有什么也沒有人可以改變它們。

上述后果

上面的意思是,如果您確實計划讓您的版本控制系統(即 Git)處理行尾,那么您可以(因此可能應該)始終將行尾用於每個索引副本,因此每個提交的副本, 每個文本文件都是 LF-only 行尾。 這些總是可以通過適當的.gitattributes設置或core.*設置轉換為工作樹文件中的 CRLF 結尾。 如果您已經完成了這樣的轉換,那么可以在git add操作中將該工作樹文件轉換回 LF-only 行尾。

如果您確實提交了帶有 CRLF 行結尾的文件,那么該提交會一直保持這種狀態,並且每次提取該提交都會為您提供一個具有 CRLF 行結尾的工作樹副本,因為 Git 沒有內置索引→ 工作樹操作將改變這一點。 Git 唯一的內置 CRLF-to-LF 操作僅適用於另一個方向,即索引 ← 工作樹。

如果您想進行新的和改進的提交,其中該文件的提交副本具有僅 LF 行結尾,您有以下兩個選項:

  1. 確保您的索引 ← 工作樹設置這樣做,然后強制 Git 添加文件(例如,在工作樹中更改它或在索引副本上使用git rm --cached ,然后git add它); 或者
  2. 使用任何更改工作樹副本以具有僅 LF 行結尾的命令,例如,在其上運行dos2unix或類似命令,然后git add它。

方法 2 的優點是您可以立即看到效果(在您的工作樹文件中)並且很難出錯。 用方法1的問題是,不到它,它很容易得到它完全錯誤的:例如,你可能會不小心用git rm而不是git rm --cached ,這同時刪除索引工作樹副本。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM