第 10 章 資料管理

目录

10.1. 共享,拷貝和存檔
10.1.1. 存檔和壓縮工具
10.1.2. 複製和同步工具
10.1.3. 歸檔語法
10.1.4. 複製語法
10.1.5. 查詢檔案的語法
10.1.6. 歸檔媒體
10.1.7. 可移動儲存裝置
10.1.8. 選擇用於分享資料的檔案系統
10.1.9. 網路上的資料分享
10.2. 備份和恢復
10.2.1. 實用備份套件
10.2.2. 一個系統備份的指令碼例子
10.2.3. 用於備份資料的複製指令碼
10.3. 資料安全基礎
10.3.1. GnuPG 金鑰管理
10.3.2. 在檔案上使用 GnuPG
10.3.3. 在 Mutt 中使用 GnuPG
10.3.4. 在 vim 中使用 GnuPG
10.3.5. MD5 校驗和
10.4. 原始碼合併工具
10.4.1. 從原始碼檔案匯出差異
10.4.2. 原始碼檔案移植更新
10.4.3. 通過三方移植進行更新
10.5. 版本控制系統
10.5.1. VCS 命令的比較
10.6. Git
10.6.1. 配置 Git 客戶端
10.6.2. Git 參考
10.6.3. Git 命令
10.6.4. 用於 Subversion 倉庫的 Git
10.6.5. 記錄配置歷史的 Git
10.7. CVS
10.7.1. CVS 儲存庫的配置
10.7.2. 本地訪問 CVS
10.7.3. 使用 pserver 遠端訪問 CVS
10.7.4. 使用 ssh 遠端訪問 CVS
10.7.5. 往 CVS 匯入新的源
10.7.6. CVS 儲存庫中的檔案許可權
10.7.7. CVS 工作流
10.7.8. CVS 中最新的檔案
10.7.9. CVS 的管理
10.7.10. 用於 CVS 簽出時的可執行位
10.8. Subversion
10.8.1. Subversion 儲存庫的配置
10.8.2. 通過 Apache2 伺服器訪問 Subversion
10.8.3. 按組本地訪問 Subversion
10.8.4. 通過 SSH 遠端訪問 Subversion
10.8.5. Subversion 目錄結構
10.8.6. 往 Subversion 裡匯入一個新的源
10.8.7. Subversion 工作流

以下是關於在 Debian 系統上管理二進位制和文字資料的工具及其相關提示。

[警告] 警告

為避免 競爭情況,不應當對正在進行寫操作的裝置和檔案,多個程序進行不協調的寫操作。採用flock(1) 檔案鎖定 機制可用於避免這種情況。

資料的安全和它的受控共享有如下幾個方面。

  • 存檔檔案的建立

  • 遠端儲存訪問

  • 複製

  • 跟蹤修改歷史

  • 促進資料共享

  • 防止未經授權的檔案訪問

  • 檢測未經授權的檔案修改

這些可以通過使用工具集來實現。

  • 存檔和壓縮工具

  • 複製和同步工具

  • 網路檔案系統

  • 移動儲存媒介

  • 安全 shell

  • 認證體系

  • 版本控制系統工具

  • 雜湊演算法和加密工具

以下是 Debian 系統上可用的存檔和壓縮工具的預覽。

表 10.1. 存檔和壓縮工具列表

軟件包 流行度 大小 副檔名 命令 描述
tar V:907, I:999 2770 .tar tar(1) 標準的歸檔工具(預設)
cpio V:320, I:998 720 .cpio cpio(1) Unix System V 風格的歸檔器,與 find(1) 一起使用
binutils V:169, I:702 223 .ar ar(1) 建立靜態庫的歸檔工具
fastjar V:5, I:53 172 .jar fastjar(1) Java 歸檔工具(類似 zip)
pax V:16, I:48 170 .pax pax(1) 新的 POSIX 歸檔工具,介於 tarcpio 之間
gzip V:877, I:999 231 .gz gzip(1), zcat(1), … GNU LZ77 壓縮工具(預設)
bzip2 V:212, I:939 184 .bz2 bzip2(1), bzcat(1), … Burrows-Wheeler block-sorting 壓縮工具有著比 gzip(1) 更高的壓縮率 (跟 gzip 有著相似的語法但速度比它慢)
lzma V:4, I:54 126 .lzma lzma(1) LZMA 壓縮工具有著比 gzip(1) 更高的壓縮率(不推薦)
xz-utils V:401, I:955 515 .xz xz(1), xzdec(1), … XZ 壓縮工具有著比 bzip2(1) 更高的壓縮率(壓縮速度慢於 gzip 但是比 bzip2 快; LZMA 壓縮工具的替代品)
p7zip V:66, I:312 934 .7z 7zr(1), p7zip(1) 有著更高壓縮率的 7-zip 檔案歸檔器(LZMA 壓縮)
p7zip-full V:155, I:528 4407 .7z 7z(1), 7za(1) 有著更高壓縮率的 7-Zip 檔案歸檔器(LZMA 壓縮和其他)
lzop V:5, I:45 97 .lzo lzop(1) LZO 壓縮工具有著比 gzip(1) 更高的壓縮和解壓縮速度 (跟 gzip 有著相似的語法但壓縮率比它低)
zip V:50, I:415 608 .zip zip(1) InfoZip:DOS 歸檔器和壓縮工具
unzip V:272, I:796 534 .zip unzip(1) InfoZIP:DOS 解檔器和解壓縮工具

[警告] 警告

除非你知道將會發生什麼,否則不要設定 "$TAPE" 變數。它會改變 tar(1) 的行為。

[注意] 注意

gzipped tar(1) 歸檔器用於副檔名是 ".tgz" 或者 ".tar.gz" 的檔案。

[注意] 注意

xz-compressed tar(1) 歸檔器用於副檔名是 ".txz" 或者 ".tar.xz" 的檔案。

[注意] 注意

FOSS 工具,例如 tar(1),中的主流壓縮方法已經按如下所示的遷移: gzipbzip2xz

