章 10. 資料管理

# 章 10. 資料管理

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

## 10.1. 共享，拷貝和存檔

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

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

- 存檔檔案的建立

- 遠端儲存存取

- 複製

- 跟蹤修改歷史

- 促進資料共享

- 防止未經授權的檔案存取

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

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

- 存檔和壓縮工具

- 複製和同步工具

- 網路檔案系統

- 移動儲存媒介

- 安全 shell

- 認證體系

- 版本控制系統工具

- 雜湊演算法和加密工具

### 10.1.1. 存檔和壓縮工具

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

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

軟體包 | 流行度 | 大小 | 副檔名 | 指令 | 描述
--- | --- | --- | --- | --- | ---
`tar` | V:908, I:1000 | 3085 | `.tar` | tar(1) | 標準的歸檔工具（預設）
`cpio` | V:352, I:999 | 1201 | `.cpio` | cpio(1) | Unix System V 風格的歸檔器，與 find(1) 一起使用
`binutils` | V:190, I:640 | 1119 | `.ar` | ar(1) | 建立靜態庫的歸檔工具
`fastjar` | V:1.0, I:9.6 | 182 | `.jar` | fastjar(1) | Java 歸檔工具（類似 zip）
`pax` | V:5.5, I:9.6 | 167 | `.pax` | pax(1) | 新的 POSIX 歸檔工具，介於 `tar` 和 `cpio` 之間
`gzip` | V:904, I:1000 | 256 | `.gz` | gzip(1), zcat(1), … | GNU LZ77 壓縮工具（預設）
`bzip2` | V:163, I:972 | 113 | `.bz2` | bzip2(1), bzcat(1), … | Burrows-Wheeler block-sorting 壓縮工具有著比 gzip(1) 更高的壓縮率 (跟 `gzip` 有著相似的語法但速度比它慢)
`lzma` | V:1, I:10 | 349 | `.lzma` | lzma(1) | LZMA 壓縮工具有著比 gzip(1) 更高的壓縮率（不推薦)
`xz-utils` | V:318, I:982 | 1520 | `.xz` | xz(1), xzdec(1), … | XZ 壓縮工具有著比 bzip2(1) 更高的壓縮率（壓縮速度慢於 `gzip` 但是比 `bzip2` 快; LZMA 壓縮工具的替代品)
`zstd` | V:318, I:803 | 2309 | `.zstd` | zstd(1), zstdcat(1), … | Zstandard 快速無失真壓縮工具
`p7zip` | V:6, I:198 | 8 | `.7z` | 7zr(1), p7zip(1) | 有著更高壓縮率的 7-zip 檔案歸檔器（LZMA 壓縮）
`p7zip-full` | V:20, I:222 | 12 | `.7z` | 7z(1), 7za(1) | 有著更高壓縮率的 7-Zip 檔案歸檔器（LZMA 壓縮和其他）
`lzop` | V:12, I:134 | 164 | `.lzo` | lzop(1) | LZO 壓縮工具有著比 gzip(1) 更高的壓縮和解壓縮速度 (跟 `gzip` 有著相似的語法但壓縮率比它低)
`zip` | V:49, I:361 | 627 | `.zip` | zip(1) | InfoZip：DOS 歸檔器和壓縮工具
`unzip` | V:110, I:749 | 387 | `.zip` | unzip(1) | InfoZIP：DOS 解檔器和解壓縮工具

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

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

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

- FOSS 工具，例如 tar(1)，中的主流壓縮方法已經按如下所示的遷移: `gzip` → `bzip2` → `xz`

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

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

- Libreoffice 資料檔案的內部結構是 "`.jar`" 檔案，它也可以使用 `unzip` 工具來開啟。

- 事實上跨平臺支援最好的存檔工具是 `zip`。按照“`zip -rX`”的方式呼叫可以獲得最大的相容性。如果最大檔案大小需要納入考慮範圍，請同時配合“`-s`”選項使用。

### 10.1.2. 複製和同步工具

以下是 Debian 系統上的可用的簡單複製和備份工具的預覽。

表格 10.2. 複製和同步工具列表

軟體包 | 流行度 | 大小 | 工具 | 功能
--- | --- | --- | --- | ---
`coreutils` | V:911, I:1000 | 17994 | GNU cp | 複製本地檔案和目錄("-a" 參數實現遞迴）
`openssh-client` | V:915, I:996 | 4210 | scp | 複製遠端檔案和目錄（客戶端，"`-r`" 參數實現遞迴)
`openssh-server` | V:768, I:819 | 3359 | sshd | 複製遠端檔案和目錄（遠端伺服器）
`rsync` | V:195, I:541 | 835 |  | 單向遠端同步和備份
`unison` | V:3, I:12 | 14 |  | 雙向遠端同步和備份

在複製檔案的時候， rsync(8) 比其他工具提供了更多的特性。

- 差分傳輸演算法只會傳送原始檔與已存在的目標檔案之間的差異部分

- 快速檢查演算法 (預設) 會查詢大小或者最後的修改時間有變化的檔案

- "`--exclude`" 和 "`--exclude-from`" 選項類似於 tar(1)

- 在源目錄中新增反斜槓的語法能夠避免在目標檔案中建立額外的目錄級別。

| 提示
在 表格 10.14, “其它版本控制系統工具列表” 中的版本控制系統 (VCS) 可以被認為是多路拷貝和同步工具。

### 10.1.3. 歸檔語法

以下是用不同的工具壓縮和解壓縮整個 "`./source`" 目錄中的內容。

GNU tar(1):

    $ tar -cvJf archive.tar.xz ./source
    $ tar -xvJf archive.tar.xz

或者，如下所示。

    $ find ./source -xdev -print0 | tar -cvJf archive.tar.xz --null -T -

cpio(1):

    $ find ./source -xdev -print0 | cpio -ov --null > archive.cpio; xz archive.cpio
    $ zcat archive.cpio.xz | cpio -i

### 10.1.4. 複製語法

如下是用不同的工具複製整個 "`./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`" 選項來忽略接受端上更新的檔案。

