簡體   English   中英

如何從 Git 中的特定版本中檢索單個文件?

[英]How to retrieve a single file from a specific revision in Git?

我有一個 Git 存儲庫,我想看看幾個月前一些文件的樣子。 我在那個日期找到了修訂版; 它是27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8 我需要查看一個文件的外觀,並將其另存為(“新”)文件。

我設法使用gitk查看了該文件,但它沒有保存它的選項。 我嘗試使用命令行工具,我得到的最接近的是:

git-show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8 my_file.txt

但是,此命令顯示差異,而不是文件內容。 我知道我以后可以使用PAGER=cat之類的東西並將 output 重定向到文件,但我不知道如何獲取實際文件內容。

基本上,我正在尋找類似svn cat的東西。

使用git show

要完成您自己的答案,語法確實是

git show object
git show $REV:$FILE
git show somebranch:from/the/root/myfile.txt
git show HEAD^^^:test/test.py

該命令采用通常的修訂風格,這意味着您可以使用以下任何一種:

  1. 分支名稱(由ash建議
  2. HEAD + x 個^字符
  3. 給定修訂版的 SHA1 hash
  4. 給定 SHA1 hash 的前幾個(可能是 5 個)字符

提示重要的是要記住,當使用“ git show ”時,始終指定從存儲庫根目錄開始的路徑,而不是當前目錄 position。

(盡管Mike Morearty提到,至少在 git 1.7.5.4 中,您可以通過將“ ./ ”放在路徑的開頭來指定相對路徑。例如:

git show HEAD^^:./test.py

)

使用git restore

使用 Git 2.23+(2019 年 8 月),您還可以使用git restore來替換令人困惑的git checkout命令

git restore -s <SHA1>     -- afile
git restore -s somebranch -- afile

這將僅在工作樹上恢復“源”( -s提交 SHA1 或分支somebranch中存在的文件。
要恢復索引:

git restore -s <SHA1> -SW -- afile

( -SW : --staged --worktree的縮寫)


正如starwarswii 的評論中所指出的那樣

它使您可以將內容 pipe 放入文件中,如果您只想快速比較提交中的文件,這非常有用。

例如,您可以這樣做:

 git show 1234:path/to/file.txt > new.txt git show 1234~:path/to/file.txt > old.txt

然后比較它們。


使用低級 git 管道命令

在 git1.5.x 之前,這是通過一些管道完成的:

git ls-tree <rev>
在提交中顯示一個或多個“blob”對象的列表

git cat-file blob <file-SHA1>
cat 文件,因為它已在特定修訂版中提交(類似於 svn cat)。 使用git ls-tree檢索給定文件 sha1 的值

git cat-file -p $(git-ls-tree $REV $file | cut -d " " -f 3 | cut -f 1)::

git-ls-tree在修訂版$REV中列出了$file的 object ID,這是從 output 中刪除的,並用作git-cat-file的參數,它實際上應該被稱為git-cat-object ,並且只是轉儲即 object 到stdout


注意:從 Git 2.11(2016 年第四季度)開始,您可以對git cat-file output 應用內容過濾器。

請參閱Johannes Schindelin ( dscho )的提交3214594 、提交7bcf341 (2016 年 9 月 9 日)、 提交 7bcf341 (2016 年 9 月 9 日)和提交 b9e62f6提交 16dcc29 (2016 年 8 月 24 日)。
(由Junio C Hamano -- gitster --提交 7889ed2中合並,2016 年 9 月 21 日)

git config diff.txt.textconv "tr A-Za-z N-ZA-Mn-za-m <"
git cat-file --textconv --batch

注意:“ git cat-file --textconv ”最近(2017 年)開始出現段錯誤,已在 Git 2.15(2017 年第四季度)中更正

請參閱Jeff King ( peff )提交 cc0ea7c (2017 年 9 月 21 日)。
(由Junio C Hamano -- gitster --提交 bfbc2fc中合並,2017 年 9 月 28 日)

如果您希望使用先前提交或其他分支中的文件內容替換/覆蓋當前分支中的文件內容,可以使用以下命令執行此操作:

git checkout 08618129e66127921fbfcbc205a06153c92622fe path/to/file.txt

或者

git checkout mybranchname path/to/file.txt

然后,您必須提交這些更改才能使它們在當前分支中生效。

您需要提供文件的完整路徑:

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8:full/repo/path/to/my_file.txt

最簡單的方法是寫:

git show HASH:file/path/name.ext > some_new_name.ext

在哪里:

  • HASH是 Git 修訂版 SHA-1 hash 編號
  • file/path/name.ext是您要查找的文件的名稱
  • some_new_name.ext是保存舊文件的路徑和名稱

例子

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8:my_file.txt > my_file.txt.OLD

這會將修訂版27cf8e中的my_file.txt保存為名為my_file.txt.OLD的新文件

它使用 Git 2.4.5 進行了測試。

如果要檢索已刪除的文件,可以使用HASH~1 (在指定 HASH 之前提交一次)。

例子:

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8~1:deleted_file.txt > deleted_file.txt

在 Windows 中,使用 Git Bash:

  • 在您的工作區中,將 dir 更改為文件所在的文件夾
  • git show cab485c83b53d56846eb883babaaf4dff2f2cc46:./your_file.ext > old.ext
git checkout {SHA1} -- filename

此命令從特定提交中獲取復制的文件。

並將其很好地轉儲到文件中(至少在 Windows 上) - Git Bash:

$ echo "`git show 60d8bdfc:src/services/LocationMonitor.java`" >> LM_60d8bdfc.java

"引號是必需的,因此它保留換行符。

除了其他答案列出的所有選項之外,您還可以使用git reset與 Git object (哈希,分支, HEAD~x ,標簽,...)您感興趣的文件和路徑:

git reset <hash> /path/to/file

在您的示例中:

git reset 27cf8e8 my_file.txt

這樣做是它將my_file.txt恢復為其在索引中的提交27cf8e8處的版本,同時在工作目錄中保持不變(因此在其當前版本中)。

從那里開始,事情很容易:

  • 您可以將文件的兩個版本與git diff --cached my_file.txt
  • 您可以使用git restore --staged file.txt刪除舊版本的文件(或者,在 Git v2.23 之前, git reset file.txt的話)
  • you can restore the old version with git commit -m "Restore version of file.txt from 27cf8e8" and git restore file.txt (or, prior to Git v2.23, git checkout -- file.txt )
  • 您可以通過運行git add -p file.txt (然后git commitgit restore file.txt )將更新從舊版本添加到新版本。

最后,如果您運行,您甚至可以在第一步中以交互方式選擇要重置的塊:

git reset -p 27cf8e8 my_file.txt

因此,使用路徑git reset為您提供了很大的靈活性來檢索文件的特定版本以與其當前簽出的版本進行比較,如果您選擇這樣做,則可以完全或僅恢復到該版本的某些大塊。


編輯:我剛剛意識到我沒有回答您的問題,因為您想要的不是差異或檢索部分或全部舊版本的簡單方法,而只是cat該版本。

當然,您仍然可以在使用以下命令重置文件后執行此操作:

git show :file.txt

至 output 至標准 output 或

git show :file.txt > file_at_27cf8e8.txt

但是,如果這就是您想要的,那么像其他人建議的那樣,直接運行git showgit show 27cf8e8:file.txt當然更直接。

我將留下這個答案,因為直接運行git show可以讓你立即獲得舊版本,但是如果你想用它做點什么,從那里這樣做並不像你重置那樣方便索引中的那個版本。

這將幫助您在不指定路徑的情況下在提交之間獲取所有已刪除的文件,這在刪除大量文件時很有用。

git diff --name-only --diff-filter=D $commit~1 $commit | xargs git checkout $commit~1

使用git show $REV:$FILE正如其他人已經指出的那樣,它可能是正確的答案。 我正在發布另一個答案,因為當我嘗試此方法時,有時會從 git 收到以下錯誤:

fatal: path 'link/foo' exists on disk, but not in 'HEAD'

當文件路徑的一部分是符號鏈接時,就會出現問題。 在這些情況下, git show $REV:$FILE方法將不起作用 重現步驟:

$ git init .
$ mkdir test
$ echo hello > test/foo
$ ln -s test link
$ git add .
$ git commit -m "initial commit"
$ cat link/foo
hello
$ git show HEAD:link/foo
fatal: path 'link/foo' exists on disk, but not in 'HEAD'

問題是,像realpath這樣的實用程序在這里沒有幫助,因為符號鏈接可能不再存在於當前提交中。 我不知道一個好的通用解決方案。 在我的例子中,我知道符號鏈接只能存在於路徑的第一個組件中,所以我通過兩次使用git show $REV:$FILE方法解決了這個問題。 這是有效的,因為當git show $REV:$FILE用於符號鏈接時,它的目標會被打印:

$ git show HEAD:link
test

而對於目錄,該命令將 output a header,然后是目錄內容:

$ git show HEAD:test
tree HEAD:test

foo

因此,就我而言,我只是檢查了第一次調用 git 的git show $REV:$FILE如果它只是一行,那么我將路徑的第一個組件替換為通過 ZBA9F191ECC34297D6E 解析符號鏈接的結果。

通過檢出先前的提交和復制文件從先前的提交中獲取文件。

  • 注意你在哪個分支:git 分支
  • 簽出您想要的上一個提交: git checkout 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8
  • 將您想要的文件復制到臨時位置
  • 結帳您開始的分支: git checkout theBranchYouNoted
  • 復制您放置在臨時位置的文件
  • 提交對 git 的更改: git commit -m "added file?? from previous commit"

如果您更喜歡使用 GUI 來執行此操作,如果您知道文件大約何時更改,則以下操作將起作用。

在安裝了 Git 擴展的 Visual Studio 上:

  1. Git -> 查看分支歷史
  2. 右鍵單擊文件更改的提交,然后選擇查看提交詳細信息
  3. 在右側的更改列表中,單擊感興趣的文件。 您將看到更改前后完整文件內容的並排比較。 只需 select 全部復制文件內容並粘貼到您想要的任何位置。

暫無
暫無

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

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