[注意] 注意

cp(1),scp(1)tar(1) 工具可能並不適用於一些特殊的檔案。cpio(1) 工具的適用範圍是最廣的。

[注意] 注意

cpio(1) 是被設計為與 find(1) 和其它命令一起使用,適合於建立備份指令碼的場景,因此,指令碼的檔案選擇部分能夠被獨立測試。

[注意] 注意

Internal structure of Libreoffice data files are ".jar" file which can be opened also by unzip.

[注意] 注意

The de-facto cross platform archive tool is zip. Use it as "zip -rX" to attain the maximum compatibility. Use also the "-s" option, if the maximum file size matters.

如下是用不同的工具複製整個 "./source" 目錄中的內容。

  • 本地複製: "./source" 目錄 → "/dest" 目錄

  • 遠端複製:本地主機上的 "./source" 目錄 → "user@host.dom" 主機上的 "/dest" 目錄

rsync(8):

# cd ./source; rsync -aHAXSv . /dest
# cd ./source; rsync -aHAXSv . user@host.dom:/dest

你能夠選擇使用“源目錄上的反斜槓”語法。

# rsync -aHAXSv ./source/ /dest
# rsync -aHAXSv ./source/ user@host.dom:/dest

或者,如下所示。

# cd ./source; find . -print0 | rsync -aHAXSv0 --files-from=- . /dest
# cd ./source; find . -print0 | rsync -aHAXSv0 --files-from=- . user@host.dom:/dest

GNU cp(1) 和 openSSH scp(1):

# cd ./source; cp -a . /dest
# cd ./source; scp -pr . user@host.dom:/dest

GNU tar(1):

# (cd ./source && tar cf - . ) | (cd /dest && tar xvfp - )
# (cd ./source && tar cf - . ) | ssh user@host.dom '(cd /dest && tar xvfp - )'

cpio(1):

# cd ./source; find . -print0 | cpio -pvdm --null --sparse /dest

你能夠在所有包含 "." 的例子裡用 "foo" 替代 ".",這樣就可以從 "./source/foo" 目錄複製檔案到 "/dest/foo" 目錄。

在所有包含 "." 的列子裡,你能夠使用絕對路徑 "/path/to/source/foo" 來代替 ".",這樣可以去掉 "cd ./source;". 如下所示,這些檔案會根據工具的不同,拷貝到不同的位置。

  • "/dest/foo": rsync(8), GNU cp(1), 和 scp(1)

  • "/dest/path/to/source/foo": GNU tar(1), 和 cpio(1)

[提示] 提示

rsync(8) 和 GNU cp(1) 可以用 "-u" 選項來忽略接受端上更新的檔案。

find(1) 被用作從歸檔中篩選檔案也被用作拷貝命令 (參見第 10.1.3 节 “歸檔語法”第 10.1.4 节 “複製語法”) 或者用於 xargs(1) (參見第 9.3.9 节 “使用檔案迴圈來重複一個命令”)。通過 find 的命令列引數能夠使其功能得到加強。

以下是 find(1)基本語法的總結。

  • find 條件引數的運算規則是從左到右。

  • 一旦輸出是確定的,那麼運算就會停止。

  • “邏輯 OR" (由條件之間的 "-o" 引數指定的)優先順序低於 "邏輯 AND" (由 "-a" 引數指定或者條件之間沒有任何引數)。

  • ”邏輯 NOT" (由條件前面的 "!" 指定) 優先順序高於 “邏輯 AND”。

  • "-prune" 總是返回邏輯 TRUE 並且如果這個目錄是存在的,將會搜尋除這個目錄以外的檔案。

  • "-name" 選項匹配帶有 shell 萬用字元 (參見第 1.5.6 节 “Shell 萬用字元”) 的檔名但也匹配帶有類似 "*" 和 "?" 元字元的 ."。(新的 POSIX 特性)

  • "-regex" 匹配整個檔案路徑,預設採用 emacs 風格的 BRE (參見第 1.6.2 节 “正則表達式”)。

  • "-size" 根據檔案大小來匹配 (值前面帶有 "+" 號匹配更大的檔案,值前面帶有 "-" 號匹配更小的檔案)

  • "-newer" 引數匹配比引數名中指定的檔案還要新的檔案。

  • "-print0" 引數總是返回邏輯 TRUE 並將完整檔名 (null terminated) 列印到標準輸出裝置上。

如下是 find(1) 語法格式。

# find /path/to \
    -xdev -regextype posix-extended \
    -type f -regex ".*\.cpio|.*~" -prune -o \
    -type d -regex ".*/\.git" -prune -o \
    -type f -size +99M -prune -o \
    -type f -newer /path/to/timestamp -print0

這些命令會執行如下動作。

  1. 查詢 "/path/to" 下的所有檔案

  2. 限定全域性查詢的檔案系統並且使用的是 ERE (參見第 1.6.2 节 “正則表達式”)

  3. 通過停止處理的方式來排除匹配 ".*\.cpio" 或 ".*~" 正則表示式的檔案

  4. 通過停止處理的方式來排除匹配 ".*/\.git" 正則表示式的目錄

  5. 通過停止處理的方式來排除比 99MB (1048576位元組單元) 更大的檔案

  6. 顯示檔名,滿足以上搜索條件並且比 "/path/to/timestamp" 新的檔案

請留心以上例子中的 "-prune -o" 排除檔案的習慣用法。

[注意] 注意

對於非 Debian 系的 Unix-like 系統,有些引數可能不被 find(1) 命令所支援。在這種情況下,應該考慮調整匹配方法並用 "-print" 替代 "-print0"。你可能同樣需要更改其他相關的命令。

為重要的資料存檔尋找 儲存裝置 時,你應該注意它們的侷限性。對於小型的個人資料備份,我使用品牌公司的 CD-R 和 DVD-R 然後把它放在陰涼、乾燥、清潔的地方。(專業的一般使用磁帶存檔介質)

[注意] 注意

