簡體   English   中英

撤消git update-index --no-assume-unchanged(不起作用),並能夠再次查看這些本地更改

[英]Undo git update-index --no-assume-unchanged (not working) and be able to see these local changes again

更新:我的權限問題以某種方式任意修復了,因為現在完全相同的遠程分支create命令可以工作了,因此(您可能猜到了)這不是由此跟蹤問題引起的。

現在,我只是想解決跟蹤問題。 謝謝!

原始語言:我最初在多個文件中應用了以下內容:

    git update-index --assume-unchanged filename.py

參考此文檔:

https://git-scm.com/docs/git-update-index#_using_assume_unchanged_bit

隱藏工作目錄更改中的某些文件(將文件添加到.git/info/exclude似乎沒有效果-盡管路徑正確且尚未提交,但文件仍然可見)。

然后,我遇到了一些問題,這些問題推到了以前從未出現過的遠程分支,標准

    fatal: Could not read from remote repository.

    Please make sure you have the correct access rights
    and the repository exists. 

因此,考慮到在運行update-index之前我沒有訪問問題,我決定恢復該--assume-unchanged因為我沒有對git repo進行任何其他操作。

我能夠使用查看這些assume-unchanged文件

    git ls-files -v | grep '^[a-z]'

我試圖通過使用以下方式恢復assume-unchanged

    git update-index --really-refresh

如此處有關在多個文件中還原assume-unchanged指示:

撤消git update-index-假定未更改的<文件>

這沒有還原它們,然后我嘗試了

    git ls-files -v | grep '^[a-z]' | cut -c 3- | tr '\012' '\000' | xargs -0 git update-index --no-assume-unchanged

根據此建議:

撤消git update-index-假定未更改的<文件>

這些文件仍然不可見,我現在也不再能夠通過運行來查看它們

    git ls-files -v | grep '^[a-z]'

我還嘗試在我的一個文件中嘗試了此操作:

    git update-index --skip-worktree file.py

按照這里

https://git-scm.com/docs/git-update-index#_skip_worktree_bit

據我所知, skip-worktreeassume-unchanged因此我希望看到該文件的某些狀態更改。 依然沒有。

如何將文件恢復為可見並在工作目錄中跟蹤更改?

還有一個問題是,這可能會影響我創建新的遠程分支機構的訪問權限嗎?

