簡體   English   中英

從.git目錄中刪除可以重新下載的所有信息

[英]Remove all information from a .git directory that can be re-downloaded

我有一個git存儲庫,當剛簽出時,即使在最淺的配置中也需要大約2.3 GiB,其中1.9 GiB在.git/objects/pack 工作樹文件大約是0.5 GiB。

考慮到我有一個遙控器,我可以根據需要重新獲取所有對象,問題是:

  • 什么(以及如何)我可以從內部刪除.git然后我可以使用簡單的git命令從遠程安全地重新獲取所有內容?

測試了一下,我發現如果我刪除.git/objects/pack/下的所有內容,它將通過簡單的git fetch從遠程重新下載。

有一些抱怨如:

error: refs/heads/master does not point to a valid object!
error: refs/remotes/origin/master does not point to a valid object!
error: refs/remotes/origin/HEAD does not point to a valid object!

但隨后.git/objects/pack重新填充,進一步調用git fetch不再抱怨了。

核武.git/objects/pack*這樣安全嗎?

假設:

  • 在repo中沒有本地提交或任何形式的git操作(比如在舞台中添加/刪除對象),只是以淺模式檢出特定分支。
  • 遠程不會為已簽出的分支重寫歷史記錄。
  • 我無法控制遠程存儲庫本身的內容。 它是我的項目的依賴項,但是一個快速更改的項目僅作為git提供,我希望在持續集成設置中自動使用指令。 有關如何修改存儲庫本身以減少占用空間的提示無濟於事。
  • 正如我之前提到的,1.9 GiB是我感興趣的一個分支的淺層克隆。 由於它的歷史悠久(開源項目已超過10年),它比不淺時更大。
  • 在同一個連續集成管道中檢查了其他存儲庫,我想在所有存儲庫中應用相同的冗余遠程信息減少。

目的是盡可能地減少工件從連續集成管道中占用的空間量,但保留足夠的信息,以便可以將這些工件下載並恢復到開發人員工作站中的工作順序(盡可能少)正常)命令。

刪除.git/東西只會破壞事物。 它包含項目的完整歷史記錄,這些包文件是git如何節省空間的。 有很多,更好的方法來減少你的回購的規模。

首先是運行垃圾收集, git gc 這將做很多事情來減少磁盤上存儲庫的大小。 你不應該這樣,這定期運行,但它可能會有所幫助。

如果沒有,請嘗試淺層克隆,只能獲得歷史記錄的一部分。 這只會克隆來自master的最新100次提交。

git clone --depth=100 <remote>

同樣,您可以克隆一個分支。

git clone --single-branch --branch master <remote>

這些可以在以后使用git-fetch “加深”。

但最好的辦法是減少回購的大小。 Git在太空中非常有效,而且演出非常多。 它表明存儲庫中有很多非常大的二進制文件,圖像,視頻,電子表格和壓縮文件...... git無法有效壓縮。 要處理這個問題,有兩個工具, git-lfs (大文件支持)和BFG Repo Cleaner

git-lfs允許您將舊版本的大文件存儲在雲存儲中,而不是存儲在每個人的.git目錄中。 這可以極大地減少存儲庫的大小......繼續。

BFG Repo Cleaner可讓您輕松重寫歷史記錄,包括刪除大文件的選項。

將它們放在一起,您可以使用BFG Repo Cleaner更改現有的大文件以使用git-lfs。 這可以極大地減少存儲庫的大小。 例如,這會將所有*.mp4更改為使用git-lfs。

$ java -jar ~/bfg-1.12.15.jar --convert-to-git-lfs '*.mp4' --no-blob-protection

有關這方面的說明可以在這里找到

另一個重要的事情是不壓縮文件 你提到了持續集成工件,我願意打賭它們是壓縮的。 Git將自己進行更高效的壓縮,並且它可以確保歷史記錄中只有一個文件的副本,但它只能在文本上執行。 在提交之前解壓縮tarball和zipfiles。


如果絕對無法減小存儲庫的大小,那么剩下的選擇是讓每個人共享一個.git目錄。 您可以使用--git-dir選項或設置GIT_DIR來執行此GIT_DIR

git --git-dir=/path/to/the/.git log

這是一個糟糕的主意。 雖然每個人都可以擁有自己的結賬,但他們都將共享相同的存儲庫狀態。 如果一個開發者進行了更改,其他開發人員將看到它,但現在使用不同的工作目錄。

例如,dev1添加一個文件。