防火安全是對於紙質文件來說的,大多數的計算機資料儲存媒介耐熱性比紙差。我經常依賴儲存在多個安全地點的加密拷貝。

網上(主要是來源於供應商資訊)可以檢視儲存介質的最大使用壽命。

  • 大於100年:用墨水的無酸紙

  • 100年:光碟儲存(CD/DVD,CD/DVD-R)

  • 30年:磁帶儲存(磁帶,軟盤)

  • 20年:相變光碟儲存(CD-RW)

這不包括由於人為導致的機械故障等等。

網上(主要來源於供應商資訊)可以檢視儲存介質的最大的寫次數。

  • 大於250,000次:硬碟驅動器

  • 大於10,000次:快閃記憶體

  • 1,000次:CD/DVD-RW

  • 1次:CD/DVD-R,紙

[小心] 小心

這裡的儲存壽命和寫次數的資料不應該被用來決定任何用於關鍵資料的儲存媒介,請翻閱製造商提供的特定產品的說明。

[提示] 提示

因為 CD/DVD-R 和 紙只能寫一次,它們從根本上阻止了因為重寫導致的資料意外丟失。這是優點!

[提示] 提示

如果你需要更快更頻繁的進行大資料備份,那麼通過高速網路連線的遠端主機上的硬碟來實現備份,可能是唯一可行的方法。

可移動儲存裝置可能是以下的任何一種。

它們可以通過以下的方式來進行連線。

像 GNOME 和 KDE 這樣的現代桌面環境能夠在 "/etc/fstab" 檔案中沒有匹配條目的時候,自動掛載這些可移動裝置。

  • udisks 包提供了守護程序和相關的實用程式來掛載和解除安裝這些裝置。

  • D-bus 建立事件來觸發自動處理。

  • PolicyKit 提供了所需的特權。

[提示] 提示

umount(8) 在自動掛載裝置的時候可能會帶有 "uhelper=" 引數。

[提示] 提示

只有當這些可移動裝置沒有在 "/etc/fstab" 檔案中列出時,桌面環境下才會自動掛載。

現代桌面環境下的掛載點被選為 "/media/<disk_label>",它可以被如下所示的來定製。

  • FAT 格式的檔案系統使用 mlabel(1) 命令

  • ISO9660 檔案系統使用帶有 "-V" 選項的 genisoimage(1) 命令

  • ext2/ext3/ext4 檔案系統使用帶有 "-L" 選項的 tune2fs(1) 命令

[提示] 提示

掛載時可能需要提供編碼選項(參見 第 8.4.6 节 “檔名編碼”)。

[提示] 提示

在圖形介面選單上移除檔案系統,可能會移除它的動態裝置節點例如 "/dev/sdc"。如果你想要保留它的裝置節點,你應該在命令列提示符上輸入 umount(8) 命令來解除安裝它。

當你通過可移動儲存裝置與其他系統分享資料的時候,你應該先把它格式化為被兩種作業系統都支援的通用的 檔案系統。下面是檔案系統的列表。


[提示] 提示

檢視第 9.8.1 节 “使用 dm-crypt/LUKS 加密移動磁碟”來獲得關於使用裝置級加密的跨平臺的資料共享的資訊。

FAT 檔案系統被絕大多數的現代作業系統支援,它對於通過可行動硬碟進行的資料交換是非常有用的。

當格式化像裝有 FAT 檔案系統的跨平臺資料共享的可移動裝置時,以下應該是保險的選擇。

當使用 FAT 或 ISO9660 檔案系統分享資料時,如下是需要注意的安全事項。

  • tar(1),或cpio(1)命令壓縮檔案,目地是為了保留檔名,符號連結,原始的檔案許可權和檔案所有者資訊。

  • split(1) 命令把壓縮檔案分解成若干小於 2GiB的小檔案,使其免受檔案大小限制。

  • 加密壓縮檔案保護其內容免受未經授權的訪問。

[注意] 注意

因為 FAT 檔案系統的設計,最大的檔案大小為 (2^32 - 1) bytes = (4GiB -1 byte)。對於一些老舊的 32 位系統上的應用程式而言,最大的檔案大小甚至更小(2^31 -1) bytes = (2GiB -1 byte)。Debian 沒有遇到後者的問題。

[注意] 注意

微軟系統本身並不建議在超過 200MB 的分割槽或者驅動器上使用 FAT。他們的 " Overview of FAT, HPFS, and NTFS File Systems 這篇文章突出顯示了微軟系統的缺點,例如低效的磁碟空間利用。當然了,我們在 Linux 系統上還是應該使用 ext4 檔案系統。

[提示] 提示

有關檔案系統和訪問檔案系統的更多資訊,請參考 "Filesystems HOWTO"。

我們都熟知計算機有時會出問題,或者由於人為的錯誤導致系統和資料損壞。備份和恢復操作是成功的系統管理中非常重要的一部分。可能有一天你的電腦就會出問題。

[提示] 提示

保持你的備份系統簡潔並且經常備份你的系統,有備份資料比你採用的備份方法的技術先進要重要的多。

有3個關鍵的因素決定實際的備份和恢復策略。

  1. 知道要備份和恢復什麼。

    • 你自己建立的資料檔案:在 "~/" 下的資料

    • 你使用的應用程式建立的資料檔案:在 "/var/" 下的資料(除了 "/var/cache/","/var/run/" 和 "/var/tmp/")

    • 系統配置檔案:在 "/etc/” 下的資料

    • 本地軟體:在 "/usr/local/" 或 "/opt/" 下的資料

    • 系統安裝資訊:關鍵步驟 (分割槽,...) 的純文字備忘錄

    • 驗證資料結果:通過實驗性的恢復操作來預先驗證

  2. 知道怎樣去備份和恢復。

    • 安全的資料儲存:保護其免於覆蓋和系統故障

    • 經常備份:有計劃的備份

    • 冗餘備份:資料映象

    • 傻瓜式操作:單個簡單命令備份

  3. 評估涉及的風險和成本。

    • 評估資料丟失的損失

    • 備份所需的資源:人力,硬體,軟體,…

    • 資料丟失的方式及其可能性

