目录
描述了在 Debian 系统上管理二进制和文本数据的工具和技巧。
数据安全及其受控共享具有多个方面。
数据归档的创建
远程存储访问
复制
修改历史的跟踪
促进数据共享
防止未经授权的文件访问
检测未经授权的文件修改
这些可以通过使用一些工具组合来实现。
归档和压缩工具
复制和同步工具
网络文件系统
可移动存储介质
安全 shell
身份验证系统
版本控制系统工具
哈希和加密工具
以下是在 Debian 系统上可用的归档和压缩工具的摘要。
表 10.1. 归档和压缩工具列表
![]() |
警告 |
---|---|
除非您知道会发生什么,否则不要设置“ |
![]() |
注意 |
---|---|
gzip 压缩的 tar(1) 归档文件使用文件扩展名“ |
![]() |
注意 |
---|---|
xz 压缩的 tar(1) 归档文件使用文件扩展名“ |
![]() |
注意 |
---|---|
在 FOSS 工具(例如 tar(1))中流行的压缩方法一直在如下发展: |
![]() |
注意 |
---|---|
cp(1)、scp(1) 和 tar(1) 对于特殊文件可能有一些限制。cpio(1) 是最通用的。 |
![]() |
注意 |
---|---|
cpio(1) 设计为与 find(1) 和其他命令一起使用,并且适用于创建备份脚本,因为脚本的文件选择部分可以独立测试。 |
![]() |
注意 |
---|---|
OpenOffice 数据文件的内部结构是“ |
以下是在 Debian 系统上可用的简单复制和备份工具的摘要。
表 10.2. 复制和同步工具列表
软件包 | popcon | 大小 | 工具 | 功能 |
---|---|---|---|---|
coreutils
|
http://qa.debian.org/popcon.php?package=coreutils | 14088 | GNU cp | 本地复制文件和目录(“-a”表示递归) |
openssh-client
|
http://qa.debian.org/popcon.php?package=openssh-client | 2246 | scp | 远程复制文件和目录(客户端,“-r ”表示递归) |
openssh-server
|
http://qa.debian.org/popcon.php?package=openssh-server | 701 | sshd | 远程复制文件和目录(远程服务器) |
rsync
|
http://qa.debian.org/popcon.php?package=rsync | 724 | - | 单向远程同步和备份 |
unison
|
http://qa.debian.org/popcon.php?package=unison | 1987 | - | 双向远程同步和备份 |
使用 rsync(8) 复制文件比其他工具提供更丰富的功能。
增量传输算法,仅发送源文件和目标位置现有文件之间的差异
快速检查算法(默认),查找大小或上次修改时间已更改的文件
类似于 tar(1) 的“--exclude
”和“--exclude-from
”选项
“源目录上的尾部斜杠”语法,避免在目标位置创建额外的目录级别。
![]() |
提示 |
---|---|
在 cron(8) 下使用“ |
![]() |
提示 |
---|---|
表 10.15 “版本控制系统工具列表”中的版本控制系统 (VCS) 工具可以用作多向复制和同步工具。 |
以下是使用不同工具归档和解归档目录“./source
”的整个内容的几种方法。
GNU tar(1)
$ tar cvzf archive.tar.gz ./source $ tar xvzf archive.tar.gz
cpio(1):
$ find ./source -xdev -print0 | cpio -ov --null > archive.cpio; gzip archive.cpio $ zcat archive.cpio.gz | cpio -i
以下是使用不同工具复制目录“./source
”的整个内容的几种方法。
本地复制:“./source
”目录 → “/dest
”目录
远程复制:本地主机上的“./source
”目录 → “user@host.dom
”主机上的 “/dest
”目录
rsync(8):
# cd ./source; rsync -av . /dest # cd ./source; rsync -av . user@host.dom:/dest
您可以选择使用“源目录上的尾部斜杠”语法。
# rsync -av ./source/ /dest # rsync -av ./source/ 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)
“/path/to/source/foo
”:GNU tar(1) 和 cpio(1)
![]() |
提示 |
---|---|
rsync(8) 和 GNU cp(1) 具有 “ |
find(1) 用于为归档和复制命令选择文件(请参阅第 10.1.3 节“归档的惯用法”和第 10.1.4 节“复制的惯用法”)或用于 xargs(1)(请参阅第 9.5.9 节“重复命令循环处理文件”)。这可以通过使用其命令参数来增强。
find(1) 的基本语法可以概括如下。
其条件参数从左到右求值。
一旦确定其结果,此求值就会停止。
“逻辑或”(由条件之间的“-o
”指定)的优先级低于“逻辑与”(由条件之间的“-a
”或无任何内容指定)。
“逻辑非”(由条件之前的“!
”指定)的优先级高于“逻辑与”。
“-prune
”始终返回逻辑真,并且如果它是一个目录,则文件搜索将在此点之后停止。
“-name
”将文件名的基本名称与 shell glob 匹配(请参阅第 1.5.6 节“Shell glob”),但它也将其初始 “.
” 与元字符(例如 “*
” 和 “?
”)匹配。(新的 POSIX 功能)
“-regex
”将完整路径与 emacs 风格的 BRE 匹配(默认情况下,请参阅第 1.6.2 节“正则表达式”)。
“-size
”根据文件大小匹配文件(对于较大的文件,值以 “+
” 开头;对于较小的文件,值以 “-
” 开头)
“-newer
”匹配比其参数中指定的文件更新的文件。
“-print0
”始终返回逻辑真,并在标准输出上打印完整文件名(空字符结尾)。
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
” 正则表达式匹配的目录
通过停止处理,从搜索中排除大于 99 兆字节(单位为 1048576 字节)的文件
打印满足上述搜索条件且比 “/path/to/timestamp
” 新的文件名
请注意在上面的示例中排除文件时惯用的使用 “-prune -o
”。
![]() |
注意 |
---|---|
对于非 Debian 类 Unix 系统,某些选项可能不受 find(1) 支持。在这种情况下,请考虑调整匹配方法,并将 “ |
我们都知道计算机有时会发生故障,或者人为错误会导致系统和数据损坏。备份和恢复操作是成功系统管理的重要组成部分。所有可能的故障模式总有一天会发生在你身上。
![]() |
提示 |
---|---|
保持备份系统简单,并经常备份系统。拥有备份数据比你的备份方法在技术上有多好更重要。 |
有 3 个关键因素决定了实际的备份和恢复策略。
了解要备份和恢复的内容。
您直接创建的数据文件: “~/
” 中的数据
您使用的应用程序创建的数据文件: “/var/
” 中的数据(“/var/cache/
”、“/var/run/
” 和 “/var/tmp/
” 除外)
系统配置文件: “/etc/
” 中的数据
本地软件: “/usr/local/
” 或 “/opt/
” 中的数据
系统安装信息:关于关键步骤(分区,…)的纯文本备忘录
经过验证的数据集:通过预先的实验性恢复操作确认
了解如何备份和恢复。
数据的安全存储:防止覆盖和系统故障
频繁备份:计划备份
冗余备份:数据镜像
傻瓜式流程:简单的单命令备份
评估涉及的风险和成本。
数据丢失时的价值
备份所需的资源:人力、硬件、软件、…
故障模式及其可能性
关于数据的安全存储,数据应至少位于不同的磁盘分区上,最好位于不同的磁盘和机器上,以承受文件系统损坏。重要数据最好存储在一次写入介质(如 CD/DVD-R)上,以防止意外覆盖。(有关如何从 shell 命令行写入存储介质,请参阅第 10.3 节“二进制数据”。GNOME 桌面 GUI 环境使您可以通过菜单轻松访问:“位置→CD/DVD 创建器”。)
![]() |
注意 |
---|---|
您可能希望在备份数据时停止某些应用程序守护进程,例如 MTA(请参阅第 6.3 节“邮件传输代理 (MTA)”)。 |
![]() |
注意 |
---|---|
您应该特别注意身份相关数据文件(例如 “ |
![]() |
注意 |
---|---|
如果您以用户进程身份运行 cron 作业,则必须恢复 “ |
以下是 Debian 系统上可用的著名备份实用程序套件的选择列表。
表 10.3. 备份套件实用程序列表
备份工具各有其专注点。
Mondo Rescue 是一个备份系统,旨在促进从备份 CD/DVD 等快速恢复完整系统,而无需经过正常的系统安装过程。
sbackup
和 keep
软件包为桌面用户提供了简单的 GUI 前端,用于定期备份用户数据。可以通过一个简单的脚本(第 10.1.8 节“系统备份的示例脚本”)和 cron(8) 来实现等效功能。
在第 10.1.1 节“归档和压缩工具”和第 10.1.2 节“复制和同步工具”中描述的基本工具可以用于通过自定义脚本来促进系统备份。可以通过以下方式增强此类脚本。
rdiff-backup
软件包启用(远程)增量备份。
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 执行的脚本示例。
我希望您按如下方式更改和执行此脚本。
编辑此脚本以涵盖所有重要数据(请参阅第 10.1.5 节“文件选择的惯用法”和第 10.1.6 节“备份和恢复”)。
将 “find … -print0
” 替换为 “find … -newer $BUDIR/backup.stamp -print0
” 以进行增量备份。
使用 scp(1) 或 rsync(1) 将备份文件传输到远程主机,或将它们刻录到 CD/DVD 以获得额外的数据安全性。(我使用 GNOME 桌面 GUI 刻录 CD/DVD。有关额外的冗余,请参阅第 12.1.8 节“使用 zenity 的 Shell 脚本示例”。)
保持简单!
![]() |
提示 |
---|---|
您可以使用“ |
对于目录树下的一组数据,使用“cp -a
”进行复制即可提供常规备份。
对于目录树下的大型非覆盖静态数据集合,例如“/var/cache/apt/packages/
”目录下的数据,使用“cp -al
”进行硬链接复制可以替代常规备份,并有效利用磁盘空间。
这是一个用于数据备份的复制脚本,我将其命名为 bkup
。此脚本将当前目录下的所有(非 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 -rlpt ./ "${HOST}:${EXTP}-${BKUP}-${TIME}" else echo "Any other idea to backup?" $FIND |xargs -0 -n 1 echo fi
这仅为命令示例。请在使用前阅读并自行编辑脚本。
![]() |
提示 |
---|---|
我将此 |
![]() |
提示 |
---|---|
为了制作源文件树或配置文件树的快照历史记录,使用 git(7) (参见 第 10.9.5 节,“使用 Git 记录配置历史”) 更容易且节省空间。 |
可移动存储设备可以是以下任何一种。
它们可以通过以下任何一种方式连接。
现代桌面环境(如 GNOME 和 KDE)可以自动挂载这些可移动设备,而无需匹配的“/etc/fstab
”条目。
![]() |
提示 |
---|---|
自动挂载的设备可能具有 “ |
![]() |
提示 |
---|---|
仅当这些可移动媒体设备未在“ |
现代桌面环境下的挂载点被选择为 “/media/<disk_label>
”,可以通过以下方式自定义。
mlabel(1) 用于 FAT 文件系统
genisoimage(1) 带有 “-V
” 选项用于 ISO9660 文件系统
tune2fs(1) 带有 “-L
” 选项用于 ext2/ext3/ext4 文件系统
![]() |
提示 |
---|---|
编码的选择可能需要作为挂载选项提供(参见 第 8.3.6 节,“文件名编码”)。 |
当通过可移动存储设备与其他系统共享数据时,您应该使用通用 文件系统,该文件系统应被两个系统都支持。以下是文件系统选择列表。
表 10.4. 可移动存储设备的文件系统选择列表及典型使用场景
文件系统 | 典型使用场景描述 |
---|---|
FAT12 | 软盘上的数据跨平台共享(<32MiB) |
FAT16 | 小型硬盘类设备上的数据跨平台共享(<2GiB) |
FAT32 | 大型硬盘类设备上的数据跨平台共享(<8TiB,由 MS Windows95 OSR2 及更高版本支持) |
NTFS | 大型硬盘类设备上的数据跨平台共享(在 MS Windows NT 及更高版本上原生支持,并通过 NTFS-3G 在 Linux 上通过 FUSE 支持) |
ISO9660 | CD-R 和 DVD+/-R 上的静态数据跨平台共享 |
UDF | CD-R 和 DVD+/-R 上的增量数据写入(新) |
MINIX 文件系统 | 软盘上节省空间的 Unix 文件数据存储 |
ext2 文件系统 | 与较旧的 Linux 系统共享硬盘类设备上的数据 |
ext3 文件系统 | 与较旧的 Linux 系统共享硬盘类设备上的数据 |
ext4 文件系统 | 与当前的 Linux 系统共享硬盘类设备上的数据 |
![]() |
提示 |
---|---|
有关使用设备级加密进行跨平台数据共享的信息,请参见 第 9.4.1 节,“使用 dm-crypt/LUKS 进行可移动磁盘加密”。 |
FAT 文件系统几乎被所有现代操作系统支持,并且对于通过可移动硬盘类介质进行数据交换非常有用。
当为跨平台数据共享使用 FAT 文件系统格式化可移动硬盘类设备时,以下应该是安全的选择。
使用 fdisk(8)、cfdisk(8) 或 parted(8) (参见 第 9.3.2 节,“磁盘分区配置”) 将它们分区为单个主分区,并将其标记为以下类型。
对于小于 2GB 的介质,类型为 “6” 表示 FAT16。
对于更大的介质,类型为 “c” 表示 FAT32 (LBA)。
使用 mkfs.vfat(8) 格式化主分区,使用以下命令。
仅使用其设备名称,例如 “/dev/sda1
” 用于 FAT16
显式选项及其设备名称,例如 “-F 32 /dev/sda1
” 用于 FAT32
当使用 FAT 或 ISO9660 文件系统共享数据时,以下应该是安全考虑事项。
首先使用 tar(1) 或 cpio(1) 将文件存档到存档文件中,以保留长文件名、符号链接、原始 Unix 文件权限和所有者信息。
使用 split(1) 命令将存档文件拆分为小于 2 GiB 的块,以防止文件大小限制。
加密存档文件以保护其内容免受未经授权的访问。
![]() |
注意 |
---|---|
根据 FAT 文件系统的设计,最大文件大小为 |
![]() |
注意 |
---|---|
Microsoft 本身不建议对超过 200 MB 的驱动器或分区使用 FAT。Microsoft 在其 “FAT、HPFS 和 NTFS 文件系统概述” 中强调了其缺点,例如磁盘空间利用率低。当然,对于 Linux,我们通常应该使用 ext4 文件系统。 |
![]() |
提示 |
---|---|
有关文件系统和访问文件系统的更多信息,请阅读 “文件系统 HOWTO”。 |
当通过网络与其他系统共享数据时,您应该使用通用服务。以下是一些提示。
表 10.5. 网络服务选择列表及典型使用场景
网络服务 | 典型使用场景描述 |
---|---|
SMB/CIFS 网络挂载文件系统,使用 Samba | 通过 “Microsoft Windows 网络” 共享文件,参见 smb.conf(5) 和 The Official Samba 3.2.x HOWTO and Reference Guide 或 samba-doc 软件包 |
NFS 网络挂载文件系统,使用 Linux 内核 | 通过 “Unix/Linux 网络” 共享文件,参见 exports(5) 和 Linux NFS-HOWTO |
HTTP 服务 | 在 Web 服务器/客户端之间共享文件 |
HTTPS 服务 | 在 Web 服务器/客户端之间共享文件,使用加密的安全套接字层 (SSL) 或 传输层安全 (TLS) |
FTP 服务 | 在 FTP 服务器/客户端之间共享文件 |
虽然这些通过网络挂载的文件系统和通过网络的文件传输方法对于共享数据非常方便,但它们可能不安全。它们的网络连接必须通过以下方式保护。
当为重要数据存档选择 计算机数据存储介质 时,您应该注意它们的局限性。对于小型个人数据备份,我使用品牌公司的 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 和纸张只有 1 次写入周期,因此它们本质上可以防止因覆盖而意外丢失数据。这是一个优点! |
![]() |
提示 |
---|---|
如果您需要快速且频繁地备份大量数据,则连接快速网络的远程主机上的硬盘可能是唯一现实的选择。 |
在这里,我们讨论磁盘镜像的操作。也请参见 第 9.3 节,“数据存储技巧”。
可以使用 cp(1) 或 dd(1) 通过以下方式制作未挂载设备的磁盘镜像文件 “disk.img
”,例如,第二个 SCSI 驱动器 “/dev/sdb
”。
# cp /dev/sdb disk.img # dd if=/dev/sdb of=disk.img
传统 PC 的 主引导记录 (MBR) 的磁盘镜像 (参见 第 9.3.2 节,“磁盘分区配置”) 位于主 IDE 磁盘的第一个扇区,可以使用 dd(1) 通过以下方式制作。
# dd if=/dev/hda of=mbr.img bs=512 count=1 # dd if=/dev/hda of=mbr-nopart.img bs=446 count=1 # dd if=/dev/hda of=mbr-part.img skip=446 bs=1 count=66
“mbr.img
”:带有分区表 MBR
“mbr-nopart.img
”:不带分区表的 MBR
“part.img
”:仅 MBR 的分区表
如果您的引导磁盘是 SCSI 设备(包括新的串行 ATA 驱动器),请将 “/dev/hda
” 替换为 “/dev/sda
”。
如果您正在制作原始磁盘的磁盘分区的镜像,请将 “/dev/hda
” 替换为 “/dev/hda1
” 等。
磁盘镜像文件 “disk.img
” 可以写入到大小匹配的未挂载设备,例如,第二个 SCSI 驱动器 “/dev/sdb
”,通过以下方式。
# dd if=disk.img of=/dev/sdb
类似地,磁盘分区镜像文件 “partition.img
” 可以写入到大小匹配的未挂载分区,例如,第二个 SCSI 驱动器的第一个分区 “/dev/sdb1
”,通过以下方式。
# dd if=partition.img of=/dev/sdb1
可以使用 loop 设备 挂载和卸载包含单个分区镜像的磁盘镜像 “partition.img
”,如下所示。
# losetup -v -f partition.img Loop device is /dev/loop0 # mkdir -p /mnt/loop0 # mount -t auto /dev/loop0 /mnt/loop0 ...hack...hack...hack # umount /dev/loop0 # losetup -d /dev/loop0
可以简化为如下所示。
# mkdir -p /mnt/loop0 # mount -t auto -o loop partition.img /mnt/loop0 ...hack...hack...hack # umount partition.img
可以使用 loop 设备 挂载包含多个分区的磁盘镜像 “disk.img
” 的每个分区。由于 loop 设备默认情况下不管理分区,我们需要如下所示重置它。
# modinfo -p loop # verify kernel capability max_part:Maximum number of partitions per loop device max_loop:Maximum number of loop devices # losetup -a # verify nothing using the loop device # rmmod loop # modprobe loop max_part=16
现在,loop 设备可以管理最多 16 个分区。
# losetup -v -f disk.img Loop device is /dev/loop0 # fdisk -l /dev/loop0 Disk /dev/loop0: 5368 MB, 5368709120 bytes 255 heads, 63 sectors/track, 652 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Disk identifier: 0x452b6464 Device Boot Start End Blocks Id System /dev/loop0p1 1 600 4819468+ 83 Linux /dev/loop0p2 601 652 417690 83 Linux # mkdir -p /mnt/loop0p1 # mount -t ext3 /dev/loop0p1 /mnt/loop0p1 # mkdir -p /mnt/loop0p2 # mount -t ext3 /dev/loop0p2 /mnt/loop0p2 ...hack...hack...hack # umount /dev/loop0p1 # umount /dev/loop0p2 # losetup -d /dev/loop0
或者,可以使用由 kpartx
软件包中的 kpartx(8) 创建的 设备映射器 设备来实现类似的效果,如下所示。
# kpartx -a -v disk.img ... # mkdir -p /mnt/loop0p2 # mount -t ext3 /dev/mapper/loop0p2 /mnt/loop0p2 ... ...hack...hack...hack # umount /dev/mapper/loop0p2 ... # kpartx -d /mnt/loop0
可以通过以下方式将磁盘镜像文件 “disk.img
” 中所有已删除的文件清理为干净的稀疏镜像 “new.img
”。
# mkdir old; mkdir new # mount -t auto -o loop disk.img old # dd bs=1 count=0 if=/dev/zero of=new.img seek=5G # mount -t auto -o loop new.img new # cd old # cp -a --sparse=always ./ ../new/ # cd .. # umount new.img # umount disk.img
如果 “disk.img
” 是 ext2 或 ext3 格式,您也可以使用 zerofree
软件包中的 zerofree(8),如下所示。
# losetup -f -v disk.img Loop device is /dev/loop3 # zerofree /dev/loop3 # cp --sparse=always disk.img new.img
可以使用 dd(1) 制作可以增长到 5GiB 的空磁盘镜像 “disk.img
”,如下所示。
$ dd bs=1 count=0 if=/dev/zero of=disk.img seek=5G
您可以使用 loop 设备 在此磁盘镜像 “disk.img
” 上创建 ext3 文件系统,如下所示。
# losetup -f -v disk.img Loop device is /dev/loop1 # mkfs.ext3 /dev/loop1 ...hack...hack...hack # losetup -d /dev/loop1 $ du --apparent-size -h disk.img 5.0G disk.img $ du -h disk.img 83M disk.img
对于 “disk.img
”,其文件大小为 5.0 GiB,而实际磁盘使用量仅为 83MiB。这种差异是可能的,因为 ext2fs 可以容纳 稀疏文件。
![]() |
提示 |
---|---|
稀疏文件 的实际磁盘使用量会随着写入其中的数据而增长。 |
使用与 第 10.2.3 节,“挂载磁盘镜像文件” 中相同的操作,在由 loop 设备 或 设备映射器 设备创建的设备上,您可以使用 parted(8) 或 fdisk(8) 对此磁盘镜像 “disk.img
” 进行分区,并可以使用 mkfs.ext3(8)、mkswap(8) 等在上面创建文件系统。
可以使用 cdrkit 提供的 genisoimage(1) 从 “source_directory
” 的源目录树制作 ISO9660 镜像文件 “cd.iso
”,如下所示。
# genisoimage -r -J -T -V volume_id -o cd.iso source_directory
类似地,可以使用以下命令从 “source_directory
” 中类似 debian-installer
的目录树制作可引导的 ISO9660 镜像文件 “cdboot.iso
”。
# genisoimage -r -o cdboot.iso -V volume_id \ -b isolinux/isolinux.bin -c isolinux/boot.cat \ -no-emul-boot -boot-load-size 4 -boot-info-table source_directory
这里使用 Isolinux 引导加载程序(参见 第 3.3 节,“阶段 2:引导加载程序”)进行引导。
您可以计算 md5sum 值并直接从 CD-ROM 设备制作 ISO9660 镜像,如下所示。
$ isoinfo -d -i /dev/cdrom CD-ROM is in ISO 9660 format ... Logical block size is: 2048 Volume size is: 23150592 ... # dd if=/dev/cdrom bs=2048 count=23150592 conv=notrunc,noerror | md5sum # dd if=/dev/cdrom bs=2048 count=23150592 conv=notrunc,noerror > cd.iso
![]() |
警告 |
---|---|
您必须小心避免 Linux 的 ISO9660 文件系统预读错误,如上所述,以获得正确的结果。 |
![]() |
提示 |
---|---|
对于 cdrkit 提供的 wodim(1) 来说,DVD 只是一个更大的 CD。 |
您可以通过以下方式找到可用的设备。
# wodim --devices
然后将空白 CD-R 插入 CD 驱动器,并使用 wodim(1) 将 ISO9660 镜像文件 “cd.iso
” 写入此设备,例如 “/dev/hda
”,如下所示。
# wodim -v -eject dev=/dev/hda cd.iso
如果使用 CD-RW 而不是 CD-R,请改为执行以下操作。
# wodim -v -eject blank=fast dev=/dev/hda cd.iso
![]() |
提示 |
---|---|
如果您的桌面系统自动挂载 CD,请在使用 wodim(1) 之前使用 “ |
如果 “cd.iso
” 包含 ISO9660 镜像,则以下命令手动将其挂载到 “/cdrom
”。
# mount -t iso9660 -o ro,loop cd.iso /cdrom
![]() |
提示 |
---|---|
现代桌面系统会自动挂载可移动媒体(参见 第 10.1.10 节,“可移动存储设备”)。 |
在这里,我们讨论直接操作存储介质上的二进制数据。也请参见 第 9.3 节,“数据存储技巧”。
最基本的二进制数据查看方法是使用 “od -t x1
” 命令。
表 10.6. 查看和编辑二进制数据的软件包列表
软件包 | popcon | 大小 | 描述 |
---|---|---|---|
coreutils
|
http://qa.debian.org/popcon.php?package=coreutils | 14088 | 基本软件包,具有 od(1) 来转储文件(HEX、ASCII、OCTAL、…) |
bsdmainutils
|
http://qa.debian.org/popcon.php?package=bsdmainutils | 558 | 实用程序软件包,具有 hd(1) 来转储文件(HEX、ASCII、OCTAL、…) |
hexedit
|
http://qa.debian.org/popcon.php?package=hexedit | 108 | 二进制编辑器和查看器(HEX、ASCII) |
bless
|
http://qa.debian.org/popcon.php?package=bless | 991 | 功能齐全的十六进制编辑器 (GNOME) |
okteta
|
http://qa.debian.org/popcon.php?package=okteta | 295 | 功能齐全的十六进制编辑器 (KDE4) |
ncurses-hexedit
|
http://qa.debian.org/popcon.php?package=ncurses-hexedit | 192 | 二进制编辑器和查看器(HEX、ASCII、EBCDIC) |
beav
|
http://qa.debian.org/popcon.php?package=beav | 164 | 二进制编辑器和查看器(HEX、ASCII、EBCDIC、OCTAL、…) |
![]() |
提示 |
---|---|
HEX 用作 十六进制 格式的缩写,基数 为 16。OCTAL 用于 八进制 格式,基数 为 8。ASCII 用于 美国信息交换标准代码,即,普通英语文本代码。EBCDIC 用于 扩展二进制编码的十进制交换码,用于 IBM 大型机 操作系统。 |
有一些工具可以在不挂载磁盘的情况下读取和写入文件。
表 10.7. 在不挂载磁盘的情况下操作文件的软件包列表
软件包 | popcon | 大小 | 描述 |
---|---|---|---|
mtools
|
http://qa.debian.org/popcon.php?package=mtools | 408 | 用于 MSDOS 文件的实用程序,无需挂载它们 |
hfsutils
|
http://qa.debian.org/popcon.php?package=hfsutils | 236 | 用于 HFS 和 HFS+ 文件的实用程序,无需挂载它们 |
Linux 内核提供的软件 RAID 系统在内核文件系统级别提供数据冗余,以实现高水平的存储可靠性。
也有一些工具可以在应用程序级别向文件添加数据冗余,以实现高水平的存储可靠性。
表 10.8. 向文件添加数据冗余的工具列表
软件包 | popcon | 大小 | 描述 |
---|---|---|---|
par2
|
http://qa.debian.org/popcon.php?package=par2 | 272 | 奇偶校验存档卷集,用于检查和修复文件 |
dvdisaster
|
http://qa.debian.org/popcon.php?package=dvdisaster | 1481 | CD/DVD 介质的数据丢失/划痕/老化保护 |
dvbackup
|
http://qa.debian.org/popcon.php?package=dvbackup | 392 | 使用 MiniDV 摄像机的备份工具(提供 rsbep(1)) |
vdmfec
|
http://qa.debian.org/popcon.php?package=vdmfec | 88 | 使用前向纠错恢复丢失的块 |
有一些用于数据文件恢复和取证分析的工具。
表 10.9. 数据文件恢复和取证分析的软件包列表
当数据太大而无法作为单个文件备份时,您可以将其内容拆分为例如 2000MiB 的块进行备份,并在以后将这些块合并回原始文件。
$ split -b 2000m large_file $ cat x* >large_file
![]() |
注意 |
---|---|
请确保您没有任何以 “ |
为了清除文件(例如日志文件)的内容,请不要使用 rm(1) 删除文件,然后再创建一个新的空文件,因为文件可能在命令之间的间隔内仍然被访问。以下是清除文件内容的安全方法。
$ :>file_to_be_cleared
以下命令创建虚拟文件或空文件。
$ dd if=/dev/zero of=5kb.file bs=1k count=5 $ dd if=/dev/urandom of=7mb.file bs=1M count=7 $ touch zero.file $ : > alwayszero.file
您应该找到以下文件。
“5kb.file
” 是 5KB 的零数据。
“7mb.file
” 是 7MB 的随机数据。
“zero.file
” 可能是 0 字节文件。如果它存在,则其 mtime
会被更新,而其内容和长度保持不变。
“alwayszero.file
” 始终是 0 字节文件。如果它存在,则其 mtime
会被更新,并且其内容会被重置。
有几种方法可以从整个硬盘类设备(例如,位于 “/dev/sda
” 的 USB 记忆棒)上完全擦除数据。
![]() |
注意 |
---|---|
在执行此处的命令之前,请先使用 mount(8) 检查您的 USB 记忆棒位置。“ |
通过将数据重置为 0 来擦除所有磁盘内容,使用以下命令。
# dd if=/dev/zero of=/dev/sda
通过覆盖随机数据来擦除所有内容,使用以下命令。
# dd if=/dev/urandom of=/dev/sda
通过非常有效地覆盖随机数据来擦除所有内容,使用以下命令。
# shred -v -n 1 /dev/sda
由于 dd(1) 可以从许多可引导的 Linux CD(例如 Debian 安装程序 CD)的 shell 中获得,因此您可以通过在此类介质上对系统硬盘(例如 “/dev/hda
”、“/dev/sda
” 等)运行擦除命令来完全擦除已安装的系统。
硬盘(或 USB 记忆棒)上的未使用区域,例如 “/dev/sdb1
”,可能仍然包含已擦除的数据本身,因为它们仅从文件系统中取消链接。可以通过覆盖它们来清理这些数据。
# mount -t auto /dev/sdb1 /mnt/foo # cd /mnt/foo # dd if=/dev/zero of=junk dd: writing to `junk': No space left on device ... # sync # umount /dev/sdb1
![]() |
警告 |
---|---|
对于您的 USB 记忆棒来说,这通常已经足够好了。但这并不完美。已擦除的文件名及其属性的大部分可能被隐藏并保留在文件系统中。 |
即使您意外删除了文件,只要该文件仍被某些应用程序(读或写模式)使用,就可以恢复此类文件。
例如,尝试以下操作
$ echo foo > bar $ less bar $ ps aux | grep ' less[ ]' bozo 4775 0.0 0.0 92200 884 pts/8 S+ 00:18 0:00 less bar $ rm bar $ ls -l /proc/4775/fd | grep bar lr-x------ 1 bozo bozo 64 2008-05-09 00:19 4 -> /home/bozo/bar (deleted) $ cat /proc/4775/fd/4 >bar $ ls -l -rw-r--r-- 1 bozo bozo 4 2008-05-09 00:25 bar $ cat bar foo
在另一个终端上执行(当您安装了 lsof
软件包时),如下所示。
$ ls -li bar 2228329 -rw-r--r-- 1 bozo bozo 4 2008-05-11 11:02 bar $ lsof |grep bar|grep less less 4775 bozo 4r REG 8,3 4 2228329 /home/bozo/bar $ rm bar $ lsof |grep bar|grep less less 4775 bozo 4r REG 8,3 4 2228329 /home/bozo/bar (deleted) $ cat /proc/4775/fd/4 >bar $ ls -li bar 2228302 -rw-r--r-- 1 bozo bozo 4 2008-05-11 11:05 bar $ cat bar foo
可以使用 “ls -li
” 识别带有硬链接的文件。
$ ls -li total 0 2738405 -rw-r--r-- 1 root root 0 2008-09-15 20:21 bar 2738404 -rw-r--r-- 2 root root 0 2008-09-15 20:21 baz 2738404 -rw-r--r-- 2 root root 0 2008-09-15 20:21 foo
“baz
” 和 “foo
” 的链接计数均为 “2” (>1),表明它们具有硬链接。它们的 inode 号码是相同的 “2738404”。这意味着它们是同一个硬链接文件。如果您碰巧没有找到所有硬链接文件,则可以按 inode(例如 “2738404”)进行搜索,如下所示。
# find /path/to/mount/point -xdev -inum 2738404
数据安全基础设施由数据加密工具、消息摘要工具和签名工具的组合提供。
表 10.10. 数据安全基础设施工具列表
命令 | 软件包 | popcon | 大小 | 描述 |
---|---|---|---|---|
gpg(1) |
gnupg
|
http://qa.debian.org/popcon.php?package=gnupg | 4621 | GNU Privacy Guard - OpenPGP 加密和签名工具 |
N/A |
gnupg-doc
|
http://qa.debian.org/popcon.php?package=gnupg-doc | 4124 | GNU Privacy Guard 文档 |
gpgv(1) |
gpgv
|
http://qa.debian.org/popcon.php?package=gpgv | 397 | GNU Privacy Guard - 签名验证工具 |
paperkey(1) |
paperkey
|
http://qa.debian.org/popcon.php?package=paperkey | 88 | 仅从 OpenPGP 密钥中提取秘密信息 |
cryptsetup(8), … |
cryptsetup
|
http://qa.debian.org/popcon.php?package=cryptsetup | 648 | 用于 dm-crypto 块设备加密的实用程序,支持 LUKS |
ecryptfs(7), … |
ecryptfs-utils
|
http://qa.debian.org/popcon.php?package=ecryptfs-utils | 368 | 用于 ecryptfs 堆叠文件系统加密的实用程序 |
md5sum(1) |
coreutils
|
http://qa.debian.org/popcon.php?package=coreutils | 14088 | 计算和检查 MD5 消息摘要 |
sha1sum(1) |
coreutils
|
http://qa.debian.org/popcon.php?package=coreutils | 14088 | 计算和检查 SHA1 消息摘要 |
openssl(1ssl) |
openssl
|
http://qa.debian.org/popcon.php?package=openssl | 1079 | 使用 "openssl dgst " (OpenSSL) 计算消息摘要 |
请参阅关于 dm-crypto 和 ecryptfs 的第 9.4 节,“数据加密技巧”,它们通过 Linux 内核模块实现自动数据加密基础设施。
以下是 GNU Privacy Guard 用于基本密钥管理的命令。
表 10.11. 用于密钥管理的 GNU Privacy Guard 命令列表
命令 | 描述 |
---|---|
gpg --gen-key
|
生成新密钥 |
gpg --gen-revoke my_user_ID
|
为 my_user_ID 生成吊销密钥 |
gpg --edit-key user_ID
|
交互式编辑密钥,"help" 获取帮助 |
gpg -o file --exports
|
将所有密钥导出到文件 |
gpg --imports 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
|
更新本地密钥环 |
以下是信任代码的含义。
以下命令将我的密钥 "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 Public Key Server (0.9.6 版本之前) 中存在一个错误,该错误会损坏包含超过 2 个子密钥的密钥。较新的 gnupg
(>1.2.1-2) 软件包可以处理这些损坏的子密钥。请参阅 gpg(1) 中的 "--repair-pks-subkey-bug
" 选项。
以下是在文件上使用 GNU Privacy Guard 命令的示例。
表 10.13. 在文件上使用 GNU Privacy Guard 命令列表
命令 | 描述 |
---|---|
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
|
公钥加密,目标接收者为 name,从文件加密到二进制 crypt_file.gpg |
gpg -o crypt_file.gpg --recipient name --encrypt file
|
, , |
gpg -o crypt_file.asc -a -r name -e file
|
公钥加密,目标接收者为 name,从文件加密到 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
|
对称加密,目标接收者为 name,从文件加密到 ASCII 文本 crypt_file.asc |
gpg -o file -d crypt_file.gpg -r name
|
解密 |
gpg -o file --decrypt crypt_file.gpg
|
, , |
将以下内容添加到 "~/.muttrc
" 以防止缓慢的 GnuPG 自动启动,同时允许通过在索引菜单中键入 "S
" 来使用它。
macro index S ":toggle pgp_verify_sig\n" set pgp_verify_sig=no
gnupg
插件允许您透明地为扩展名为 ".gpg
"、".asc
" 和 ".ppg
" 的文件运行 GnuPG。
# aptitude install vim-scripts vim-addon-manager $ vim-addons install gnupg
md5sum(1) 提供了实用程序,可以使用 rfc1321 中的方法制作摘要文件,并使用它验证每个文件。
$ md5sum foo bar >baz.md5 $ cat baz.md5 d3b07384d113edec49eaa6238ad5ff00 foo c157a79031e1c40f85931829bc5fc552 bar $ md5sum -c baz.md5 foo: OK bar: OK
![]() |
注意 |
---|---|
与 GNU Privacy Guard (GnuPG) 的加密签名相比,MD5 校验和的计算 CPU 密集程度较低。通常,只有顶层摘要文件会进行加密签名以确保数据完整性。 |
有许多用于源代码的合并工具。以下命令引起了我的注意。
表 10.14. 源代码合并工具列表
以下过程之一提取两个源文件之间的差异,并根据文件位置创建统一的 diff 文件 "file.patch0
" 或 "file.patch1
"。
$ diff -u file.old file.new > file.patch0 $ diff -u old/file new/file > file.patch1
diff 文件(也称为补丁文件)用于发送程序更新。接收方通过以下方式将此更新应用于另一个文件。
$ patch -p0 file < file.patch0 $ patch -p1 file < file.patch1
以下是 Debian 系统上 版本控制系统 (VCS) 的摘要。
![]() |
注意 |
---|---|
如果您是 VCS 系统的新手,则应从学习 Git 开始,它正迅速普及。 |
表 10.15. 版本控制系统工具列表
VCS 有时被称为版本控制系统 (RCS) 或软件配置管理 (SCM)。
像 Git 这样的分布式 VCS 是当今的首选工具。CVS 和 Subversion 对于加入一些现有的开源程序活动可能仍然有用。
Debian 通过 Debian Alioth 服务 提供免费的 VCS 服务。它实际上支持所有 VCS。其文档可以在 http://wiki.debian.org/Alioth 找到。
创建共享访问 VCS 归档文件有一些基本知识。
使用 "umask 002
" (参见关于 第 1.2.4 节,“控制新创建文件的权限:umask”)
使所有 VCS 归档文件属于相关的组
在所有 VCS 归档目录上启用设置组 ID(类似 BSD 的文件创建方案,参见关于 第 1.2.3 节,“文件系统权限”)
使共享 VCS 归档的用户属于该组
这是一个简化的本机 VCS 命令比较,以提供总体概况。典型的命令序列可能需要选项和参数。
表 10.16. 本机 VCS 命令的比较
CVS | Subversion | Git | 功能 |
---|---|---|---|
cvs init
|
svn create
|
git init
|
创建(本地)存储库 |
cvs login
|
- | - | 登录到远程存储库 |
cvs co
|
svn co
|
git clone
|
将远程存储库检出为工作树 |
cvs up
|
svn up
|
git pull
|
通过合并远程存储库来更新工作树 |
cvs add
|
svn add
|
git add .
|
将工作树中的文件添加到 VCS |
cvs rm
|
svn rm
|
git rm
|
从 VCS 中删除工作树中的文件 |
cvs ci
|
svn ci
|
- | 将更改提交到远程存储库 |
- | - |
git commit -a
|
将更改提交到本地存储库 |
- | - |
git push
|
通过本地存储库更新远程存储库 |
cvs status
|
svn status
|
git status
|
从 VCS 显示工作树状态 |
cvs diff
|
svn diff
|
git diff
|
diff <reference_repository> <working_tree> |
- | - |
git repack -a -d; git prune
|
将本地存储库重新打包到单个包中 |
tkcvs
|
tkcvs
|
gitk
|
VCS 存储库树的 GUI 显示 |
![]() |
注意 |
---|---|
从命令行直接调用 |
![]() |
提示 |
---|---|
诸如 tkcvs(1) 和 gitk(1) 之类的 GUI 工具确实可以帮助您跟踪文件的修订历史记录。许多公共归档文件为其存储库提供的 Web 界面也非常有用。 |
![]() |
提示 |
---|---|
Git 可以直接与不同的 VCS 存储库(例如 CVS 和 Subversion 提供的存储库)一起工作,并通过 |
![]() |
提示 |
---|---|
Git 有一些 CVS 和 Subversion 中没有等效命令的命令:“fetch”、“rebase”、“cherry-pick”,… |
请参阅以下内容。
cvs(1)
“/usr/share/doc/cvs/html-cvsclient
”
“/usr/share/doc/cvs/html-info
”
“/usr/share/doc/cvsbook
”
“info 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
![]() |
提示 |
---|---|
您可以通过将 " |
许多公共 CVS 服务器通过 pserver 服务使用帐户名 "anonymous
" 提供对它们的只读远程访问。例如,Debian 网站内容由 webwml 项目 通过 Debian alioth 服务上的 CVS 维护。以下为远程访问此 CVS 存储库设置 "$CVSROOT
"。
$ export CVSROOT=:pserver:anonymous@cvs.alioth.debian.org:/cvsroot/webwml $ cvs login
![]() |
注意 |
---|---|
由于 pserver 容易受到窃听攻击且不安全,因此服务器管理员通常禁用写入访问。 |
以下为通过 SSH 远程访问 webwml 项目 的 CVS 存储库设置 "$CVS_RSH
" 和 "$CVSROOT
"。
$ export CVS_RSH=ssh $ export CVSROOT=:ext:account@cvs.alioth.debian.org:/cvs/webwml
您还可以对 SSH 使用公钥身份验证,这消除了远程密码提示。
通过以下方式在 "~/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
CVS 不会覆盖当前的存储库文件,而是用另一个文件替换它。因此,对存储库目录的写入权限至关重要。对于 "/srv/cvs/project
" 存储库中 "module1
" 的每个新模块,如果需要,请运行以下命令以确保此条件。
# cd /srv/cvs/project # chown -R root:src module1 # chmod -R ug+rwX module1 # chmod 2775 module1
以下是使用 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"
通过以下方式将发布标签 "Release-1
" 重新添加到已更新的 CVS main HEAD。
$ 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"
通过以下方式更新本地树(内容 = main HEAD),同时删除粘性标签 ("-A
") 且不进行关键字扩展 ("-kk
")。
$ cvs up -d -kk -A
通过以下方式,通过从 "Release-initial-bugfixes
" 分支合并来更新本地树(内容 = main HEAD)且不进行关键字扩展。
$ 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
![]() |
提示 |
---|---|
“ |
![]() |
提示 |
---|---|
您可以通过提供子目录的名称作为 " |
通过以下方式将模块别名 "mx
" 添加到 CVS 项目(本地服务器)。
$ 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 .
现在,您可以通过以下方式将 "module1
"(别名: "mx
")从 CVS 检出到 "new
" 目录。
$ cvs co -d new mx $ cd new
![]() |
注意 |
---|---|
为了执行上述过程,您应该具有适当的文件权限。 |
Subversion 是取代旧 CVS 的新一代版本控制系统。它具有 CVS 的大多数功能,除了标签和分支。
您需要安装 subversion
、libapache2-svn
和 subversion-tools
软件包以设置 Subversion 服务器。
目前,subversion
软件包未设置存储库,因此必须手动设置。存储库的一个可能位置是 "/srv/svn/project
"。
通过以下方式创建目录。
# mkdir -p /srv/svn/project
通过以下方式创建存储库数据库。
# svnadmin create /srv/svn/project
如果您仅通过 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。
您的新 Subversion 存储库可通过 URL "http://localhost/project
" 和 "http://example.com/project
" 从 svn(1) 访问(假设您的 Web 服务器 URL 为 "http://example.com/
")。
以下为通过组(例如 project
)本地访问设置 Subversion 存储库。
# chmod 2775 /srv/svn/project # chown -R root:src /srv/svn/project # chmod -R ug+rwX /srv/svn/project
对于属于 project
组的本地用户,您的新 Subversion 存储库可通过 URL "file:///localhost/srv/svn/project
" 或 "file:///srv/svn/project
" 从 svn(1) 进行组访问。您必须在 "umask 002
" 下运行诸如 svn
、svnserve
、svnlook
和 svnadmin
之类的命令,以确保组访问。
对于 SSH,组可访问的 Subversion 存储库位于 URL "example.com:/srv/svn/project
",您可以从 svn(1) 以 URL "svn+ssh://example.com:/srv/svn/project
" 访问它。
许多项目使用类似于以下的目录树用于 Subversion,以弥补其缺少分支和标签的不足。
----- module1 | |-- branches | |-- tags | | |-- release-1.0 | | `-- release-2.0 | | | `-- trunk | |-- file1 | |-- file2 | `-- file3 | `-- module2
![]() |
提示 |
---|---|
您必须使用 " |
通过以下方式在 "~/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
![]() |
提示 |
---|---|
您可以将诸如 " |
以下是使用 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"
通过以下方式从已更新的 trunk 的 Subversion HEAD 重新添加发布标签 "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"
通过以下方式使用 trunk 的 HEAD 更新本地树。
$ svn switch file:///srv/svn/project/module1/trunk
通过以下方式,通过从 "Release-initial-bugfixes
" 分支合并来更新本地树(内容 = trunk 的 HEAD)。
$ 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
![]() |
提示 |
---|---|
您可以将诸如 " |
![]() |
提示 |
---|---|
您可以通过提供子目录的名称作为 " |
Git 可以为本地和远程源代码管理做所有事情。这意味着您无需连接到远程仓库的网络即可记录源代码更改。
您可能希望在“~/.gitconfig
”中设置几个全局配置,例如您的姓名和 Git 使用的电子邮件地址,如下所示。
$ git config --global user.name "Name Surname" $ git config --global user.email yourname@example.com
如果您太习惯 CVS 或 Subversion 命令,您可能希望通过以下方式设置几个命令别名。
$ git config --global alias.ci "commit -a" $ git config --global alias.co checkout
您可以通过以下方式检查您的全局配置。
$ git config --global --list
请参阅以下内容。
手册页: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 这样的服务器以及如何从 CVS 中提取旧数据到 Git 中。
Git Magic (/usr/share/doc/gitmagic/html/index.html
)
git-gui(1) 和 gitk(1) 命令使 Git 的使用非常容易。
![]() |
警告 |
---|---|
即使某些工具(如 gitk(1))允许您使用,也不要在标签字符串中使用空格。它可能会使其他一些 |
即使您的上游使用不同的 VCS,为本地活动使用 git(1) 也可能是一个好主意,因为您可以在没有连接到上游的网络的情况下管理本地源代码树副本。以下是一些与 git(1) 一起使用的软件包和命令。
表 10.19. git 相关软件包和命令列表
![]() |
提示 |
---|---|
使用 git(1),您可以在本地分支上进行许多提交的工作,并使用类似“ |
![]() |
提示 |
---|---|
当您想要返回到干净的工作目录而又不丢失工作目录的当前状态时,可以使用“ |
您可以将 Subversion 仓库“svn+ssh://svn.example.org/project/module/trunk
”检出到本地 Git 仓库“./dest
”,然后提交回 Subversion 仓库。例如:
$ git svn clone -s -rHEAD svn+ssh://svn.example.org/project dest $ cd dest ... make changes $ git commit -a ... keep working locally with git $ git svn dcommit
![]() |
提示 |
---|---|
使用“ |
您可以使用 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) 才能处理配置数据的任何文件权限。对于用户配置数据,您可以跳过 |
![]() |
注意 |
---|---|
上述示例中的“ |
![]() |
提示 |
---|---|
有关记录配置历史记录的更完整设置,请查找 |