[英]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
該命令采用通常的修訂風格,這意味着您可以使用以下任何一種:
提示重要的是要記住,當使用“ 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
然后比較它們。
在 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
在哪里:
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:
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
的話)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 commit
和git 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 show
和git 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 checkout 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8
git checkout theBranchYouNoted
git commit -m "added file?? from previous commit"
如果您更喜歡使用 GUI 來執行此操作,如果您知道文件大約何時更改,則以下操作將起作用。
在安裝了 Git 擴展的 Visual Studio 上:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.