[注意] 注意

除非你知道自己做的是什麼,否則不要備份 /proc, /sys, /tmp, 和 /run 目錄下的偽檔案系統(參見 第 1.2.12 节 “procfs 和 sysfs”第 1.2.13 节 “tmpfs”)。它們是龐大且無用的資料。

至於安全的資料儲存,資料至少是應該在不同的磁碟分割槽上最好是在不同的磁碟和機器上,來承受檔案系統發生的損壞。重要的資料最好儲存在只能寫一次的媒介上例如 CD/DVD-R 來防止覆蓋事故。(參見 第 9.7 节 “二進位制資料” 怎樣在 shell 命令列寫入儲存媒介。GNOME 桌面圖形環境可以讓你輕鬆的通過選單:“位置 → CD/DVD 燒錄”來實現寫入操作。)

[注意] 注意

當備份資料的時候,你可能希望停止一些應用程式的守護程序例如 MTA(參見第 6.3 节 “郵件傳輸代理 (MTA)”)。

[注意] 注意

你應該格外小心地備份和恢復身份認證相關的資料檔案例如 "/etc/ssh/ssh_host_dsa_key", "/etc/ssh/ssh_host_rsa_key", "~/.gnupg/*", "~/.ssh/*", /etc/passwd", "/etc/shadow", "/etc/fetchmailrc", "popularity-contest.conf", "/etc/ppp/pap-secrets" 和 "/etc/exim4/passwd.client/"。 這些資料中的有一些檔案是不能通過向系統輸入同樣的字串來再生的。

[注意] 注意

如果你以使用者程序的方式執行 cron job,你必須儲存檔案到 "/var/spool/cron/crontabs" 目錄並且重啟 cron(8)。參見第 9.3.14 节 “定時任務安排”來獲得關於 cron(8)crontab(1) 的資訊。

以下是 Debian 系統上值得注意的實用備份程式套件的列表。

表 10.5. 實用備份程式套件列表

軟件包 流行度 大小 說明
dump V:1, I:7 341 4.4 BSD dump(8)restore(8) 命令用於 ext2/ext3/ext4 檔案系統
xfsdump V:0, I:11 838 在 GNU/Linux 和 IRIX 上用 xfsdump(8)xfsrestore(8) 命令來備份和恢復 XFS 檔案系統
backupninja V:4, I:4 329 輕量的可擴充套件的 meta-backup 系統
bacula-common V:10, I:19 2055 Bacula: 網路資料備份,恢復和核查-常見的支援檔案
bacula-client I:5 162 Bacula: 網路資料備份,恢復和核查-客戶端元軟體包
bacula-console V:1, I:7 64 Bacula: 網路資料備份,恢復和核查-文字終端
bacula-server I:2 165 Bacula: 網路資料備份,恢復和核查-伺服器端元軟體包
amanda-common V:1, I:2 7419 Amanda: 馬里蘭大學開發的高階自動化網路磁碟歸檔器(庫)
amanda-client V:1, I:2 999 Amanda: 馬里蘭大學開發的高階自動化網路磁碟歸檔器(客戶端)
amanda-server V:0, I:0 1047 Amanda: 馬里蘭大學開發的高階自動化網路磁碟歸檔器(伺服器端)
backup-manager V:1, I:2 543 命令列備份工具
backup2l V:1, I:1 113 用於可掛載媒介 (基於磁碟的) 的低維護的備份/恢復工具
backuppc V:4, I:5 2232 BackupPC 是用於備份 PC 機資料(基於磁碟)的高效能的企業級工具
duplicity V:8, I:15 1534 (遠端) 增量備份
flexbackup V:0, I:0 242 (遠端) 增量備份
rdiff-backup V:9, I:18 704 (遠端) 增量備份
restic V:0, I:0 11149 (遠端) 增量備份
rsnapshot V:6, I:12 452 (遠端) 增量備份
slbackup V:0, I:0 146 (遠端) 增量備份

備份工具有各自的專用的用途。

第 10.1.1 节 “存檔和壓縮工具”第 10.1.2 节 “複製和同步工具” 描述的基礎工具能夠通過自定義指令碼來幫助系統備份。這些指令碼的功能可以通過如下的工具來增強。

  • restic 軟體包能夠增量備份(遠端)。

  • rdiff-backup 軟體包能夠增量備份(遠端)。

  • dump 軟體包用於高效增量的歸檔和恢復整個檔案系統。

[提示] 提示

參見 "/usr/share/doc/dump/" 和 "Is dump really deprecated?" 來了解 dump 程式。

對於執行 unstable 套件的個人 Debian 桌面系統來說,只需要保護個人資料和關鍵資料。我不管怎樣每年都會重新安裝一次系統。因此沒理由去備份整個系統或者安裝全功能的備份實用程式。

我使用簡單的指令碼來製作用於備份的壓縮檔案並用 GUI 介面把它燒寫到 CD/DVD 裡。以下是關於這個的指令碼例子。

#!/bin/sh -e
# Copyright (C) 2007-2008 Osamu Aoki <osamu@debian.org>, Public Domain
BUUID=1000; USER=osamu # UID and name of a user who accesses backup files
BUDIR="/var/backups"
XDIR0=".+/Mail|.+/Desktop"
XDIR1=".+/\.thumbnails|.+/\.?Trash|.+/\.?[cC]ache|.+/\.gvfs|.+/sessions"
XDIR2=".+/CVS|.+/\.git|.+/\.svn|.+/Downloads|.+/Archive|.+/Checkout|.+/tmp"
XSFX=".+\.iso|.+\.tgz|.+\.tar\.gz|.+\.tar\.bz2|.+\.cpio|.+\.tmp|.+\.swp|.+~"
SIZE="+99M"
DATE=$(date --utc +"%Y%m%d-%H%M")
[ -d "$BUDIR" ] || mkdir -p "BUDIR"
umask 077
dpkg --get-selections \* > /var/lib/dpkg/dpkg-selections.list
debconf-get-selections > /var/cache/debconf/debconf-selections

