第 10 章 数据管理
以下是关于在 Debian 系统上管理二进制和文本数据的工具及其相关提示。
10.1. 共享,拷贝和存档
警告 | |
---|---|
为避免 竞争情况,不应当对正在进行写操作的设备和文件,多个进程进行不协调的写操作。采用flock(1) 的 文件锁定 机制可用于避免这种情况。 |
数据的安全和它的受控共享有如下几个方面。
存档文件的建立
远程存储访问
复制
跟踪修改历史
促进数据共享
防止未经授权的文件访问
检测未经授权的文件修改
这些可以通过使用工具集来实现。
存档和压缩工具
复制和同步工具
网络文件系统
移动存储媒介
安全 shell
认证体系
版本控制系统工具
哈希算法和加密工具
10.1.1. 存档和压缩工具
以下是 Debian 系统上可用的存档和压缩工具的预览。
表 10.1. 存档和压缩工具列表
软件包 | 流行度 | 大小 | 扩展名 | 命令 | 描述 |
---|---|---|---|---|---|
tar | V:905, I:999 | 3098 | .tar | tar(1) | 标准的归档工具(默认) |
cpio | V:412, I:998 | 1136 | .cpio | cpio(1) | Unix System V 风格的归档器,与 find(1) 一起使用 |
binutils | V:164, I:678 | 97 | .ar | ar(1) | 创建静态库的归档工具 |
fastjar | V:2, I:29 | 183 | .jar | fastjar(1) | Java 归档工具(类似 zip) |
pax | V:13, I:26 | 170 | .pax | pax(1) | 新的 POSIX 归档工具,介于 tar 和 cpio 之间 |
gzip | V:883, I:999 | 245 | .gz | gzip(1), zcat(1), … | GNU LZ77 压缩工具(默认) |
bzip2 | V:157, I:970 | 122 | .bz2 | bzip2(1), bzcat(1), … | Burrows-Wheeler block-sorting 压缩工具有着比 gzip(1) 更高的压缩率 (跟 gzip 有着相似的语法但速度比它慢) |
lzma | V:2, I:29 | 149 | .lzma | lzma(1) | LZMA 压缩工具有着比 gzip(1) 更高的压缩率(不推荐) |
xz-utils | V:454, I:977 | 612 | .xz | xz(1), xzdec(1), … | XZ 压缩工具有着比 bzip2(1) 更高的压缩率(压缩速度慢于 gzip 但是比 bzip2 快; LZMA 压缩工具的替代品) |
p7zip | V:89, I:464 | 987 | .7z | 7zr(1), p7zip(1) | 有着更高压缩率的 7-zip 文件归档器(LZMA 压缩) |
p7zip-full | V:113, I:486 | 4664 | .7z | 7z(1), 7za(1) | 有着更高压缩率的 7-Zip 文件归档器(LZMA 压缩和其他) |
lzop | V:9, I:76 | 164 | .lzo | lzop(1) | LZO 压缩工具有着比 gzip(1) 更高的压缩和解压缩速度 (跟 gzip 有着相似的语法但压缩率比它低) |
zip | V:51, I:432 | 608 | .zip | zip(1) | InfoZip:DOS 归档器和压缩工具 |
unzip | V:154, I:798 | 566 | .zip | unzip(1) | InfoZIP:DOS 解档器和解压缩工具 |
警告 | |
---|---|
除非你知道将会发生什么,否则不要设置 “ |
注意 | |
---|---|
gzipped tar(1) 归档器用于扩展名是 “ |
注意 | |
---|---|
xz-compressed tar(1) 归档器用于扩展名是 “ |
注意 | |
---|---|
FOSS 工具,例如 tar(1),中的主流压缩方法已经按如下所示的迁移: |
注意 | |
---|---|
cp(1),scp(1) 和 tar(1) 工具可能并不适用于一些特殊的文件。cpio(1) 工具的适用范围是最广的。 |
注意 | |
---|---|
cpio(1) 是被设计为与 find(1) 和其它命令一起使用,适合于创建备份脚本的场景,因此,脚本的文件选择部分能够被独立测试。 |
注意 | |
---|---|
Libreoffice 数据文件的内部结构是 “ |
注意 | |
---|---|
事实上跨平台支持最好的存档工具是 |
10.1.2. 复制和同步工具
以下是 Debian 系统上的可用的简单复制和备份工具的预览。
表 10.2. 复制和同步工具列表
软件包 | 流行度 | 大小 | 工具 | 功能 |
---|---|---|---|---|
coreutils | V:891, I:999 | 17478 | GNU cp | 复制本地文件和目录(“-a” 参数实现递归) |
openssh-client | V:803, I:996 | 4298 | scp | 复制远端文件和目录(客户端,”-r “ 参数实现递归) |
openssh-server | V:690, I:834 | 1567 | sshd | 复制远端文件和目录(远程服务器) |
rsync | V:281, I:560 | 677 | - | 单向远程同步和备份 |
unison | V:4, I:17 | 14 | - | 双向远程同步和备份 |
在复制文件的时候, rsync(8) 比其他工具提供了更多的特性。
差分传输算法只会发送源文件与已存在的目标文件之间的差异部分
快速检查算法 (默认) 会查找大小或者最后的修改时间有变化的文件
“
--exclude
“ 和 “--exclude-from
“ 选项类似于 tar(1)在源目录中添加反斜杠的语法能够避免在目标文件中创建额外的目录级别。
提示 | |
---|---|
在 cron(8) 下使用” |
提示 | |
---|---|
在 表 10.11 “版本控制系统工具列表” 中的版本控制系统 (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 -F -
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) 可以用 “ |
10.1.5. 查找文件的语法
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
这些命令会执行如下动作。
查找 “
/path/to
“ 下的所有文件限定全局查找的文件系统并且使用的是 ERE (参见第 1.6.2 节 “正则表达式”)
通过停止处理的方式来排除匹配 “
.*\.cpio
“ 或 “.*~
“ 正则表达式的文件通过停止处理的方式来排除匹配 “
.*/\.git
“ 正则表达式的目录通过停止处理的方式来排除比 99MB (1048576字节单元) 更大的文件
显示文件名,满足以上搜索条件并且比 “
/path/to/timestamp
“ 新的文件
请留心以上例子中的 “-prune -o
“ 排除文件的习惯用法。
注意 | |
---|---|
对于非 Debian 系的 Unix-like 系统,有些参数可能不被 find(1) 命令所支持。在这种情况下,应该考虑调整匹配方法并用 “ |
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 和 纸只能写一次,它们从根本上阻止了因为重写导致的数据意外丢失。这是优点! |
提示 | |
---|---|
如果你需要更快更频繁的进行大数据备份,那么通过高速网络连接的远端主机上的硬盘来实现备份,可能是唯一可行的方法。 |
10.1.7. 可移动存储设备
可移动存储设备可能是以下的任何一种。
它们可以通过以下的方式来进行连接。
像 GNOME 和 KDE 这样的现代桌面环境能够在 “/etc/fstab
“ 文件中没有匹配条目的时候,自动挂载这些可移动设备。
提示 | |
---|---|
umount(8) 在自动挂载设备的时候可能会带有 “ |
提示 | |
---|---|
只有当这些可移动设备没有在 “ |
现代桌面环境下的挂载点被选为 “/media/<disk_label>
“,它可以被如下所示的来定制。
FAT 格式的文件系统使用 mlabel(1) 命令
ISO9660 文件系统使用带有 “
-V
“ 选项的 genisoimage(1) 命令ext2/ext3/ext4 文件系统使用带有 “
-L
“ 选项的 tune2fs(1) 命令
提示 | |
---|---|
挂载时可能需要提供编码选项(参见 第 8.4.6 节 “文件名编码”)。 |
提示 | |
---|---|
在图形界面菜单上移除文件系统,可能会移除它的动态设备节点例如 “ |
10.1.8. 选择用于分享数据的文件系统
当你通过可移动存储设备与其他系统分享数据的时候,你应该先把它格式化为被两种操作系统都支持的通用的 文件系统。下面是文件系统的列表。
表 10.3. 典型使用场景下可移动存储设备可选择的文件系统列表
文件系统 | 典型使用场景描述 |
---|---|
FAT12 | 软盘(<32MiB)上跨平台的数据分享 |
FAT16 | 在小硬盘(<2GiB)上的跨平台的数据分享 |
FAT32 | 在大硬盘(<8TiB,被 MS Windows95 OSR2 以上的操作系统所支持) 上的跨平台的数据分享 |
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 系统的硬盘上的数据分享 |
提示 | |
---|---|
查看第 9.8.1 节 “使用 dm-crypt/LUKS 加密移动磁盘”来获得关于使用设备级加密的跨平台的数据共享的信息。 |
FAT 文件系统被绝大多数的现代操作系统支持,它对于通过可移动硬盘进行的数据交换是非常有用的。
当格式化像装有 FAT 文件系统的跨平台数据共享的可移动设备时,以下应该是保险的选择。
用 fdisk(8),cfdisk(8) 或者 parted(8) 命令(参见第 9.5.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 文件系统的设计,最大的文件大小为 |
注意 | |
---|---|
微软系统本身并不建议在超过 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 服务器/客户端之间分享文件 |
尽管对于文件分享来说,通过网络挂载文件系统和传输文件是相当方便的,但这可能是不安全的。它们的网络连接必须通过如下所示的加强安全性。
参见 第 6.10 节 “其它网络应用服务” 和 第 6.11 节 “其它网络应用客户端”。
10.2. 备份和恢复
我们都熟知计算机有时会出问题,或者由于人为的错误导致系统和数据损坏。备份和恢复操作是成功的系统管理中非常重要的一部分。可能有一天你的电脑就会出问题。
提示 | |
---|---|
保持你的备份系统简洁并且经常备份你的系统,有备份数据比你采用的备份方法的技术先进要重要的多。 |
有3个关键的因素决定实际的备份和恢复策略。
知道要备份和恢复什么。
你自己创建的数据文件:在 “
~/
“ 下的数据你使用的应用程序创建的数据文件:在 “
/var/
“ 下的数据(除了 “/var/cache/
“,”/var/run/
“ 和 “/var/tmp/
“)系统配置文件:在 “
/etc/
” 下的数据本地软件:在 “
/usr/local/
“ 或 “/opt/
“ 下的数据系统安装信息:关键步骤 (分区,…) 的纯文本备忘录
验证数据结果:通过实验性的恢复操作来预先验证
知道怎样去备份和恢复。
安全的数据存储:保护其免于覆盖和系统故障
经常备份:有计划的备份
冗余备份:数据镜像
傻瓜式操作:单个简单命令备份
评估涉及的风险和成本。
评估数据丢失的损失
备份所需的资源:人力,硬件,软件,…
数据丢失的方式及其可能性
注意 | |
---|---|
除非你知道自己做的是什么,否则不要备份 |
至于安全的数据存储,数据至少是应该在不同的磁盘分区上最好是在不同的磁盘和机器上,来承受文件系统发生的损坏。重要的数据最好存储在只能写一次的媒介上例如 CD/DVD-R 来防止覆盖事故。(参见 第 9.7 节 “二进制数据” 怎样在 shell 命令行写入存储媒介。GNOME 桌面图形环境可以让你轻松的通过菜单:“位置 → CD/DVD 刻录”来实现写入操作。)
注意 | |
---|---|
当备份数据的时候,你可能希望停止一些应用程序的守护进程例如 MTA(参见第 6.3 节 “邮件传输代理 (MTA)”)。 |
注意 | |
---|---|
你应该格外小心地备份和恢复身份认证相关的数据文件例如 “ |
注意 | |
---|---|
如果你以用户进程的方式执行 cron job,你必须存储文件到 “ |
10.2.1. 实用备份套件
以下是 Debian 系统上值得注意的实用备份程序套件的列表。
表 10.5. 实用备份程序套件列表
软件包 | 流行度 | 大小 | 说明 |
---|---|---|---|
dump | V:1, I:6 | 352 | 4.4 BSD dump(8) 和 restore(8) 命令用于 ext2/ext3/ext4 文件系统 |
xfsdump | V:0, I:9 | 854 | 在 GNU/Linux 和 IRIX 上用 xfsdump(8) 和 xfsrestore(8) 命令来备份和恢复 XFS 文件系统 |
backupninja | V:4, I:5 | 355 | 轻量的可扩展的 meta-backup 系统 |
bacula-common | V:10, I:15 | 2158 | Bacula: 网络数据备份,恢复和核查-常见的支持文件 |
bacula-client | I:3 | 183 | Bacula: 网络数据备份,恢复和核查-客户端元软件包 |
bacula-console | V:1, I:5 | 107 | Bacula: 网络数据备份,恢复和核查-文本终端 |
bacula-server | I:1 | 183 | Bacula: 网络数据备份,恢复和核查-服务器端元软件包 |
amanda-common | V:0, I:2 | 10031 | Amanda: 马里兰大学开发的高级自动化网络磁盘归档器(库) |
amanda-client | V:0, I:2 | 1089 | Amanda: 马里兰大学开发的高级自动化网络磁盘归档器(客户端) |
amanda-server | V:0, I:0 | 1076 | Amanda: 马里兰大学开发的高级自动化网络磁盘归档器(服务器端) |
backup-manager | V:1, I:2 | 572 | 命令行备份工具 |
backup2l | V:0, I:1 | 114 | 用于可挂载媒介 (基于磁盘的) 的低维护的备份/恢复工具 |
backuppc | V:3, I:3 | 3182 | BackupPC 是用于备份 PC 机数据(基于磁盘)的高性能的企业级工具 |
duplicity | V:7, I:15 | 1761 | (远程) 增量备份 |
flexbackup | V:0, I:0 | 243 | (远程) 增量备份 |
rdiff-backup | V:7, I:15 | 733 | (远程) 增量备份 |
restic | V:1, I:3 | 20595 | (远程) 增量备份 |
rsnapshot | V:5, I:11 | 462 | (远程) 增量备份 |
slbackup | V:0, I:0 | 151 | (远程) 增量备份 |
备份工具有各自的专用的用途。
Mondo Rescue 是一个备份系统,它能够方便的从备份 CD/DVD 等设备中快速恢复整个系统,而不需要经过常规的系统安装过程。
定期备份用户数据,可以通过一个简单的脚本(第 10.2.2 节 “一个系统备份的脚本例子”)和 cron(8) 来实现。
第 10.1.1 节 “存档和压缩工具” 和 第 10.1.2 节 “复制和同步工具” 描述的基础工具能够通过自定义脚本来帮助系统备份。这些脚本的功能可以通过如下的工具来增强。
restic
软件包能够增量备份(远程)。rdiff-backup
软件包能够增量备份(远程)。dump
软件包用于高效增量的归档和恢复整个文件系统。
提示 | |
---|---|
参见 “ |
10.2.2. 一个系统备份的脚本例子
对于运行 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 权限执行的脚本例子。
我建议你按照如下所示的去更改和执行这个脚本。
编辑这个脚本使其能够覆盖到你所有的重要数据(参见第 10.1.5 节 “查找文件的语法” 和 第 10.2 节 “备份和恢复”)。
用 “
find ...-newer $BUDIR/backup.stamp -print0
“ 替代 “find ...-print0
“ 来实现增量备份。为保险起见,使用 scp(1) 或 rsync(1) 命令来备份文件到远端 或者把它们烧写到 CD/DVD 里。(我使用 GNOME 桌面 GUI 来烧写 CD/DVD。参见 第 12.1.8 节 “zenity 的 shell 脚本案例” 来获得更多的信息。)
把事情简单化!
提示 | |
---|---|
你能够用 “ |
10.2.3. 用于备份数据的复制脚本
对于目录树下面的数据集,”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
如上只是一个范例。在你自己使用脚本之前,请阅读此脚本并且修改它。
提示 | |
---|---|
我把 |
提示 | |
---|---|
如果是要制作源文件树或者配置文件树的快照历史的话,使用 git(7) (参见第 10.6.5 节 “记录配置历史的 Git”) 是更简便并且也是空间高效的。 |
10.3. 数据安全基础
数据安全基础设施是数据加密,讯息摘要和签名工具的结合。
表 10.6. 数据安全基础工具列表
软件包 | 流行度 | 大小 | 命令 | 说明 |
---|---|---|---|---|
gnupg | V:531, I:950 | 787 | gpg(1) | GNU 隐私卫士 - OpenPGP 加密和签名工具 |
gpgv | V:880, I:999 | 859 | gpgv(1) | GNU 隐私卫士 - 签名验证工具 |
paperkey | V:1, I:13 | 58 | paperkey(1) | 从 OpenPGP 私钥里面,仅仅导出私密信息 |
cryptsetup | V:29, I:78 | 402 | cryptsetup(8), … | dm-crypto 块设备加密支持 LUKS 工具 |
ecryptfs-utils | V:3, I:5 | 460 | ecryptfs(7), … | ecryptfs 堆叠文件系统加密工具 |
coreutils | V:891, I:999 | 17478 | md5sum(1) | 计算与校验 MD5 讯息摘要 |
coreutils | V:891, I:999 | 17478 | sha1sum(1) | 计算与校验 SHA1 讯息摘要 |
openssl | V:794, I:993 | 1465 | openssl(1ssl) | 使用 “openssl dgst “ (OpenSSL)计算信息摘要 |
参见 第 9.8 节 “数据加密提示” 的 dm-crypto 和 ecryptfs,它们通过 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 —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 | 最终信任 |
如下命令上传我的 “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
“ 选项.
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-sig 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
“, 和 “.ppg
“的文件可靠的运行 GnuPG.
# aptitude install vim-scripts vim-addon-manager
$ vim-addons install gnupg
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.4. 源代码合并工具
这里有许多源代码合并工具。如下的是我感兴趣的工具。
表 10.10. 源代码合并工具列表
软件包 | 流行度 | 大小 | 命令 | 说明 |
---|---|---|---|---|
diffutils | V:871, I:991 | 1598 | diff(1) | 逐行比较两个文件 |
diffutils | V:871, I:991 | 1598 | diff3(1) | 逐行比较和合并三个文件 |
vim | V:106, I:398 | 3231 | vimdiff(1) | 在 vim 中并排比较两个文件 |
patch | V:99, I:725 | 248 | patch(1) | 给原文件打补丁 |
dpatch | V:0, I:11 | 191 | dpatch(1) | 管理 Debian 软件包的系列补丁 |
diffstat | V:16, I:154 | 73 | diffstat(1) | 通过 diff 生成一个改变柱状图 |
patchutils | V:18, I:150 | 232 | combinediff(1) | 从两个增量补丁创建一个积累补丁 |
patchutils | V:18, I:150 | 232 | dehtmldiff(1) | 从一个 HTML 页面提取出一个 diff |
patchutils | V:18, I:150 | 232 | filterdiff(1) | 从一个 diff 文件里面提取或者排除 diff 文件 |
patchutils | V:18, I:150 | 232 | fixcvsdiff(1) | 修复由 CVS patch(1) 错误创建的 diff 文件 |
patchutils | V:18, I:150 | 232 | flipdiff(1) | 交换两个补丁的顺序 |
patchutils | V:18, I:150 | 232 | grepdiff(1) | 显示哪些文件是由匹配正则表达式的补丁修改 |
patchutils | V:18, I:150 | 232 | interdiff(1) | 显示在两个统一格式 diff 文件(基于同一个文件的两个不同 diff 文件)之间的差异 |
patchutils | V:18, I:150 | 232 | lsdiff(1) | 显示哪些文件由补丁修改 |
patchutils | V:18, I:150 | 232 | recountdiff(1) | 重新计算通用内容 diff 文件的数量和偏移 |
patchutils | V:18, I:150 | 232 | rediff(1) | 修复手工编辑 diff 文件的数量和偏移 |
patchutils | V:18, I:150 | 232 | splitdiff(1) | 隔离出增量补丁 |
patchutils | V:18, I:150 | 232 | unwrapdiff(1) | 识别已经被分词的补丁 |
wiggle | V:0, I:0 | 174 | wiggle(1) | 应用被拒绝的补丁 |
quilt | V:3, I:33 | 788 | quilt(1) | 管理系列补丁 |
meld | V:14, I:39 | 2972 | meld(1) | 比较和移植文件(GTK) |
dirdiff | V:0, I:2 | 166 | dirdiff(1) | 显示目录树之间的不同并移植改变 |
docdiff | V:0, I:0 | 555 | docdiff(1) | 逐词逐字地比较两个文件 |
imediff | V:0, I:0 | 157 | imediff(1) | 全屏交互式两路/三路合并工具 |
makepatch | V:0, I:0 | 102 | makepatch(1) | 生成扩展补丁文件 |
makepatch | V:0, I:0 | 102 | applypatch(1) | 应用扩展补丁文件 |
wdiff | V:9, I:72 | 644 | wdiff(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. 通过三方移植进行更新
如果一个源代码,你有三个版本,你可以通过下面的方式,使用 diff3(1) 高效执行三方移植。
$ diff3 -m file.mine file.old file.yours > file
10.5. 版本控制系统
如下是 Debian 系统上可用的版本控制系统(VCS) 的摘要。
注意 | |
---|---|
如果是刚接触版本控制系统,你应该从 git 入门,git 人气日益高涨。 |
表 10.11. 版本控制系统工具列表
软件包 | 流行度 | 大小 | 工具 | VCS 类型 | 描述 |
---|---|---|---|---|---|
cssc | V:0, I:2 | 2044 | CSSC | 本地 | Unix SCCS (过时)的克隆 |
rcs | V:3, I:19 | 562 | RCS | 本地 | “比 Unix SCCS 做的好” |
cvs | V:5, I:41 | 4609 | CVS | 远程 | 以前的远程 VCS 标准 |
subversion | V:20, I:109 | 4858 | Subversion | 远程 | ”比 CVS 做的好“,远程 VCS 的新标准 |
git | V:305, I:478 | 35040 | Git | 分布式 | 用 C 写的快速 DVCS (被 Linux 内核和其他项目使用) |
mercurial | V:8, I:48 | 1053 | Mercurial | 分布式 | mercurial 主要是用 Python 写的还有一部分是 C 写的 |
bzr | V:2, I:16 | 28 | Bazaar | 分布式 | 受 tla 启发并且是用 Python 写的 DVCS (被 Ubuntu 使用) |
darcs | V:0, I:7 | 23159 | Darcs | 分布式 | 有智能代数补丁的 DVCS(慢) |
tla | V:0, I:2 | 1011 | GNU arch | 分布式 | 主要由 Tom Lord 写的 DVCS (成为历史的) |
monotone | V:0, I:0 | 5815 | Monotone | 分布式 | 用 C++ 写的 DVCS |
tkcvs | V:0, I:1 | 1498 | CVS, … | 远程 | VCS (CVS,Subversion,RCS) 存储库树的图形界面显示 |
gitk | V:6, I:42 | 1723 | Git | 分布式 | VCS (Git) 存储库树的图形界面显示 |
VCS 有时被认为是修订控制系统 (RCS), 或者是软件配置管理程序 (SCM)。
像 Git 这样的分布式 VCS 是现在正在使用的工具。参加那些已经存在的开源软件的开发活动,掌握 CVS 和 Subversion 仍然是有用的。
通过 Debian Salsa 服务,Debian 能够提供免费的 Git 服务。在 https://wiki.debian.org/Salsa 能找到它的说明文档。
小心 | |
---|---|
Debian 已经停止了其旧有的 alioth 服务,旧的 alioth 服务数据可以在 alioth-archive 站点上以 tar 压缩包的形式获取。 |
这里有一些关于创建共享访问 VCS 归档的基础知识。
使用 “
umask 002
“ (参见 第 1.2.4 节 “控制新建文件的权限:umask”)使得所有的 VCS 归档文件属于一个相关的组
能够在所有的 VCS 归档目录设置组 ID(类似 BSD 的文件创建方案,参见第 1.2.3 节 “文件系统权限”)
使得属于这个组的用户能够共享 VCS 归档
10.5.1. VCS 命令的比较
这里有原生 VCS 命令的简单比较来提供大图概要。典型的命令序列需要选项和参数。
表 10.12. 本地 VCS 命令比较
Git | CVS | Subversion | 功能 |
---|---|---|---|
git init | cvs init | svn create | 创建(本地)存储库 |
- | cvs login | - | 登录远程存储库 |
git clone | cvs co | svn co | 签出远程存储库到本地工作目录树 |
git pull | cvs up | svn up | 通过合并远程存储库来更新工作目录树 |
git add . | cvs add | svn add | 把工作目录树中的文件添加到 VCS |
git rm | cvs rm | svn rm | 从 VCS 中移除工作目录树中的文件 |
- | cvs ci | svn ci | 提交改变到远程存储库 |
git commit -a | - | - | 提交改变到本地存储库 |
git push | - | - | 通过本地存储库来更新远程存储库 |
git status | cvs status | svn status | 从 VCS 中显示工作目录树的状态 |
git diff | cvs diff | svn diff | 比较<参考存储库>和<工作目录树>的差异 |
git repack -a -d; git prune | - | - | 重新打包本地仓库到一个单独的包 |
gitk | tkcvs | tkcvs | VCS 存储库树的图形界面显示 |
小心 | |
---|---|
从命令行通过 “ |
提示 | |
---|---|
如果有一个可执行文件 |
提示 | |
---|---|
例如 tkcvs(1) 和 gitk(1) 这样的图形界面工具有助于追踪文件的修改历史。许多公共的归档提供的用于浏览它们的存储库的 web 界面同样是很有用的。 |
提示 | |
---|---|
Git 能够直接在不同的 VCS 仓库上工作,比如说 CVS 和 Subversion 提供的仓库, 通过 |
提示 | |
---|---|
Git 中的有些命令在 CVS 和 Subversion 中并没有对应的命令:”fetch”,”rebase”,”cherry-pick”, … |
10.6. Git
Git 可以用来做本地和远程源代码管理的任何事情。这意味着,你能够在本地记录源代码修改,而不是必须要和远程仓库有网络连接。
10.6.1. 配置 Git 客户端
你可以在 “~/.gitconfig
“ 里面设置几个 Git 接下来需要使用的全局配置,比如说你的名字和电子邮件地址。
$ git config --global user.name "姓名"
$ git config --global user.email 电子邮件地址
如果你习惯使用 CVS 或 Subversion 命令,你也许希望设置如下几个命令别名。
$ git config --global alias.ci "commit -a"
$ git config --global alias.co checkout
你能够通过如下方式检查你的全局配置:
$ git config --global --list
10.6.2. 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/everyday.html
)CVS 用户用 git (
/usr/share/doc/git-doc/gitcvs-migration.html
)- 描述了怎样搭建服务,以及如何把老的数据从 CVS 迁移到 Git。
-
Git 魔术 (
/usr/share/doc/gitmagic/html/index.html
)
git-gui(1) 和 gitk(1) 命令使 Git 变得非常容易使用。
警告 | |
---|---|
不要使用带空格的标签字符串。即使一些工具,如 gitk(1) 允许你使用它,但会阻碍其它 |
10.6.3. Git 命令
即使你的上游使用不同的版本控制系统,使用 git(1) 作为本地活动的版本控制系统,仍然是一个好的主意,因为 git 可以让你在没有上游网络连接的情况下,管理你的本地源代码树拷贝。这里有一些 git(1) 使用的包和命令。
表 10.13. git 相关包和命令列表
软件包 | 流行度 | 大小 | 命令 | 说明 |
---|---|---|---|---|
git-doc | I:15 | 11762 | N/A | Git 官方文档 |
gitmagic | I:1 | 721 | N/A | “Git 魔术”,易于理解的 Git 手册 |
git | V:305, I:478 | 35040 | git(7) | Git 快速、可扩展、分布式的版本控制系统 |
gitk | V:6, I:42 | 1723 | gitk(1) | 有历史功能的 Git 图形仓库浏览器 |
git-gui | V:2, I:24 | 2317 | git-gui(1) | Git 图形界面(无历史功能) |
git-svn | V:1, I:22 | 1144 | git-svnimport(1) | 从 Subversion 导出数据,导入到 Git |
git-svn | V:1, I:22 | 1144 | git-svn(1) | 在 Subversion 和 Git 之间提供双向操作 |
git-cvs | V:0, I:10 | 1279 | git-cvsimport(1) | 从 CVS 导出数据,导入到 Git |
git-cvs | V:0, I:10 | 1279 | git-cvsexportcommit(1) | 从 Git 中检出一个 CVS 的提交 |
git-cvs | V:0, I:10 | 1279 | git-cvsserver(1) | Git 的 CVS 服务模拟器 |
git-email | V:0, I:11 | 966 | git-send-email(1) | 从 Git 用电子邮件发送收集到的补丁 |
stgit | V:0, I:0 | 603 | stg(1) | 封装的 git (Python) |
git-buildpackage | V:2, I:12 | 4193 | git-buildpackage(1) | 用 Git 自动制作 Debian 包 |
guilt | V:0, I:0 | 146 | guilt(7) | 封装的 git (SH/AWK/SED/…) |
提示 | |
---|---|
在 git(1) 下,你在本地分支下进行了许多提交,稍后你可以使用 “ |
提示 | |
---|---|
当你想要回到一个干净的工作目录,并且不丢失工作目录当前的状态,你可以使用 “ |
10.6.4. 用于 Subversion 仓库的 Git
你可以把一个在 “svn+ssh://svn.example.org/project/module/trunk
“ 的 Subversion 仓库检出到一个本地的 Git 仓库,使用”./dest
“目录,并把修改提交回 Subversion 仓库。例如:
$ git svn clone -s -rHEAD svn+ssh://svn.example.org/project dest
$ cd dest
... 进行修改
$ git commit -a
... 继续在本地用 git 工作
$ git svn dcommit
提示 | |
---|---|
使用 “ |
10.6.5. 记录配置历史的 Git
你可以使用 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) 是需要用于配置数据文件,任意文件权限的情况。 对于普通用户的配置数据,你需要省略 |
注意 | |
---|---|
在上面例子里的 “ |
提示 | |
---|---|
要更加完整的建立配置历史记录,请参阅 |
10.7. CVS
CVS 是一个古老的版本控制系统,它的出现早于 Subversion 和 Git。
小心 | |
---|---|
下面例子里给出的 CVS 相关的链接许多已不存在。 |
参见下面内容。
cvs(1)
“
/usr/share/doc/cvs/html-cvsclient
““
/usr/share/doc/cvs/html-info
““
/usr/share/doc/cvsbook
““
info cvs
“
10.7.1. CVS 存储库的配置
如下的配置将只允许 “src
“ 组的成员向 CVS 存储库提交修改 ,只允许 “staff
“ 组的成员管理 CVS,这样可以减少出错的机会。
# cd /var/lib; umask 002; mkdir cvs
# export CVSROOT=/srv/cvs/project
# cd $CVSROOT
# chown root:src .
# chmod 2775 .
# cvs -d $CVSROOT init
# cd CVSROOT
# chown -R root:staff .
# chmod 2775 .
# touch val-tags
# chmod 664 history val-tags
# chown root:src history val-tags
提示 | |
---|---|
你可以改变 “ |
10.7.2. 本地访问 CVS
默认的 CVS 存储库由 “$CVSROOT
“ 指定。如下将建立用于本地访问的 “$CVSROOT
“。
$ export CVSROOT=/srv/cvs/project
10.7.3. 使用 pserver 远程访问 CVS
许多公共 CVS 服务器可以通过 pserver 服务用 “anonymous
“ 账户远程只读访问。例如,Debian 网站的内容曾经使用名为 webwml project 的仓库经由 Debian alioth 服务的 CVS 服务进行维护。如下命令曾被用来建立用于远程访问该旧 CVS 仓库的 “$CVSROOT
“。
$ export CVSROOT=:pserver:anonymous@anonscm.debian.org:/cvs/webwml
$ cvs login
注意 | |
---|---|
因为 pserver 容易被窃听攻击并且是不安全的,所以写访问通常是被服务器管理员禁用的。 |
10.7.4. 使用 ssh 远程访问 CVS
如下所示的命令曾被用来配置“$CVS_RSH
”和“$CVSROOT
”变量,以此实现使用 SSH 远程访问旧的 Debian webwml 项目所使用的 CVS 仓库。
$ export CVS_RSH=ssh
$ export CVSROOT=:ext:account@cvs.alioth.debian.org:/cvs/webwml
你也可以使用 SSH 的公钥认证,这能够去除远程密码提示。
10.7.5. 往 CVS 导入新的源
按如下所示创建 “~/path/to/module1
“ 路径下的新的本地源目录树。
$ mkdir -p ~/path/to/module1; cd ~/path/to/module1
把文件添加到 “~/path/to/module1
“ 下的新的本地源目录树。
使用如下的参数把文件导入到 CVS。
模块名: “
module1
“提供商标签: “
Main-branch
“ (用于整个分支的标签)发布标签: “
Release-initial
“ (用于特定发布版本的标签)
$ cd ~/path/to/module1
$ cvs import -m "Start module1" module1 Main-branch Release-initial
$ rm -Rf . # optional
10.7.6. CVS 存储库中的文件权限
CVS 不会覆盖当前的存储库文件,只是用另外的文件来替代它。因此,存储库目录的写权限是很重要的。存储库位于 “/srv/cvs/project
“ 的 “module1
“,对于其下的每一个新模块而言,如果需要的话运行如下所示的来确保这种情况。
# cd /srv/cvs/project
# chown -R root:src module1
# chmod -R ug+rwX module1
# chmod 2775 module1
10.7.7. CVS 工作流
这里有一个 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
提示 | |
---|---|
使用 “ |
在基于原始版本的有 “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
提示 | |
---|---|
“ |
提示 | |
---|---|
你可以通过形如 “ |
表 10.14. 值得注意的 CVS 命令选项 (用作 cvs(1) 的第一个选项)
选项 | 说明 |
---|---|
-n | 测试,没有影响 |
-t | 显示 cvs 活动步骤的信息 |
10.7.8. CVS 中最新的文件
按如下所示使用 “tomorrow
“ 选项,就能得到 CVS 中的最新文件。
$ cvs ex -D tomorrow module_name
10.7.9. CVS 的管理
按如下所示往 CVS 项目 (本地服务器) 里添加 “mx
“ 模块别名。
$ export CVSROOT=/srv/cvs/project
$ cvs co CVSROOT/modules
$ cd CVSROOT
$ echo "mx -a module1" >>modules
$ cvs ci -m "Now mx is an alias for module1"
$ cvs release -d .
按如下所示,你可以从 CVS 中签出 “module1
“ (别名为: “mx
“) 到 “new
“ 目录。
$ cvs co -d new mx
$ cd new
注意 | |
---|---|
为了执行上述步骤,你应当有合适的文件权限。 |
10.7.10. 用于 CVS 签出时的可执行位
当你从 CVS 中签出文件时,它们的可执行权限是保留的。
当你发现在检出的形如 “filename
“ 这样的文件中,可执行权限有问题时,按如下所示在相应的 CVS 存储库中改变文件的权限来解决这个问题。
# chmod ugo-x filename
10.8. Subversion
Subversion 是在 Git 之前出现的旧的版本控制系统,但它出现在 CVS 之后。它缺少 CVS 和 Git 中的标签和分支功能。
你需要安装 subversion
,libapache2-mod-svn
和 subversion-tools
软件包来搭建 Subversion 服务器。
10.8.1. Subversion 存储库的配置
subversion
软件包通常不会自动建立存储库,所以你必须手动搭建它。存储库可能的位置是在 “/srv/svn/project
“。
按如下所示建立目录。
# mkdir -p /srv/svn/project
按如下所示建立存储库数据库。
# svnadmin create /srv/svn/project
10.8.2. 通过 Apache2 服务器访问 Subversion
如果只是用 Apache2 服务器访问 Subversion 存储库,你只需按如下所示的使存储库只是对于 WWW 服务器是可写的。
# chown -R www-data:www-data /srv/svn/project
在 “/etc/apache2/mods-available/dav_svn.conf
“ 中添加 (或取消注释) 如下所示的来允许通过用户认证访问存储库。
<Location /project>
DAV svn
SVNPath /srv/svn/project
AuthType Basic
AuthName "Subversion repository"
AuthUserFile /etc/subversion/passwd
<LimitExcept GET PROPFIND OPTIONS REPORT>
Require valid-user
</LimitExcept>
</Location>
用如下所示的命令创建用户认证文件。
# htpasswd2 -c /etc/subversion/passwd some-username
重启 Apache2。
通过 “http://localhost/project
“ 和 “http://example.com/project
“ URL 来访问 svn(1) 中的 Subversion 存储库(假设你的 web 服务器的 URL 为 “http://example.com/
“)。
10.8.3. 按组本地访问 Subversion
如下所示将建立用户组,例如 project
,可以本地访问的 Subversion 存储库。
# chmod 2775 /srv/svn/project
# chown -R root:src /srv/svn/project
# chmod -R ug+rwX /srv/svn/project
属于 project
组的本地用户可以访问在 “file:///localhost/srv/svn/project
“ 或 file:///srv/svn/project
“ 下 svn(1) 中的新 Subversion 存储库。你必须在 “umask 002
“ 下运行诸如 svn
, svnserve
, svnlook
和 svnadmin
命令,来确保用户组可以访问。
10.8.4. 通过 SSH 远程访问 Subversion
用户组可以访问的 Subversion 存储库的 URL 为 “example.com:/srv/svn/project
“。至于 SSH 访问,你能够在 svn(1) 中的 “svn+ssh://example.com:/srv/svn/project
“ URL 访问它。
10.8.5. Subversion 目录结构
对于 Subversion 来说,许多项目使用类似如下的目录树来弥补它的分支和标签的不足。
----- module1
| |-- branches
| |-- tags
| | |-- release-1.0
| | `-- release-2.0
| |
| `-- trunk
| |-- file1
| |-- file2
| `-- file3
|
`-- module2
提示 | |
---|---|
你必须使用 “ |
10.8.6. 往 Subversion 里导入一个新的源
按如下所示创建 “~/path/to/module1
“ 路径下的新的本地源目录树。
$ mkdir -p ~/path/to/module1; cd ~/path/to/module1
把文件添加到 “~/path/to/module1
“ 下的新的本地源目录树。
把它导入到 Subversion 的时候带有以下的参数。
模块名: “
module1
“Subversion 位置 URL: “
file:///srv/svn/project
“Subversion 目录: “
module1/trunk
“Subversion 标签: “
module1/tags/Release-initial
“
$ cd ~/path/to/module1
$ svn import file:///srv/svn/project/module1/trunk -m "Start module1"
$ svn cp file:///srv/svn/project/module1/trunk file:///srv/svn/project/module1/tags/Release-initial
或者,如下所示。
$ svn import ~/path/to/module1 file:///srv/svn/project/module1/trunk -m "Start module1"
$ svn cp file:///srv/svn/project/module1/trunk file:///srv/svn/project/module1/tags/Release-initial
提示 | |
---|---|
你能够用像 “ |
10.8.7. Subversion 工作流
这里给出使用 Subversion 及其原生客户端的典型工作流示例。
提示 | |
---|---|
|
查看如下所示的 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
提示 | |
---|---|
使用 “ |
在基于原始版本的 “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
提示 | |
---|---|
你能够用像 “ |
提示 | |
---|---|
通过 “ |
表 10.15. 值得注意的 Subversion 命令选项 (使用时作为 svn(1) 的第一个参数)
选项 | 说明 |
---|---|
—dry-run | 测试,没有影响 |
-v | 显示 svn 活动的详细信息 |