### 10.1.5. 查詢檔案的語法

find(1) 被用作從歸檔中篩選檔案也被用作拷貝指令 (參見節 10.1.3, “歸檔語法”和節 10.1.4, “複製語法”) 或者用於 xargs(1) (參見節 9.4.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`"。你可能同樣需要更改其他相關的指令。

### 10.1.6. 歸檔媒體

為重要的資料存檔尋找 儲存裝置 時，你應該注意它們的侷限性。對於小型的個人資料備份，我使用品牌公司的 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 和 紙只能寫一次，它們從根本上阻止了因為重寫導致的資料意外丟失。這是優點！

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

| 提示
如果你在使用一個可重複寫入的介質作為你的備份介質，使用支援只讀快照的 btrfs 或 zfs 檔案系統，也許是一個好注意。

### 10.1.7. 可移動儲存裝置

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

- USB 快閃記憶體盤

- 硬碟驅動器

- 光碟驅動器

- 數碼相機

- 數字音樂播放器

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

- USB

- IEEE 1394 / FireWire

- PC 卡

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

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

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

- PolicyKit 提供了所需的特權。

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

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

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

- FAT 格式的檔案系統使用 mlabel(1) 指令

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

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

| 提示
掛載時可能需要提供編碼選項（參見 節 8.1.3, “檔名編碼”）。

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

### 10.1.8. 選擇用於分享資料的檔案系統

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

| 注意
對硬碟(HDD)的描述也適合用於其它儲存裝置，比如 SSD / U 盤 / 記憶體卡 /……。替換例子中 `/dev/sda` 的裝置名稱，用其適合的裝置名稱 `/dev/nvme0`、`/dev/mmcblk0`……。

表格 10.3. 典型使用場景下可移動儲存裝置可選擇的檔案系統列表

檔案系統名 | 典型使用場景
--- | ---
FAT12 | 軟盤（<32MiB）上跨平臺的資料分享
FAT16 | 在小硬碟(<2GiB)上的跨平臺的資料分享
FAT32 | 在大硬碟（<8TiB，被 MS Windows95 OSR2 以上的作業系統所支援) 上的跨平臺的資料分享
exFAT | 在大硬碟類裝置上跨平臺共享資料（<512TiB，被 WindowsXP, Mac OS X Snow Leopard 10.6.5 和 Linux 核心 5.4 版本以上的作業系統所支援)
NTFS | 在大硬碟類裝置上的跨平臺共享資料 (在 MS Windows NT 和後續版本原生支援；在 Linux 上，通過使用 FUSE 的 NTFS-3G 支援。)
ISO9660 | 在 CD-R 和 DVD+/-R 上的跨平臺的靜態資料分享
UDF | CD-R 和 DVD+/-R (新)上的增量資料寫入
MINIX | 軟盤上磁碟空間高利用率的 unix 檔案資料儲存
ext2 | 在裝有老舊 linux 系統的硬碟上的資料分享
ext3 | 在裝有老舊 linux 系統的硬碟上的資料分享
ext4 | 在裝有較新的 linux 系統的硬碟上的資料分享
btrfs | 使用只讀快照在裝有較新的 Linux 系統的硬碟上共享資料

| 提示
檢視節 9.9.1, “使用 dm-crypt/LUKS 加密移動磁碟”來獲得關於使用裝置級加密的跨平臺的資料共享的資訊。

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

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

- 用 fdisk(8)，cfdisk(8) 或者 parted(8) 指令（參見節 9.6.2, “硬碟分割槽調配”）把它們格式化為單個的主分割槽並對把它做如下標記。

  - 標記小於 2GB 的 FAT 裝置為 字元"6"。

  - 標記更大的 FAT32 裝置為字元 "c"。

- 如下所示是用 mkfs.vfat(8) 指令格式化主分割槽的。

  - 它的裝置名字，例如 "`/dev/sda1`" 用於 FAT16 裝置

  - 明確的選項和它的裝置名，例如 "`-F 32 /dev/sda1`" 用於 FAT32 裝置

當使用 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"。

### 10.1.9. 網路上的資料分享

當使用網路來分享資料的時候，你應該使用通用的服務。這裡有一些提示。

表格 10.4. 典型使用場景下可選擇的網路服務列表

網路服務 | 典型使用場景描述
--- | ---
SMB/CIFS 用 Samba 掛載網路檔案系統 | 通過 “Microsoft Windows 網路” 分享檔案，參見 smb.conf(5) 和 官方 Samba 3.x.x 指導和參考手冊（The Official Samba 3.x.x HOWTO and Reference Guide） 或 `samba-doc` 軟體包
NFS 用 Linux 核心掛載網路檔案系統 | 通過 “Unix/Linux 網路" 分享檔案，參見 exports(5) 和 Linux NFS-HOWTO
HTTP 服務 | 在 web 伺服器/客戶端之間分享檔案
HTTPS 服務 | 在有加密的安全套接層 (SSL) 或者安全傳輸層 (TLS) 的網路伺服器/客戶端中分享檔案
FTP 服務 | 在 FTP 伺服器/客戶端之間分享檔案

儘管對於檔案分享來說，通過網路掛載檔案系統和傳輸檔案是相當方便的，但這可能是不安全的。它們的網路連線必須通過如下所示的加強安全性。

- 用 SSL/TLS 加密

- 建立 SSH 通道

- 建立 VPN 通道

- 網路之間需要有安全的防火牆

參見 節 6.5, “其它網路應用服務” 和 節 6.6, “其它網路應用客戶端”。

## 10.2. 備份和恢復

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

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

### 10.2.1. 備份和恢復策略

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

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

   - 你自己建立的資料檔案：在 "`~/`" 下的資料

   - 你使用的應用程式建立的資料檔案：在 "`/var/`" 下的資料（除了 "`/var/cache/`"，"`/var/run/`" 和 "`/var/tmp/`")

   - 系統組態檔案：在 "`/etc/`” 下的資料

   - 本地程式：在 "`/usr/local/`" 或 "`/opt/`" 下的資料

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

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

     - 使用者程序的 Cron 工作，檔案在 "`/var/spool/cron/crontabs`" 目錄，並且重啟 cron(8)。參見節 9.4.14, “定時任務安排”來獲得關於 cron(8) 和 crontab(1) 的資訊。

     - 使用者程序的 Systemd 計時器工作：檔案在 "`~/.config/systemd/user`" 目錄。參見 systemd.timer(5) 和 systemd.service(5)。

     - 使用者程序的自動啟動工作：檔案在 "`~/.config/autostart`" 目錄。參見 Desktop Application Autostart Specification。

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

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

   - 經常備份：有計劃的備份

   - 冗餘備份：資料映象

   - 傻瓜式操作：單個簡單指令備份

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

   - 資料丟失的風險

     - 資料至少是應該在不同的磁碟分割槽上，最好是在不同的磁碟和機器上，來承受檔案系統發生的損壞。重要資料最好儲存在一個只讀檔案系統上。[4]

   - 資料非法訪問的風險

     - 敏感的身份資料，比如 "`/etc/ssh/ssh_host_*_key`", "`~/.gnupg/*`", "`~/.ssh/*`", "`~/.local/share/keyrings/*`", "`/etc/passwd`", "`/etc/shadow`", "`popularity-contest.conf`", "`/etc/ppp/pap-secrets`", and "`/etc/exim4/passwd.client`" 應當使用加密備份。[5] (參見 節 9.9, “資料加密提示”。)

     - 即使在信任的系統上，也不能夠硬編碼系統登入密碼或者加密密碼到任何腳本里面。(參見 節 10.3.6, “密碼金鑰環”。)

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

     - 硬體（特別是硬碟）將會損壞

     - 檔案系統可能會損壞，裡面的資料可能被丟失

     - 對違規安全訪問而言，遠端儲存系統不能夠被信任

     - 弱的密碼保護能夠被輕鬆的破解

     - 檔案許可權系統可以被破解

   - 備份所需的資源：人力，硬體，軟體，…

     - 使用 cron 任務或者 systemd 計時器任務來自動化排程備份工作

| 提示
你能夠用 "`debconf-set-selections debconf-selections`" 命令恢復 debconf 調配資料，可以用 "`dpkg --set-selection <dpkg-selections.list`" 指令恢復 dpkg 篩選資料。

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

| 注意
當備份資料的時候，你可能希望停止一些應用程式的背景程式例如 MTA（參見節 6.2.4, “郵件傳輸代理 (MTA)”）。

### 10.2.2. 實用備份套件

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

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

軟體包 | 流行度 | 大小 | 說明
--- | --- | --- | ---
`bacula-common` | V:6.3, I:7.2 | 2501 | Bacula: 網路資料備份，恢復和核查-常見的支援檔案
`bacula-client` | V:0.3, I:1.9 | 199 | Bacula: 網路資料備份，恢復和核查-客戶端元軟體包
`bacula-console` | V:0.7, I:2.1 | 112 | Bacula: 網路資料備份，恢復和核查-文字終端
`bacula-server` | I:0.60 | 199 | Bacula: 網路資料備份，恢復和核查-伺服器端元軟體包
`amanda-common` | V:0.6, I:2.2 | 9851 | Amanda: 馬里蘭大學開發的高階自動化網路磁碟歸檔器（庫）
`amanda-client` | V:0.6, I:2.2 | 1099 | Amanda: 馬里蘭大學開發的高階自動化網路磁碟歸檔器（客戶端）
`amanda-server` | V:0.11, I:0.23 | 1093 | Amanda: 馬里蘭大學開發的高階自動化網路磁碟歸檔器（伺服器端）
`backuppc` | V:1.4, I:1.7 | 3088 | BackupPC 是用於備份 PC 機資料（基於磁碟）的高效能的企業級工具
`duplicity` | V:6, I:47 | 2670 | (遠端) 增量備份
`deja-dup` | V:29, I:43 | 5274 | duplicity 的 GUI（圖形使用者介面）前端
`borgbackup` | V:13, I:28 | 3485 | (遠端) 去重備份
`borgmatic` | V:3.2, I:4.4 | 946 | borgbackup 備份軟體的輔助軟體
`rdiff-backup` | V:2.3, I:6.6 | 1207 | (遠端) 增量備份
`restic` | V:6, I:12 | 41560 | (遠端) 增量備份
`backupninja` | V:2.2, I:2.6 | 360 | 輕量，可擴展的 meta-backup 系統
`slbackup` | V:0.11, I:0.13 | 147 | (遠端) 增量備份
`backup-manager` | V:0.43, I:0.77 | 573 | 指令列備份工具
`backup2l` | V:0.38, I:0.53 | 110 | 用於可掛載媒介 (基於磁碟的) 的低維護的備份/恢復工具

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

- Mondo Rescue 是一個備份系統，它能夠方便的從備份 CD/DVD 等裝置中快速恢復整個系統，而不需要經過常規的系統安裝過程。

- Bacula，Amanda 和 BackupPC 是全功能的備份實用套件，主要用於聯網的定期備份。

- Duplicity 和 Borg 是簡單的備份工具用於典型的工作站。

### 10.2.3. 備份技巧

對於一個個人工作站，為伺服器環境設計的全功能備份套件工具也行不是最合適的。與此同時，已有的用於工作站的備份工具有一些不足。

這裡有一些技巧讓備份更加容易，只需使用者做最小的工作。這些技巧可以同任意備份工具一起使用。

出於演示的目的，讓我們假設基本使用者和組名為 `penguin`，建立一個備份和快照指令碼例子"`/usr/local/bin/bkss.sh`"：

    #!/bin/sh -e
    SRC="$1" # source data path
    DSTFS="$2" # backup destination filesystem path
    DSTSV="$3" # backup destination subvolume name
    DSTSS="${DSTFS}/${DSTSV}-snapshot" # snapshot destination path
    if [ "$(stat -f -c %T "$DSTFS")" != "btrfs" ]; then
      echo "E: $DESTFS needs to be formatted to btrfs" >&2 ; exit 1
    fi
    MSGID=$(notify-send -p "bkup.sh $DSTSV" "in progress ...")
    if [ ! -d "$DSTFS/$DSTSV" ]; then
      btrfs subvolume create "$DSTFS/$DSTSV"
      mkdir -p "$DSTSS"
    fi
    rsync -aHxS --delete --mkpath "${SRC}/" "${DSTFS}/${DSTSV}"
    btrfs subvolume snapshot -r "${DSTFS}/${DSTSV}" ${DSTSS}/$(date -u --iso=min)
    notify-send -r "$MSGID" "bkup.sh $DSTSV" "finished!"

這裡，只使用基本工具 rsync(1)來幫助備份，儲存空間使用 Btrfs 來高效利用。

| 提示
提示：這個作者在他的工作站上使用他自己的類似 shell 指令碼"bss: Btrfs Subvolume Snapshot Utility"。

#### 10.2.3.1. GUI（圖形使用者介面）備份

這裡是一個建立單擊 GUI（圖形使用者介面）圖示備份的例子。

- 準備一個 USB 儲存裝置用來備份。

  - 格式化 USB 儲存裝置為一個分割槽，使用 btrfs 檔案系統，卷標名為"`BKUP`"。這個 U 盤也能夠加密 (參見 節 9.9.1, “使用 dm-crypt/LUKS 加密移動磁碟”)。

  - 把這個插入你的系統。桌面系統將自動掛載它到 "`/media/penguin/BKUP`"。

  - 執行"`sudo chown penguin:penguin /media/penguin/BKUP`"，讓它可以由使用者寫。

- 建立如下的"`~/.local/share/applications/BKUP.desktop`"檔案，按照 節 9.4.10, “從 GUI 啟動一個程式” 裡寫的技術：

      [Desktop Entry]
      Name=bkss
      Comment=Backup and snapshot of ~/Documents
      Exec=/usr/local/bin/bkss.sh /home/penguin/Documents /media/penguin/BKUP Documents
      Type=Application

對於每一次圖示單擊，你的資料從"`~/Documents`"備份到 USB 儲存裝置，並建立了一個只讀快照。

#### 10.2.3.2. 掛載事件觸發的備份

這裡是一個由掛載事件觸發的自動備份例子。

- 按 節 10.2.3.1, “GUI（圖形使用者介面）備份” 的方式準備一個 USB 儲存裝置用於備份。

- 建立一個如下的 systemd 服務單元檔案"`~/.config/systemd/user/back-BKUP.service`"：

      [Unit]
      Description=USB Disk backup
      Requires=media-%u-BKUP.mount
      After=media-%u-BKUP.mount

      [Service]
      ExecStart=/usr/local/bin/bkss.sh %h/Documents /media/%u/BKUP Documents
      StandardOutput=append:%h/.cache/systemd-snap.log
      StandardError=append:%h/.cache/systemd-snap.log

      [Install]
      WantedBy=media-%u-BKUP.mount

- 用下面的方式啟用這個 systemd 單元配置：

       $ systemctl --user enable bkup-BKUP.service

對於每一次掛載事件，你的資料從"`~/Documents`"備份到 USB 儲存裝置，並建立了一個只讀快照。

這裡，當前 systemd 在記憶體中的 systemd 掛載單元的名字，使用者使用 "`systemctl --user list-units --type=mount`" 來呼叫服務管理器來查詢。

#### 10.2.3.3. 時間事件觸發的備份

這裡是一個由時間事件觸發的自動備份例子。

- 按 節 10.2.3.1, “GUI（圖形使用者介面）備份” 的方式準備一個 USB 儲存裝置用於備份。

- 建立一個如下的 systemd 時間單元檔案"`~/.config/systemd/user/snap-Documents.timer`"：

      [Unit]
      Description=Run btrfs subvolume snapshot on timer
      Documentation=man:btrfs(1)

      [Timer]
      OnStartupSec=30
      OnUnitInactiveSec=900

      [Install]
      WantedBy=timers.target

- 建立一個如下的 systemd 服務單元檔案"`~/.config/systemd/user/snap-Documents.service`"：

      [Unit]
      Description=Run btrfs subvolume snapshot
      Documentation=man:btrfs(1)

      [Service]
      Type=oneshot
      Nice=15
      ExecStart=/usr/local/bin/bkss.sh %h/Documents /media/%u/BKUP Documents
      IOSchedulingClass=idle
      CPUSchedulingPolicy=idle
      StandardOutput=append:%h/.cache/systemd-snap.log
      StandardError=append:%h/.cache/systemd-snap.log

- 用下面的方式啟用這個 systemd 單元配置：

       $ systemctl --user enable snap-Documents.timer

對於每一次時間事件，你的資料從"`~/Documents`"備份到 USB 儲存裝置，並建立了一個只讀快照。

這裡，當前 systemd 在記憶體中的 systemd 使用者時間單元的名字，使用 "`systemctl --user list-units --type=timer`" 來呼叫服務管理器來查詢。

對於現在的桌面系統，這個 systemd 方案，比起傳統的 Unix at(1)、cron(8) 或 `anacron` 方式，能夠提供更精緻的細粒度控制。

## 10.3. 資料安全基礎

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

表格 10.6. 資料安全基礎工具列表

軟體包 | 流行度 | 大小 | 指令 | 說明
--- | --- | --- | --- | ---
`gnupg` | V:398, I:867 | 464 | gpg(1) | GNU 隱私衛士 - OpenPGP 加密和簽名工具
`gpgv` | V:234, I:939 | 555 | gpgv(1) | GNU 隱私衛士 - OpenPGP 簽名驗證工具
`sq` | V:1, I:27 | 23948 | sq(1) | Sequoia-PGP - OpenPGP 加密和簽名工具
`sqv` | V:416, I:487 | 1702 | sqv(1) | Sequoia-PGP - OpenPGP 簽名驗證工具
`paperkey` | V:1, I:13 | 58 | paperkey(1) | 從 OpenPGP 私鑰裡面，僅僅匯出私密資訊
`cryptsetup` | V:35, I:78 | 462 | cryptsetup(8), … | dm-crypt 塊裝置加密支援 LUKS 工具
`coreutils` | V:911, I:1000 | 17994 | md5sum(1) | 計算與校驗 MD5 訊息摘要
`coreutils` | V:911, I:1000 | 17994 | sha1sum(1) | 計算與校驗 SHA1 訊息摘要
`openssl` | V:847, I:996 | 2532 | `openssl`(1ssl) | 使用 "`openssl dgst`" (OpenSSL)計算資訊摘要
`libsecret-tools` | V:1, I:11 | 45 | secret-tool(1) | 儲存和取回密碼 (CLI)
`seahorse` | V:75, I:261 | 7971 | seahorse(1) | 金鑰管理工具(GNOME)

參見 節 9.9, “資料加密提示” 的 dm-crypt 和 fscrypt，它們通過 Linux 核心模組實現了自動資料加密架構。

### 10.3.1. GnuPG 金鑰管理

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

表格 10.7. GNU 隱私衛士金鑰管理指令的列表

指令 | 說明
--- | ---
`gpg --gen-key` | 生成一副新的金鑰對
`gpg --gen-revoke my_user_ID` | 生成 my_user_ID 的一份吊銷證書
`gpg --edit-key user_ID` | 互動式的編輯金鑰，輸入 "help" 來獲得幫助資訊
`gpg -o file --export` | 把所有的公共金鑰輸出到檔案
`gpg -o file --export-secret-keys` | 把所有的私有金鑰輸出到檔案
`gpg --import file` | 從檔案匯入金鑰
`gpg --send-keys user_ID` | 傳送 user_ID 的公鑰到公鑰伺服器
`gpg --recv-keys user_ID` | 從公鑰伺服器下載 user_ID 的公鑰
`gpg --list-keys user_ID` | 列出 user_ID 的所有金鑰
`gpg --list-sigs user_ID` | 列出 user_ID 的簽字
`gpg --check-sigs user_ID` | 檢查 user_ID 金鑰簽字
`gpg --fingerprint user_ID` | 檢查 user_ID 的指紋
`gpg --refresh-keys` | 更新本地金鑰

信任碼含義.

表格 10.8. 信任碼含義列表

程式碼 | 信任描述
--- | ---
`-` | 沒有所有者信任簽名/沒有計算
`e` | 信任計算失敗
`q` | 沒有足夠的資訊用於計算
`n` | 從不信任這個鍵
`m` | 最低限度的信任
`f` | 完全信任
`u` | 最終信任

如下命令生成我的公鑰 "`9563FC29932C409F1A77F9C1AB8A1522D8234C6A`" 。

    $ gpg --gen-key
    gpg (GnuPG) 2.4.7; Copyright (C) 2024 g10 Code GmbH
    ...
    GnuPG needs to construct a user ID to identify your key.

    Real name: Osamu Aoki
    Email address: osamu@debian.org
    You selected this USER-ID:
        "Osamu Aoki <osamu@debian.org>"

    Change (N)ame, (E)mail, or (O)kay/(Q)uit? o
    ...
    public and secret key created and signed.

    pub   ed25519 2026-02-14 [SC] [expires: 2029-02-13]
          9563FC29932C409F1A77F9C1AB8A1522D8234C6A
    uid                      Osamu Aoki <osamu@debian.org>
    sub   cv25519 2026-02-14 [E] [expires: 2029-02-13]

如下指令上傳我的 "`9563FC29932C409F1A77F9C1AB8A1522D8234C6A`" 公鑰到主流的公鑰伺服器 "`hkp://keys.gnupg.net`"。

    $ gpg --keyserver hkp://keys.gnupg.net --send-keys 9563FC29932C409F1A77F9C1AB8A1522D8234C6A

預設良好的公鑰伺服器在 "`~/.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`" 選項.

使用SHA-1作為雜湊演算法已棄用。如果基於openPGP的RSA使用了SHA-1作為雜湊演算法，可以使用 FixKeyWithSha1來修復。

| 提示
sq(1) 和 sqv(1) 命令是 openPGP 命令的替代命令集合。參見 sq 使用者文件 和 使用 sq 的實踐介紹 ，Sequoia PGP 命令列.

### 10.3.2. 在檔案上使用 GnuPG

這裡有一些在檔案上使用 GNU 隱私衛士 指令的例子。

表格 10.9. 在檔案上使用的 GNU 隱私衛士的指令列表

指令 | 說明
--- | ---
`gpg -a -s file` | ASCII 封裝的簽名檔案 file.asc
`gpg --armor --sign file` | 同上
`gpg --clearsign file` | 生成明文簽字資訊
`gpg --clearsign file|mail foo@example.org` | 傳送一份明文簽字到 `foo@example.org`
`gpg --clearsign --not-dash-escaped patchfile` | 明文簽名的補丁檔案
`gpg --verify file` | 驗證明文檔案
`gpg -o file.sig -b file` | 生成一份分離的簽字
`gpg -o file.sig --detach-sign file` | 同上
`gpg --verify file.sig file` | 使用 file.sig 驗證檔案
`gpg -o crypt_file.gpg -r name -e file` | 公鑰加密，從檔案裡面獲得名字，生成二進位制的 crypt_file.gpg
`gpg -o crypt_file.gpg --recipient name --encrypt file` | 同上
`gpg -o crypt_file.asc -a -r name -e file` | 公鑰加密，從檔案中獲得名字，生成 ASCII 封裝的 crypt_file.asc
`gpg -o crypt_file.gpg -c file` | 將檔案對稱加密到 crypt_file.gpg
`gpg -o crypt_file.gpg --symmetric file` | 同上
`gpg -o crypt_file.asc -a -c file` | 對稱加密，從檔案到 ASCII 封裝的 crypt_file.asc
`gpg -o file -d crypt_file.gpg -r name` | 解密
`gpg -o file --decrypt crypt_file.gpg` | 同上

### 10.3.3. 在 Mutt 中使用 GnuPG

增加下面內容到 "`~/.muttrc`"，在自動啟動時，避免一個慢的 GnuPG，在索引選單中按 "`S`" 來允許它使用。

    macro index S ":toggle pgp_verify_sig\n"
    set pgp_verify_sig=no

### 10.3.4. 在 vim 中使用 GnuPG

`gnupg` 外掛可以讓你對副檔名為 "`.gpg`", "`.asc`", 和 "`.pgp`"的檔案可靠的執行 GnuPG。[6]

    $ sudo aptitude install vim-scripts
    $ echo "packadd! gnupg" >> ~/.vim/vimrc

### 10.3.5. MD5 校驗和

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.3.6. 密碼金鑰環

在 GNOME 系統，GUI（圖形使用者介面）工具 seahorse(1) 管理密碼，安全的在金鑰環 `~/.local/share/keyrings/*` 裡面儲存它們。

secret-tool(1) 能夠從命令列儲存密碼到鑰匙環。

讓我們儲存 LUKS/dm-crypt 加密磁碟映象用到的密碼

    $ secret-tool store --label='LUKS passphrase for disk.img' LUKS my_disk.img
    Password: ********

這個儲存的密碼能夠被獲取並給到其它程式，比如 cryptsetup(8)。

    $ secret-tool lookup LUKS my_disk.img | \
      cryptsetup open disk.img disk_img --type luks --keyring -
    $ sudo mount /dev/mapper/disk_img /mnt

| 提示
無論何時，你需要在一個腳本里面提供密碼時，使用 `secret-tool` 來避免將密碼直接硬編碼到腳本里面。

## 10.4. 原始碼合併工具

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

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

軟體包 | 流行度 | 大小 | 指令 | 說明
--- | --- | --- | --- | ---
`patch` | V:103, I:726 | 242 | patch(1) | 給原檔案打補丁
`vim` | V:85, I:347 | 4135 | vimdiff(1) | 在 vim 中並排比較兩個檔案
`imediff` | V:0.03, I:0.26 | 329 | imediff(1) | 全屏互動式兩路/三路合併工具
`meld` | V:5, I:24 | 3992 | meld(1) | 比較和移植檔案(GTK)
`wiggle` | V:0.01, I:0.12 | 175 | wiggle(1) | 應用被拒絕的補丁
`diffutils` | V:896, I:998 | 1768 | diff(1) | 逐行比較兩個檔案
`diffutils` | V:896, I:998 | 1768 | diff3(1) | 逐行比較和合並三個檔案
`quilt` | V:2, I:17 | 880 | quilt(1) | 管理系列補丁
`wdiff` | V:6, I:40 | 651 | wdiff(1) | 在文字檔案中，顯示單詞的不同
`diffstat` | V:9, I:98 | 79 | diffstat(1) | 通過 diff 生成一個改變柱狀圖
`patchutils` | V:11, I:97 | 269 | combinediff(1) | 從兩個增量補丁建立一個積累補丁
`patchutils` | V:11, I:97 | 269 | dehtmldiff(1) | 從一個 HTML 頁面提取出一個 diff
`patchutils` | V:11, I:97 | 269 | filterdiff(1) | 從一個 diff 檔案裡面提取或者排除 diff 檔案
`patchutils` | V:11, I:97 | 269 | fixcvsdiff(1) | 修復由 CVS patch(1) 錯誤建立的 diff 檔案
`patchutils` | V:11, I:97 | 269 | flipdiff(1) | 交換兩個補丁的順序
`patchutils` | V:11, I:97 | 269 | grepdiff(1) | 顯示哪些檔案是由匹配正規表達式的補丁修改
`patchutils` | V:11, I:97 | 269 | interdiff(1) | 顯示在兩個統一格式 diff 檔案（基於同一個檔案的兩個不同 diff 檔案）之間的差異
`patchutils` | V:11, I:97 | 269 | lsdiff(1) | 顯示哪些檔案由補丁修改
`patchutils` | V:11, I:97 | 269 | recountdiff(1) | 重新計算通用內容 diff 檔案的數量和偏移
`patchutils` | V:11, I:97 | 269 | rediff(1) | 修復手工編輯 diff 檔案的數量和偏移
`patchutils` | V:11, I:97 | 269 | splitdiff(1) | 隔離出增量補丁
`patchutils` | V:11, I:97 | 269 | unwrapdiff(1) | 識別已經被分詞的補丁
`dirdiff` | V:0.1, I:1.4 | 167 | dirdiff(1) | 顯示目錄樹之間的不同並移植改變
`docdiff` | V:0.03, I:0.25 | 554 | docdiff(1) | 逐詞逐字的比較兩個檔案
`makepatch` | V:0.02, I:0.16 | 99 | makepatch(1) | 生成擴展補丁檔
`makepatch` | V:0.02, I:0.16 | 99 | applypatch(1) | 套用擴展補丁檔

### 10.4.1. 從原始碼檔案匯出差異

下面的操作，匯出兩個原始檔的不同，並根據檔案的位置，建立通用 diff 檔案"`file.patch0`" 或 "`file.patch1`".

    $ diff -u file.old file.new > file.patch0
    $ diff -u old/file new/file > file.patch1

### 10.4.2. 原始碼檔案移植更新

diff 檔案（通常被叫作 patch 補丁檔案），用於傳送一個程式更新。通過下面的方式，接收到的部分，應用這個更新到其它檔案。

    $ patch -p0 file < file.patch0
    $ patch -p1 file < file.patch1

### 10.4.3. 互動式移植

如果一個原始碼，你有兩個版本，你可以通過下面的方式，使用 imediff(1) 執行兩方互動式移植。

    $ imediff -o file.merged file.old file.new

如果一個原始碼，你有三個版本，你可以通過下面的方式，使用 imediff(1) 執行互動式三方移植。

    $ imediff -o file.merged file.yours file.base file.theirs

## 10.5. Git

Git 是這些天選擇的用於 版本控制系統 version control system (VCS) 的工具，因為 Git 能夠同時在本地和遠端原始碼管理上，做任何事情。

通過 Debian Salsa service，Debian 能夠提供免費的 Git 服務。在 http://wiki.debian.org/Salsa 能找到它的說明文件。

下面是一些 Git 相關軟體包。

表格 10.11. git 相關包和指令列表

軟體包 | 流行度 | 大小 | 指令 | 說明
--- | --- | --- | --- | ---
`git` | V:406, I:616 | 50972 | git(7) | Git 快速、可擴展、分佈式的版本控制系統
`gitk` | V:4, I:27 | 2022 | gitk(1) | 有歷史功能的 Git 圖形倉庫瀏覽器
`qgit` | V:0.2, I:2.0 | 1431 | dgit(1) | 有歷史功能的 Git 圖形倉庫瀏覽器
`git-cola` | V:0.7, I:4.6 | 5005 | git-cola(1) | 有歷史功能的 Git 圖形倉庫瀏覽器
`tig` | V:2, I:12 | 1243 | tig(1) | 瀏覽 Git 歷史倉庫的控制台
`lazygit` | V:0.9, I:3.6 | 24167 | lazygit(1) | 瀏覽 Git 歷史倉庫的控制台
`git-gui` | V:1, I:17 | 2525 | git-gui(1) | Git 圖形界面（無歷史功能）
`git-email` | V:0.4, I:9.8 | 1204 | git-send-email(1) | 從 Git 用電子郵件發送收集到的補丁
`git-buildpackage` | V:1.2, I:7.1 | 2027 | git-buildpackage(1) | 用 Git 自動製作 Debian 包
`dgit` | V:0.2, I:1.0 | 738 | dgit(1) | Debian 檔案庫的 git 互動操作
`imediff` | V:0.03, I:0.26 | 329 | git-ime(1) | 互動式的分開 git 提交的輔助工具
`stgit` | V:0.08, I:0.50 | 6181 | stg(1) | 封裝的 git (Python)
`git-doc` | I:11 | 14896 | N/A | Git 官方文檔
`gitmagic` | I:0.52 | 721 | N/A | "Git 魔術"，易於理解的 Git 手冊

### 10.5.1. 調配 Git 客戶端

你可以在 "`~/.gitconfig`" 裏面設置幾個 Git 接下來需要使用的全局調配，比如說你的名字和電子郵件地址。

    $ git config --global user.name "Name Surname"
    $ git config --global user.email yourname@example.com

你也可以按如下所示定製 Git 的預設行為。

    $ git config --global init.defaultBranch main
    $ git config --global pull.rebase true
    $ git config --global push.default current

如果你習慣使用 CVS 或 Subversion 指令，你也許希望設置如下幾個指令別名。

    $ git config --global alias.ci "commit -a"
    $ git config --global alias.co checkout

你能夠通過如下方式檢查你的整體組態。

    $ git config --global --list

### 10.5.2. 基本的 Git 命令

Git 操作涉及幾個資料。

- 工作樹目錄保持面向使用者的檔案，你可以對這些檔案做修改。

  - 需要被記錄的改變，必須明確的被選擇並暫存到索引。這是 `git add` 和 `git rm` 命令。

- 索引保持暫存檔案。

  - 在接下來的請求之前，暫存檔案將被提交到本地倉庫。這個是 `git commit` 命令。

- 本地倉庫保持已經提交的的檔案。

  - Git 記錄提交資料的連結歷史並在倉庫裡面將它們作為分支組織。

  - 本地倉庫通過 `git push` 命令傳送資料到遠端倉庫。

  - 本地倉庫能夠通過 `git fetch` 和 `git pull` 命令從遠端倉庫接收資料。

    - `git pull` 命令在 `git fetch` 後執行 `git merge` 或 `git rebase` 命令。

    - 這裡，`git merge` 聯合兩個獨立分支的歷史結尾到一個點。（在沒有定製的 `git pull` ，這個是預設的，同時對上游作者釋出分支到許多人時，也是好的 ）

    - 這裡，`git rebase` 建立一個遠端分支的序列歷史的單個分支，跟著本地分支。（這是定製 `pull.rebase true` 的情況，對我們其餘的用途有用。）

- 遠端倉庫保持已經提交的檔案。

  - 到遠端倉庫的通訊，使用安全的通訊協議，比如 SSH 或 HTTPS。

工作樹是在 `.git/` 目錄之外的檔案。在 `.git/` 目錄裡面的檔案，包括索引、本地倉庫資料和一些 git 配置的文本檔案。

這裡是主要的 Git 命令概覽。

表格 10.12. 主要的 Git 命令

Git 命令 | 功能
--- | ---
`git init` | 建立(本地)儲存庫
`git clone URL` | 克隆遠端儲存庫到本地倉庫工作目錄樹
`git pull origin main` | 通過遠端倉庫 `origin` 更新本地 `main` 分支
`git add .` | 增加工作樹裡面的檔案僅作為預先存在的索引檔案
`git add -A .` | 增加工作樹裡面的所有檔案到索引（包括已經刪除的）
`git rm filename` | 從工作樹和索引中刪除檔案
`git commit` | 提交在索引中的暫存改變到本地儲存庫
`git commit -a` | 新增工作樹裡的所有的改變到索引並提交它們到本地倉庫（新增 + 提交）
`git push -u origin branch_name` | 使用本地 `branch_name` 分支更新遠端倉庫 `origin`（初始啟用）
`git push origin branch_name` | 使用本地 `branch_name` 分支更新遠端倉庫 `origin`（隨後呼叫）
`git diff treeish1 treeish2` | 顯示 treeish1 提交和 treeish2 提交的不同
`gitk` | VCS 儲存庫分支歷史樹的圖形介面顯示

### 10.5.3. Git 技巧

下面是一些 Git 技巧。

表格 10.13. Git 技巧

Git 命令列 | 功能
--- | ---
`gitk --all` | 參看完整的 Git 歷史和操作，比如重置 HEAD 到另外一個提交、挑選補丁、建立標籤和分支……
`git stash` | 得到一個乾淨的工作樹，不會丟失資料
`git remote -v` | 檢查遠端設定
`git branch -vv` | 檢查分支設定
`git status` | 顯示工作樹狀態
`git config -l` | 列出 git 設定
`git reset --hard HEAD; git clean -x -d -f` | 反轉所有工作樹的改變並完全清理它們
`git rm --cached filename` | 反轉由 `git add filename` 改變的暫存索引
`git reflog` | 獲取參考日誌（對從刪除的分支中恢復提交有用）
`git branch new_branch_name HEAD@{6}` | 從 reflog 資訊建立一個新的分支
`git remote add new_remote URL` | 增加一個由 URL 指向的遠端倉庫 `new_remote`
`git remote rename origin upstream` | 遠端倉庫的名字從 `origin` 重新命名到 `upstream`
`git branch -u upstream/branch_name` | 設定遠端跟蹤到遠端倉庫 `upstream` 和它的分支名 `branch_name`。
`git remote set-url origin https://foo/bar.git` | 改變 `origin` 的 URL
`git remote set-url --push upstream DISABLED` | 禁止推送到 `upstream`（編輯 `.git/config` 來重新啟用）
`git remote update upstream` | 獲取 `upstream` 倉庫中所有遠端分支更新
`git fetch upstream foo:upstream-foo` | 建立本地（可能是孤立的）`upstream-foo` 分支，作為`upstream` 倉庫中 `foo` 分支的一個複製
`git checkout -b topic_branch ; git push -u topic_branch origin` | 製作一個新的 `topic_branch` 並把它推送到 `origin`
`git branch -m oldname newname` | 本地分支改名
`git push -d origin branch_to_be_removed` | 刪除遠端分支（新的方式）
`git push origin :branch_to_be_removed` | 刪除遠端分支（老的方式）
`git checkout --orphan unconnected` | 建立一個新的 `unconnected` 分支
`git rebase -i origin/main` | 從 `origin/main` 重新排序、刪除、壓縮提交到一個乾淨的分支歷史
`git reset HEAD^; git commit --amend` | 壓縮最後兩個提交為一個
`git checkout topic_branch ; git merge --squash topic_branch` | 壓縮整個 `topic_branch` 到一個提交
`git fetch --unshallow --update-head-ok origin '+refs/heads/*:refs/heads/*'` | 反轉一個淺克隆到一個所有分支的完整克隆
`git ime` | 分開最後的提交到一系列單個逐一檔案的小提交。（要求 `imediff`）
`git repack -a -d; git prune` | 本地倉庫重新打包到一個單獨的包中（這可能限制從刪除分支裡面恢復丟失資料等機會）

| 警告
不要使用帶空格的標簽字串。即使一些工具，如 gitk(1) 允許你使用它，但會阻礙其它 `git` 指令。

| 注意
如果一個本地分支推送到一個已經變基或者壓縮過的倉庫，推送這樣的分支有風險，並要求 `--force` 選項。這通常對 `main` 分支來說不可接受，但對於一個移植到 `main` 分支前的特定分支，是可以接受的。

| 注意
從指令列通過 "`git-xyz`" 直接呼叫 `git` 子指令的方式，從 2006 年早期開始就被取消。

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

### 10.5.4. Git 參考

看下面。

- man 手冊： git(1) (`/usr/share/doc/git-doc/git.html`)

- Git 使用者手冊 (`/usr/share/doc/git-doc/user-manual.html`)

- git 介紹教學 (`/usr/share/doc/git-doc/gittutorial.html`)

- git 介紹教學：第二部 (`/usr/share/doc/git-doc/gittutorial-2.html`)

- GIT 每一天 20個左右的命令 (`/usr/share/doc/git-doc/giteveryday.html`)

- Git 魔術 (`/usr/share/doc/gitmagic/html/index.html`)

### 10.5.5. 其它的版本控制系統

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

這裡是 Debian 系統上著名的其它非 Git 的 VCS 彙總。

表格 10.14. 其它版本控制系統工具列表

軟體包 | 流行度 | 大小 | 工具 | VCS 型別 | 描述
--- | --- | --- | --- | --- | ---
`mercurial` | V:3, I:26 | 2575 | Mercurial | 分散式 | mercurial 主要是用 Python 寫的還有一部分是 C 寫的
`darcs` | V:0.2, I:3.3 | 38856 | Darcs | 分散式 | 有智慧代數補丁的 DVCS（慢）
`tla` | V:0.04, I:0.72 | 1022 | GNU arch | 分散式 | 主要由 Tom Lord 寫的 DVCS (成為歷史的)
`bzr` | V:0.1, I:4.3 | 28 | GNU Bazaar | 分散式 | 受 `tla` 啟發並且是用 Python 寫的 DVCS (歷史)
`subversion` | V:10, I:57 | 4849 | Subversion | 遠端 | ”比 CVS 做的好“，遠端 VCS 的新標準（歷史）
`cvs` | V:3, I:25 | 4835 | CVS | 遠端 | 以前的遠端 VCS 標準（歷史）
`tkcvs` | V:0.12, I:0.88 | 34 | CVS, … | 遠端 | VCS (CVS,Subversion,RCS) 儲存庫樹的圖形介面顯示
`rcs` | V:1.7, I:9.5 | 578 | RCS | 本地 | "比 Unix SCCS 做的好"（歷史）
`cssc` | V:0.01, I:0.35 | 2044 | CSSC | 本地 | Unix SCCS 的克隆（歷史）

[4] 一個只能寫一次的媒介，例如 CD/DVD-R， 能防止覆蓋事故。（參見 節 9.8, “二進位制資料” 怎樣在 shell 命令列寫入儲存媒介。GNOME 桌面圖形環境可以讓你輕鬆的通過選單：“位置 → CD/DVD 燒錄”來實現寫入操作。）

[5] 這些資料中的一些，不能夠通過在系統裡面輸入同樣的字串來重新生成。

[6] 如果你使用 "`~/.vimrc`" 代替 "`~/.vim/vimrc`"，請進行相應的取代。

章 9. 系統技巧 |  | 章 11. 資料轉換