{
find /etc /usr/local /opt /var/lib/dpkg/dpkg-selections.list \
     /var/cache/debconf/debconf-selections -xdev -print0
find /home/$USER /root -xdev -regextype posix-extended \
  -type d -regex "$XDIR0|$XDIR1" -prune -o -type f -regex "$XSFX" -prune -o \
  -type f -size  "$SIZE" -prune -o -print0
find /home/$USER/Mail/Inbox /home/$USER/Mail/Outbox -print0
find /home/$USER/Desktop  -xdev -regextype posix-extended \
  -type d -regex "$XDIR2" -prune -o -type f -regex "$XSFX" -prune -o \
  -type f -size  "$SIZE" -prune -o -print0
} | cpio -ov --null -O $BUDIR/BU$DATE.cpio
chown $BUUID $BUDIR/BU$DATE.cpio
touch $BUDIR/backup.stamp

這是一個用 root 許可權執行的指令碼例子。

我建議你按照如下所示的去更改和執行這個指令碼。

把事情簡單化!

[提示] 提示

你能夠用 "debconf-set-selections debconf-selections" 命令恢復 debconf 配置資料,可以用 "dpkg --set-selection <dpkg-selections.list" 命令恢復 dpkg 篩選資料。

對於目錄樹下面的資料集,"cp -a" 命令可以實現常規備份。

對於類似 "/var/cache/apt/packages/" 目錄下面的大量不可覆蓋的靜態資料集,使用 "cp -al" 命令來建立硬連結是一種替代常規備份的方式,這樣可以高效的利用磁碟空間。

以下是一個用於資料備份的名為 bkup 的複製指令碼。它把當前目錄下的所有 (non-VCS) 檔案複製到父目錄下的指定目錄中或者遠端主機上。