$ touch this
$ GIT_DIR=~/tmp/foo/.git git add this
$ GIT_DIR=~/tmp/foo/.git git st
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   this

然后dev2突然看到了這一點。

$ GIT_DIR=~/tmp/foo/.git git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   this

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    deleted:    this

他們共享相同的暫存區域,但不是相同的工作副本。 開發者將不斷地絆倒對方。


如果git clone --depth=1仍然產生太大的repos,那么每個checkout中只有很多數據。 你無能為力。 如果淺克隆上的.git是2演出,那么結賬將會更大。

至於在.git上進行手術的想法,也許你可以通過刪除一些對象來逃避,並希望git fetch --deepen可以修復它,但是在多個開發者中保持這個......這是一個維護噩夢。

那時,您可以完全刪除.git 現在您已經有效地導出了最新的提交。 有多種方法可以直接執行此操作

或者只是停止浪費時間和金錢並購買更大的硬盤。 花在這上面的每個人小時都是你可以購買的硬盤。

盡可能減少工件從連續集成管道中占用的空間量,但保留足夠的信息,以便可以使用盡可能少的(和正常的)命令將這些工件下載並恢復到開發人員工作站中的工作順序。可能

我不完全理解你的情況,但一種經常被遺忘的減少網絡數據大小和服務器內存使用的方法是:

  • 分發一些穩定的存儲庫(其中只包括未重寫的分支),然后
  • 克隆時使用--reference <path>

在正常的開發條件下(文本文件,並非每次提交都更新它們的所有fof),它比使用淺克隆更有效。

至於你問過的事情,我認為嘗試保存從存儲庫中刪除任何內容是沒有意義的。 大多數數據用於包裝,這是必需的,休息是無關緊要的。

PS:存儲庫只能通過git本身在臨時存儲中初始化:

CACHE_REPO=/tmp/repo
if ![ -d "$CACHE_REPO" ]; then
  git clone --single-branch --no-checkout --branch=_BRANCH_ _REMOTE_ "$CACHE_REPO"
fi

_BRANCH_master或其他一些你肯定不會強行推進的分支。 你可以試着把它變淺,它可能會也可能不會起作用,我不確定。

  • 什么(以及如何)我可以從內部刪除.git然后我可以使用簡單的git命令從遠程安全地重新獲取所有內容?

一切怎么樣?

如果您不想擔心.git的內部以及某些內容是否可恢復,您可以保存足夠的信息以再次檢查它,並將工作區恢復到與運行時相比功能相似的狀態。 CI管道。

在CI管道中

添加這樣的文件(讓我們稱之為degit.sh

#!/bin/bash
set -ex
GIT_REMOTE=$( git remote get-url origin )
GIT_BRANCH=$( git rev-parse --abbrev-ref HEAD )
GIT_COMMIT=$( git rev-parse HEAD )

# TABs, not spaces, indenting the block below:
cat <<-EOF > .gitrestore
    set -ex
    test ! -e .git
    tmpclone=\$( mktemp -d --tmpdir=. )
    git clone $GIT_REMOTE -n --branch=$GIT_BRANCH \$tmpclone
    ( cd \$tmpclone ; git reset --hard $GIT_COMMIT )
    mv \$tmpclone/.git .
    rm -rf "\$tmpclone"
    rm -f \$0
EOF

rm -rf .git

然后,在您的Continous Integration(CI)工作空間的每個git repos的根目錄中,調用它以便生成.gitrestore文件。

它看起來像這樣:

set -ex
test ! -e .git
tmpclone=$( mktemp -d --tmpdir=. )
git clone git@example.com:example/repo.git -n --branch=example-branch $tmpclone
mv $tmpclone/.git .
git reset --hard example-commit-hash
rm -rf "$tmpclone"
rm -f $0

請注意,它在成功運行后會自行破壞。 你不想運行它兩次。

在Developer Machine中

現在,您的開發人員可以在每個存儲庫中獲取CI工件並運行:

bash .gitrestore

它將擁有一個看起來非常類似CI管道的存儲庫,除了更新的遙控器視圖,它允許開發人員比較CI與她擁有的內容。

其他考慮

這假設只有CI機器受空間限制,而不是開發人員機器(她的帶寬都沒有)。

如果要在開發人員端節省空間/帶寬,可以傳遞--depth=1 ,它將僅克隆指定的分支(即,它意味着--single-branch並將歷史記錄限制為單個提交。

暫無
暫無

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

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