您在這里有兩個不同的問題。 您的fatal: Could not read from remote repository錯誤fatal: Could not read from remote repository錯誤完全獨立於您在索引中設置或清除的任何標志位。 它暗示着:

  • 對於您用來訪問另一個存儲庫( httphttpsssh://git:// )的任何協議,到另一個Git的連接失敗,或者
  • 連接成功,但是據稱擁有另一個Git存儲庫的另一台主機說“我在這里看不到Git存儲庫”(在URL的其余部分)。

如果連接本身失敗,通常您應該在出現fatal:之前看到其他信息fatal:行告訴您發生了什么,例如,無法將主機名解析為IP地址,所需的用戶名和/或密碼,但丟失等等。 使用它來診斷不良連接。 如果連接成功 ,但是主機說“這里沒有Git存儲庫”,請使用可以獲得的有關主機的任何信息來找出存儲庫的去向(例如,您可以直接登錄到主機並四處逛逛嗎?)。


現在,關於assume-unchangedskip-worktree位,恐怕這會變得有些復雜和技術性。 需要知道一些這方面使用Git的,所以這是值得學習的。 我在這里還指出,使用--really-refresh的建議基本上是錯誤的。 出於更新索引中的緩存stat數據的目的,這確實暫時忽略了assume-unchanged位,但是對實際的假設不變的位沒有影響。 清除該位的方法確實是使用--no-assume-unchanged ,如您在上面引用的幻想管道中,以| xargs -0 git update-index --no-assume-unchanged結尾| xargs -0 git update-index --no-assume-unchanged | xargs -0 git update-index --no-assume-unchanged skip-worktree位也一樣,除了使用--no-skip-worktree 清除--no-skip-worktree 1個

索引是什么,這些git update-index命令在做什么?

重要的是要認識到,在使用Git時,您擁有三個我喜歡隨時調用每個文件的活動副本的文件。 2這三個副本之一就是您簽出的那個提交中的任何一個。 此副本嚴格是只讀的。 您無法更改它:它會被凍結為一個提交,並且只要該提交本身存在(基本上永久),它將一直保留在該提交中。 3這意味着凍結的副本是安全的:您所做的任何事情都不會破壞它; 您總能取回它。 查看名為path/to/file.ext的文件的凍結副本,請使用git show HEAD:path/to/file.ext HEAD:file語法與git show ,可讓您查看當前提交中的凍結副本。 (您也可以在任何其他提交中看到凍結的副本。)

現在,這些凍結副本采用特殊的只讀,僅Git壓縮格式。 您計算機上的其他程序均無法直接訪問它們(除非它們對Git內部了解得太多)。 而且,由於無法更改它們,因此可以很好地進行存檔,但是對於完成任何實際的工作卻毫無用處。 因此,當您git checkout某些特定的提交時,Git會提取所有凍結的文件,並將它們恢復為正常的日常文件,您可以照常查看和使用它們。 您可以更改這些普通的讀/寫文件,或對它們執行任何所需的操作,包括添加新文件和刪除現有文件,所有這些操作都與使用計算機執行任何操作一樣。

這些可用的,可用的文件位於Git所謂的工作樹中 那就是您完成工作的地方。 那是每個文件的第二個副本。 您不必在這里做任何特別的事情:這些只是文件。 如果你想看看文件命名file ,使用任何工具(編輯,文件瀏覽器等),您總是用它來查看文件命名file 它的名字就是file

每個文件的第三個副本是Git偷偷摸摸的地方。 這就是索引的來源。索引也稱為暫存區域 ,或者有時(有時是最近) 緩存 這些都是同一事物的名稱。 每個文件的第三個副本都在索引中 ,您可以使用git show :file查看名為file的文件的索引副本。 也就是說, git show將冒號放在前面意味着: 給我看一下索引中的副本。 您在花式管道中使用的git ls-files命令還會列出索引中的內容。

文件的第三個副本采用Git用於永久凍結文件存儲的格式 ,但並沒有完全凍結。 您可以隨時覆蓋它。 您可以用任何喜歡的新內容替換file的索引副本。 您可以使用git add執行此操作,它會獲取工作樹副本(大概您已經更改了該副本),並該版本替換了索引副本。 或者,你可以,如果你喜歡, 請取出的索引拷貝file ,使用git rm ,這將同時刪除索引副本工作樹副本。

從技術上講,索引中的內容只是有關文件的大量緩存數據,加上一堆標志,以及對文件的存儲的凍結格式副本的引用。 首次簽出某些提交以使HEAD和工作樹副本匹配時,索引副本實際上只是直接重用凍結的HEAD副本,因此根本不占用額外的空間。 當您使用git add覆蓋它時,Git會獲取工作樹副本,將其壓縮為凍結的,隨時可存儲的副本,並將該副本放置在4處並更新索引引用。

這是使git commit如此快速git commit的秘密之一。 Git不必查看您的工作樹。 它不必重新壓縮所有文件。 他們已經在您的索引中,准備就緒了。 git commit要做的就是將預凍結的文件打包成一個commit。 它只是在運行git commit索引中的內容。 因此,考慮這一點的一種好方法是索引是您建議的下一次提交 git addgit rm所做的是更新您建議的提交 運行git commit只是可以快照索引中的內容(在登台區域中,隨時可以提交),即使這與上一次提交幾乎相同。 git addgit rm命令是實際更新索引的內容。

這就是為什么以及每次提交都是每個文件的完整快照的原因。 更新的任何文件仍在索引中(“正在執行中”),並且將在下一次提交中。

git status使用標志

假設您在當前已檢出的提交(因此在工作樹中)中有3000個文件,並且在工作樹中更改了一個文件git add它以使其在索引/登台區域中得到更新。 如果您現在運行git status ,則git status不會告訴您3000個文件中 2999個是相同的 ,因為這不是有用的信息。 git status告訴您的是一個文件已更新。

git status這樣做的方法至少在原則上至少是運行兩個單獨的比較:

  • 首先, git status會將HEAD提交中的每個文件與索引中的副本進行比較。 對於此處相同的每個文件,它什么也沒有說。 但是,如果文件在此處不同 ,則表示: 進行提交

  • 接下來, git status將索引中的每個文件與工作樹中的副本進行比較。 同樣,如果文件相同 ,則什么也沒說。 如果文件不同 ,則表示: 未暫存為commit

git status此比較時,由於Git內部將文件內容表示為Blob哈希ID,所以第一部分進展很快。 因此,實際上,只是比較每個文件。 只需幾毫秒即可確定3000個文件中的2999個相同而一個不同。 但是第二部分很慢:實際上比較所有3000個文件可能需要幾秒鍾!

因此, git status作弊。 這就是索引的緩存方面發揮作用的地方。 每個索引條目均包含對已准備好提交的凍結格式文件的引用。 但是它也保存一些來自OS lstat系統調用的數據。 5 Git可以在工作樹中的文件上執行另一個lstat系統調用。 在大多數情況下, 當且僅當工作樹中的文件仍與 Git具有凍結格式(由索引條目緩存)的副本相同時 ,結果stat數據才與Git先前保存的內容匹配。 如果您修改了工作樹副本,則操作系統還將更新stat數據。

因此,假設您是git status ,將索引中的每個文件與其在工作樹中的副本進行比較,以便可以說如果有必要暫不進行提交 可以打開每個工作樹文件並通讀文件,並將其內容與解壓縮凍結的索引副本時得到的內容進行比較。 這將告訴您它們是相同還是不同,但是哇,這是很多工作,可能要花幾秒鍾 但是,您已經緩存了此stat數據,如果將統計數據與另一個lstat的結果進行比較,那么這將節省大量的工作和時間。 因此,您改為這樣做。 如果lstat結果與緩存的結果匹配,則文件必須相同,並且您什么也不能說,而是繼續下一個文件。

但是實際上,每個lstat系統調用也相當慢。 當然,它比讀取每個文件快數千倍,但仍可能需要數百微秒。 而且,如果操作系統具有耗時3 毫秒的可怕的非常慢的lstat 怎么辦? 對3000個文件執行此操作,如果每個文件花費3毫秒,則將花費9 ,這太長了!

Git對此有一個標記。 --assume-unchanged標志(在每個索引條目中都是可設置的標志)告訴Git: 不要打擾在此工作樹副本上調用lstat ,只需假設它與緩存的stat數據匹配即可 它具有第二個功能更強大的標志--skip-worktree ,它可以實現相同的結果。 (它稍微強大一點,因為某些命令(例如git update-index --really-refresh )將忽略第一個標志,而不會忽略第二個標志。)

如果您將其設置為任意一位,則該操作會將索引的緩存stat數據與工作樹中的實際stat數據進行比較,以判斷該文件是否確實被修改,只需假設該文件未被修改即可。 清除兩個位,這些Git操作將最終調用stat 然后, 只要操作系統返回的stat數據也已更新, git status 就會看到該文件的更新。 有一些操作系統級別的技巧可以解決這些問題,但是您通常可以使用touch來擊敗這些操作系統級別的技巧:

touch path/to/file

確保path/to/file上的stat數據現在比Git可能保存的任何緩存的stat數據都新。

如果有點復雜,此圖片應該足夠清晰:索引/登台區域保存來自上一個lstat系統調用的有關每個工作樹文件的緩存數據。 如果緩存的數據與OS在新的 lstat調用中報告的數據匹配,則索引副本必須與工作樹副本匹配。 如果設置了標志位,則Git不會打擾lstat調用:它只是假設兩組數據匹配,因此索引副本與工作樹副本匹配,而這是否真的成立。 清除這些位后,Git返回調用lstat並(我們希望)從操作系統獲得准確的報告。

由於Git現在還具有使用文件系統監視器來避免不必要地調用lstat的能力,因此該圖片不再完全正確。 但這完全是另一個問題的話題。


1請注意,在某些版本的grep ,花哨管道假定您已將LC_COLLATE設置為C ,並且遵循LC_COLLATE標志。 那是:

git ls-files -v | grep '^[a-z]'

可能會根據LC_COLLATE列出每個文件。 它還列出--skip-worktree文件,但是您必須使用單獨的git update-index --no-skip-worktree命令取消設置該標志。 這是我寫git-flagged原因之一。 (由於grep匹配太多而列出的文件太多是無害的:您只需調用一些git update-index命令,這些命令實際上並不需要運行。)

我尚未使git-flagged腳本支持新的fsmonitor有效/無效位。 如果您的系統使用的是fsmonitor,而這出了問題,那么您會遇到更大的問題,也許應該通過git configcore.fsmonitor設置在全局禁用fsmonitor。

2這假設一個正常的(不是--bare )存儲庫,並且您尚未使用git worktree add添加其他工作樹。 您使用git worktree add添加的每個工作樹都有自己的索引和工作樹以及自己的HEAD ,因此每個工作樹都會得到另外三個活動副本。

3提交並獲取特定的哈希ID后,就可以使用該哈希ID來查看該提交是否仍然存在。 如果確實存在(並且可能確實存在),那么您凍結到其中的文件也將以該凍結形式存在。

要真正擺脫錯誤的提交有點困難。 它是可以做到的,所以提交並不一定要永遠永久 ,但這是思考它們的一種方式。

4 “某處”實際上直接進入存儲庫。 如果提交該文件的副本,則將使用凍結的副本;否則,將使用凍結的副本。 如果不是這樣,那么Git 最終會清理掉通常只是剩下的垃圾。 除非您的磁盤空間一直很短,否則您不必擔心git fsck將顯示為懸掛的blob 只是讓Git稍后自行清理它們。

5這特別是指POSIX lstat系統調用,該系統調用會生成stat數據。 如果您的基礎操作系統沒有或不使用stat數據,則Git仍需要緩存某些內容,並將使用某種綜合stat數據,這些數據需要足夠好才能完成其余工作。

暫無
暫無

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

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