#!/bin/sh -e
# Copyright (C) 2007-2008 Osamu Aoki <osamu@debian.org>, Public Domain
fdot(){ find . -type d \( -iname ".?*" -o -iname "CVS" \) -prune -o -print0;}
fall(){ find . -print0;}
mkdircd(){ mkdir -p "$1";chmod 700 "$1";cd "$1">/dev/null;}
FIND="fdot";OPT="-a";MODE="CPIOP";HOST="localhost";EXTP="$(hostname -f)"
BKUP="$(basename $(pwd)).bkup";TIME="$(date  +%Y%m%d-%H%M%S)";BU="$BKUP/$TIME"
while getopts gcCsStrlLaAxe:h:T f; do case $f in
g)  MODE="GNUCP";; # cp (GNU)
c)  MODE="CPIOP";; # cpio -p
C)  MODE="CPIOI";; # cpio -i
s)  MODE="CPIOSSH";; # cpio/ssh
t)  MODE="TARSSH";; # tar/ssh
r)  MODE="RSYNCSSH";; # rsync/ssh
l)  OPT="-alv";; # hardlink (GNU cp)
L)  OPT="-av";;  # copy (GNU cp)
a)  FIND="fall";; # find all
A)  FIND="fdot";; # find non CVS/ .???/
x)  set -x;; # trace
e)  EXTP="${OPTARG}";; # hostname -f
h)  HOST="${OPTARG}";; # user@remotehost.example.com
T)  MODE="TEST";; # test find mode
\?) echo "use -x for trace."
esac; done
shift $(expr $OPTIND - 1)
if [ $# -gt 0 ]; then
  for x in $@; do cp $OPT $x $x.$TIME; done
elif [ $MODE = GNUCP ]; then
  mkdir -p "../$BU";chmod 700 "../$BU";cp $OPT . "../$BU/"
elif [ $MODE = CPIOP ]; then
  mkdir -p "../$BU";chmod 700 "../$BU"
  $FIND|cpio --null --sparse -pvd ../$BU
elif [ $MODE = CPIOI ]; then
  $FIND|cpio -ov --null | ( mkdircd "../$BU"&&cpio -i )
elif [ $MODE = CPIOSSH ]; then
  $FIND|cpio -ov --null|ssh -C $HOST "( mkdircd \"$EXTP/$BU\"&&cpio -i )"
elif [ $MODE = TARSSH ]; then
  (tar cvf - . )|ssh -C $HOST "( mkdircd \"$EXTP/$BU\"&& tar xvfp - )"
elif [ $MODE = RSYNCSSH ]; then
  rsync -aHAXSv ./ "${HOST}:${EXTP}-${BKUP}-${TIME}"
else
  echo "Any other idea to backup?"
  $FIND |xargs -0 -n 1 echo
fi

如上只是一個範例。在你自己使用指令碼之前,請閱讀此指令碼並且修改它。

[提示] 提示

我把 bkup 儲存在我的 "/usr/local/bin" 目錄。我假定當需要臨時快照備份的時候,能夠在工作目錄不帶任何引數執行 bkup 命令。

[提示] 提示

如果是要製作原始檔樹或者配置檔案樹的快照歷史的話,使用 git(7) (參見第 10.6.5 节 “記錄配置歷史的 Git”) 是更簡便並且也是空間高效的。

資料安全基礎設施是資料加密,訊息摘要和簽名工具的結合。


參見 第 9.8 节 “資料加密提示”dm-cryptoecryptfs,它們通過 Linux 核心模組實現了自動資料加密架構。

如下是 GNU 隱私衛士 基本的金鑰管理命令。


信任碼含義.


如下命令上傳我的 "1DD8D791" 公鑰到主流的公鑰伺服器 "hkp://keys.gnupg.net"。

$ gpg --keyserver hkp://keys.gnupg.net --send-keys 1DD8D791

預設良好的公鑰伺服器在 "~/.gnupg/gpg.conf" (舊的位置在 "~/.gnupg/options")檔案中設定,此檔案包含了以下資訊。

keyserver hkp://keys.gnupg.net

從鑰匙伺服器獲取無名鑰匙。

$ gpg --list-sigs --with-colons | grep '^sig.*\[User ID not found\]' |\
  cut -d ':' -f 5| sort | uniq | xargs gpg --recv-keys

有一個錯誤在 OpenPGP 公鑰伺服器 (先前的版本 0.9.6),會將鍵中斷為 2 個以上的子鍵。新的 gnupg (>1.2.1-2) 軟體包能夠處理這些中斷的子鍵。參見 gpg(1) 下的 "--repair-pks-subkey-bug" 選項.

md5sum(1) 提供了製作摘要檔案的一個工具,它使用 rfc1321 裡的方式製作摘要檔案.

$ md5sum foo bar >baz.md5
$ cat baz.md5
d3b07384d113edec49eaa6238ad5ff00  foo
c157a79031e1c40f85931829bc5fc552  bar
$ md5sum -c baz.md5
foo: OK
bar: OK
[注意] 注意

MD5 校驗和的 CPU 計算強度是比 GNU Privacy Guard (GnuPG) 加密簽名要少的.在通常情況下,只有頂級的摘要檔案才需要加密簽名來確保資料完整性.

這裡有許多原始碼合併工具。如下的是我感興趣的工具。

表 10.10. 原始碼合併工具列表

軟件包 流行度 大小 命令 說明
diffutils V:857, I:981 1394 diff(1) 逐行比較兩個檔案
diffutils V:857, I:981 1394 diff3(1) 逐行比較和合並三個檔案
vim V:122, I:392 2470 vimdiff(1) 在 vim 中並排比較兩個檔案
patch V:98, I:857 216 patch(1) 給原檔案打補丁
dpatch V:1, I:16 191 dpatch(1) 管理 Debian 軟體包的系列補丁
diffstat V:21, I:186 70 diffstat(1) 通過 diff 生成一個改變柱狀圖
patchutils V:20, I:179 223 combinediff(1) 從兩個增量補丁建立一個積累補丁
patchutils V:20, I:179 223 dehtmldiff(1) 從一個 HTML 頁面提取出一個 diff
patchutils V:20, I:179 223 filterdiff(1) 從一個 diff 檔案裡面提取或者排除 diff 檔案
patchutils V:20, I:179 223 fixcvsdiff(1) 修復由 CVS patch(1) 錯誤建立的 diff 檔案
patchutils V:20, I:179 223 flipdiff(1) 交換兩個補丁的順序
patchutils V:20, I:179 223 grepdiff(1) 顯示哪些檔案是由匹配正則表示式的補丁修改
patchutils V:20, I:179 223 interdiff(1) 顯示在兩個統一格式 diff 檔案(基於同一個檔案的兩個不同 diff 檔案)之間的差異
patchutils V:20, I:179 223 lsdiff(1) 顯示哪些檔案由補丁修改
patchutils V:20, I:179 223 recountdiff(1) 重新計算通用內容 diff 檔案的數量和偏移
patchutils V:20, I:179 223 rediff(1) 修復手工編輯 diff 檔案的數量和偏移
patchutils V:20, I:179 223 splitdiff(1) 隔離出增量補丁
patchutils V:20, I:179 223 unwrapdiff(1) 識別已經被分詞的補丁
wiggle V:0, I:0 166 wiggle(1) 應用被拒絕的補丁
quilt V:4, I:43 711 quilt(1) 管理系列補丁
meld V:15, I:41 3115 meld(1) 比較和移植檔案(GTK)
dirdiff V:0, I:2 144 dirdiff(1) 顯示目錄樹之間的不同並移植改變
docdiff V:0, I:0 573 docdiff(1) 逐詞逐字的比較兩個檔案
imediff2 V:0, I:0 34 imediff2(1) 全屏交付式雙向移植工具
makepatch V:0, I:0 102 makepatch(1) 生成擴充套件補丁檔案
makepatch V:0, I:0 102 applypatch(1) 應用擴充套件補丁檔案
wdiff V:5, I:81 643 wdiff(1) 在文字檔案中,顯示單詞的不同

如下是 Debian 系統上可用的版本控制系統(VCS) 的摘要。

[注意] 注意

如果是剛接觸版本控制系統,你應該從 git 入門,git 人氣日益高漲。


VCS 有時被認為是修訂控制系統 (RCS), 或者是軟體配置管理程式 (SCM)。

像 Git 這樣的分散式 VCS 是現在正在使用的工具。參加那些已經存在的開源軟體的開發活動,掌握 CVS 和 Subversion 仍然是有用的。

通過 Debian Alioth service,Debian 能夠提供免費的幾乎所有的 VCS 服務。在 http://wiki.debian.org/Alioth 能找到它的說明文件。

這裡有一些關於建立共享訪問 VCS 歸檔的基礎知識。

這裡有原生 VCS 命令的簡單比較來提供大圖概要。典型的命令序列需要選項和引數。


[小心] 小心

從命令列通過 "git-xyz" 直接呼叫 git 子命令的方式,從 2006 年早期開始就被取消。

[提示] 提示

如果有一個可執行檔案 git-foo 在路徑環境變數 $PATH 裡面,在命令列輸入沒有中劃線的 "git foo",則將呼叫 git-foo.這是 git 命令的一個特性.

[提示] 提示

例如 tkcvs(1)gitk(1) 這樣的圖形介面工具有助於追蹤檔案的修改歷史。許多公共的歸檔提供的用於瀏覽它們的儲存庫的 web 介面同樣是很有用的。

[提示] 提示

Git 能夠直接在不同的 VCS 倉庫上工作,比如說 CVS 和 Subversion 提供的倉庫, 通過 git-cvsgit-svn 軟體包提供本地倉庫的本地改變.參見 用於 CVS 使用者的 git第 10.6.4 节 “用於 Subversion 倉庫的 Git”.

[提示] 提示

Git 中的有些命令在 CVS 和 Subversion 中並沒有對應的命令:"fetch","rebase","cherry-pick", …

Git 可以用來做本地和遠程源代碼管理的任何事情。這意味着,你能夠在本地記錄源代碼修改,而不是必須要和遠程倉庫有網絡連接。

看下面。

git-gui(1)gitk(1) 命令使 Git 變得非常容易使用。

[警告] 警告

不要使用帶空格的標簽字符串。即使一些工具,如 gitk(1) 允許你使用它,但會阻礙其它 git 命令。

即使你的上游使用不同的版本控制系統,使用 git(1) 作爲本地活動的版本控制系統,仍然是一個好的主意,因爲 git 可以讓你在沒有上遊網絡連接的情況下,管理你的本地源代碼樹拷貝。這裏有一些 git(1) 使用的包和命令。


[提示] 提示

git(1) 下,你在本地分支下進行了許多提交,稍後你可以使用 "git rebase -i master" 之類的命令來重新組織改變歷史。這可以使你製作一個乾淨的改變歷史。參見 git-rebase(1)git-cherry-pick(1).

[提示] 提示

當你想要回到一個乾淨的工作目錄,並且不丟失工作目錄當前的狀態,你可以使用 "git stash".參見 git-stash(1).

你可以使用 Git 工具來手工記錄按時間先後順序的配置歷史。這裏是一個例子,讓你練習記錄"/etc/apt/" 內容。

$ cd /etc/apt/
$ sudo git init
$ sudo chmod 700 .git
$ sudo git add .
$ sudo git commit -a

提交配置,描述此次提交。

對配置文件進行修改。

$ cd /etc/apt/
$ sudo git commit -a

提交配置,說明提交,繼續你的工作。

$ cd /etc/apt/
$ sudo gitk --all

你有全部的配置歷史。

[注意] 注意

sudo(8) 是需要用於配置數據文件,任意文件權限的情況。 對於普通用戶的配置數據,你需要省略 sudo

[注意] 注意

在上面例子裏的 "chmod 700 .git" 命令,是用來保護文檔數據不被未經授權的讀訪問。

[提示] 提示

要更加完整的建立配置歷史記錄,請參閱 etckeeper 包: 第 9.2.10 节 “記錄配置檔案的變更”

看下面。

  • cvs(1)

  • "/usr/share/doc/cvs/html-cvsclient"

  • "/usr/share/doc/cvs/html-info"

  • "/usr/share/doc/cvsbook"

  • "info cvs"

許多公共 CVS 伺服器可以通過 pserver 服務用 "anonymous" 賬戶遠端只讀訪問。例如,Debian 網站的內容是 webwml project 通過 Debian alioth 服務中的 CVS 來維護。如下將建立用於遠端訪問 CVS 儲存庫的 "$CVSROOT"。

$ export CVSROOT=:pserver:anonymous@anonscm.debian.org:/cvs/webwml
$ cvs login
[注意] 注意

因為 pserver 容易被竊聽攻擊並且是不安全的,所以寫訪問通常是被伺服器管理員禁用的。

如下所示將建立 webwml project 使用 SSH 遠端訪問 CVS 儲存庫所需的 "$CVS_RSH" 和 "$CVSROOT"。

$ export CVS_RSH=ssh
$ export CVSROOT=:ext:account@cvs.alioth.debian.org:/cvs/webwml

你也可以使用 SSH 的公鑰認證,這能夠去除遠端密碼提示。

這裡有一個 CVS 典型工作流的例子。

按如下所示檢視 "$CVSROOT" 所指的 CVS 專案上所有可用的模組。

$ cvs rls
CVSROOT
module1
module2
...

按如下所示簽出 "module1" 到預設的目錄 "./module1"。

$ cd ~/path/to
$ cvs co module1
$ cd module1

按需修改裡面的內容。

通過如下所示的命令來檢查改變,其作用相當於使用 "diff -u [repository] [local]"。

$ cvs diff -u

你發現自己改壞了 "file_to_undo" 檔案,而其他的檔案都是好的。

按如下所示用 CVS 中的原始副本覆蓋 "file_to_undo" 檔案。

$ cvs up -C file_to_undo

按如下所示把更新了的本地源目錄樹儲存到 CVS。

$ cvs ci -m "Describe change"

按如下建立並新增 "file_to_add" 檔案到 CVS。

$ vi file_to_add
$ cvs add file_to_add
$ cvs ci -m "Added file_to_add"

按如下所示合併 CVS 中的最新版本。

$ cvs up -d

當心以 "C filename" 開頭的行,這意味著衝突的改變。

檢視 ".#filename.version" 中未經修改的程式碼。

查詢檔案中的 "<<<<<<<" 和 ">>>>>>>" 來獲得衝突的改變的資訊。

按需更改檔案來解決衝突。

按如下所示新增一個釋出標籤 "Release-1"。

$ cvs ci -m "last commit for Release-1"
$ cvs tag Release-1

繼續編輯檔案。

按如下所示移除釋出分支 "Release-1"。

$ cvs tag -d Release-1

按如下所示把改變簽入到 CVS。

$ cvs ci -m "real last commit for Release-1"

按如下所示給已經更新了的 CVS 主幹中的 HEAD 重新新增 "Release-1" 釋出標籤。

$ cvs tag Release-1

按如下所示從 "Release-initial" 標籤指向的初始版本中建立一個帶有粘性標籤的 "Release-initial-bugfixes" 分支,並把它簽出到 "~/path/to/old" 目錄。

$ cvs rtag -b -r Release-initial Release-initial-bugfixes module1
$ cd ~/path/to
$ cvs co -r Release-initial-bugfixes -d old module1
$ cd old
[提示] 提示

使用 "-D 2005-12-20" (ISO 8601 日期格式) 而不是 "-r Release-initial" 來指定某個特定日期作為分支點。

在基於原始版本的有 "Release-initial-bugfixes" 粘性標籤的本地源目錄樹上工作。

獨自在 "Release-initial-bugfixes" 分支上工作...直到有其他人加入到此分支。

當要建立新的目錄時,按如下所示同步其他人在此分支上對檔案所做的修改。

$ cvs up -d

按需更改檔案來解決衝突。

按如下所示把改變簽入到 CVS。

$ cvs ci -m "checked into this branch"

按如下所示更新本地目錄樹為主幹的最新版本,同時移除粘性標籤 ("-A") 並且不使用關鍵字擴充套件 ("-kk")。

$ cvs up -d -kk -A

按如下所示通過合併 "Release-initial-bugfixes" 分支並且不使用關鍵字擴充套件的方式來更新本地目錄樹 (內容為主幹中的最新版本)。

$ cvs up -d -kk -j Release-initial-bugfixes

用編輯器來解決衝突。

按如下所示把改變簽入到 CVS。

$ cvs ci -m "merged Release-initial-bugfixes"

按如下所示建立歸檔。

$ cd ..
$ mv old old-module1-bugfixes
$ tar -cvzf old-module1-bugfixes.tar.gz old-module1-bugfixes
$ rm -rf old-module1-bugfixes
[提示] 提示

"cvs up" 命令能夠使用 "-d" 選項來建立新目錄並且可以使用 "-P" 選項來刪除空目錄。

[提示] 提示

你可以通過形如 "cvs co module1/subdir" 這樣的列出其名的方式,來簽出 "module1" 的一個子目錄。


Subversion 是替代舊的 CVS 的近代版本控制系統。除了標籤和分支以外,它也擁有 CVS 的絕大多數特性。

你需要安裝 subversionlibapache2-svnsubversion-tools 軟體包來搭建 Subversion 伺服器。

這裡給出使用 Subversion 及其原生客戶端的典型工作流示例。

[提示] 提示

git-svn 軟體包提供的客戶端命令,可以作為使用 git 命令的 Subversion 工作流的一個另外選擇。參見 第 10.6.4 节 “用於 Subversion 倉庫的 Git”.

檢視如下所示的 URL "file:///srv/svn/project" 指向的 Subversion 專案上所有可用的模組。

$ svn list file:///srv/svn/project
module1
module2
...

按如下所示的檢出 "module1/trunk" 到 "module1" 目錄。

$ cd ~/path/to
$ svn co file:///srv/svn/project/module1/trunk module1
$ cd module1

按需修改裡面的內容。

通過如下所示的命令來檢查改變,其作用相當於使用 "diff -u [repository] [local]"。

$ svn diff

你發現自己改壞了 "file_to_undo" 檔案,而其他的檔案都是好的。

按如下所示的用 Subversion 中的乾淨副本來覆蓋 "file_to_undo" 檔案。

$ svn revert file_to_undo

按如下所示的把已經更新了的本地源目錄樹儲存到 Subversion。

$ svn ci -m "Describe change"

按如下所示的建立 "file_to_add" 檔案並把它新增到 Subversion。

$ vi file_to_add
$ svn add file_to_add
$ svn ci -m "Added file_to_add"

按如下所示更新工作拷貝到 Subversion 中的最新版本。

$ svn up

當心以 "C filename" 開頭的行,這意味著衝突的改變。

檢視檔案中未經修改的程式碼,例如 "filename.r6", "filename.r9" 和 "filename.mine" 檔案。

查詢檔案中的 "<<<<<<<" 和 ">>>>>>>" 來獲得衝突的改變的資訊。

按需更改檔案來解決衝突。

按如下所示新增一個釋出標籤 "Release-1"。

$ svn ci -m "last commit for Release-1"
$ svn cp file:///srv/svn/project/module1/trunk file:///srv/svn/project/module1/tags/Release-1

繼續編輯檔案。

按如下所示移除釋出分支 "Release-1"。

$ svn rm file:///srv/svn/project/module1/tags/Release-1

按如下所示把改變簽入到 Subversion。

$ svn ci -m "real last commit for Release-1"

按如下所示在最新的 Subversion 主幹的基礎上重新添加發布分支 "Release-1"。

$ svn cp file:///srv/svn/project/module1/trunk file:///srv/svn/project/module1/tags/Release-1

按如下所示在 "module1/tags/Release-initial" 路徑指定的最初版本的基礎上再建立一個路徑為 "module1/branches/Release-initial-bugfixes" 的分支,並把它簽出到 "~/path/to/old" 目錄。

$ svn cp file:///srv/svn/project/module1/tags/Release-initial file:///srv/svn/project/module1/branches/Release-initial-bugfixes
$ cd ~/path/to
$ svn co file:///srv/svn/project/module1/branches/Release-initial-bugfixes old
$ cd old
[提示] 提示

使用 "module1/trunk@{2005-12-20}" (ISO 8601 日期格式) 而不是 "module1/tags/Release-initial" 來指定分支建立時候的日期。

在基於原始版本的 "Release-initial-bugfixes" 分支的本地源目錄樹上工作。

獨自在 "Release-initial-bugfixes" 分支上工作...直到有其他人加入到此分支。

按如下所示同步其他人在此分支上改動的檔案。

$ svn up

按需更改檔案來解決衝突。

按如下所示把改變簽入到 Subversion。

$ svn ci -m "checked into this branch"

按如下所示更新本地目錄樹為主幹的最新版本。

$ svn switch file:///srv/svn/project/module1/trunk

按如下所示通過合併 "Release-initial-bugfixes" 分支的方式來更新本地目錄樹 (內容為主幹的最新版本)。

$ svn merge file:///srv/svn/project/module1/branches/Release-initial-bugfixes

用編輯器來解決衝突。

按如下所示把改變簽入到 Subversion。

$ svn ci -m "merged Release-initial-bugfixes"

按如下所示建立歸檔。

$ cd ..
$ mv old old-module1-bugfixes
$ tar -cvzf old-module1-bugfixes.tar.gz old-module1-bugfixes
$ rm -rf old-module1-bugfixes
[提示] 提示

你能夠用像 "http://…" 和 "svn+ssh://..." 這樣格式的 URL 來替代 "file:///…" URL。

[提示] 提示

通過 "svn co file:///srv/svn/project/module1/trunk/subdir module1/subdir" 等命令,你可以只簽出 "module1" 的一個子目錄。