文件的可移植性

优质
小牛编辑
117浏览
2023-12-01

对于经常需要在不同的操作系统中工作的用户来说, 比较幸运的一点是 Subversion 命令行工具在所有系统中的表现几乎都是相同的, 如果用户已经知道 了如何在一种系统中使用 svn, 那他也就知道了如何在其他 系统中使用 svn.

然而, 其他软件或存放在 Subversion 仓库里的文件并不都是这样. 比如说 在一台 Windows 机器上, 对于 “文本文件” 的定义和 Linux 机器 类似, 除了一点—标记一行结束的字符序列不同. 除此之外, Unix 平台 (和 Subversion) 支持符号链接, 而 Windows 不支持; Unix 平台根据文件系统权限 来判断文件的可执行性, 而 Windows 是根据文件的扩展名.

Subversion 并不想把整个世界都统一到公共的定义和实现上, 当用户要在多 种不同的操作系统中管理文件与目录时, 它所能做的只是尽量减少用户的麻烦. 本节介绍 Subversion 如何帮助用户在多种不同的平台中使用 Subversion.

文件内容类型

和许多应用程序一样, Subversion 也会使用 MIME (多用途互联网邮件扩展 类型, Multipurpose Internet Mail Extensions) 内容类型. 属性 svn:mime-type 除了可以作为文件内容类型的存放位置, 它的值还决定了 Subversion 的某些行为特征.

识别文件类型

很多程序都会根据文件的名字—尤其是扩展名—对文件内容 的类型和格式作出一些假定, 比如说文件名以 .txt 结 尾的文件通常被认为是人类可读的, 也就是说用户可以通过简单的阅读来理解 文件的内容, 而不需要经过复杂的译解过程. 另一方面, 文件名以 .png 结尾的文件通常会被当作可移植网络图像 (Portable Network Graphics, PNG) 格式—它们不是人类可读的类型, 只有理解 PNG 格式的软件才能把文件内容以适当的形式展现出来.

不幸的是, 有些扩展名的意义会随着时间而发生变化. 当个人计算机首次出 现时, 如果有一个名为 README.DOC 的文件, 那就几乎可 以确定它是个纯文本文件, 就像现在的 .txt 文件, 但是 在 90 年代中期, 同样名字的文件很可能是一个 Microsoft Word 文档, 它采用 了一种私有的, 人类不可读的文件格式. 不过这种变化并非一蹴而就—曾经 有一段时间, 当计算机用户看到一个 .DOC 文件时, 常常 想不清楚文件的格式到底是什么类型.[18]

计算机网络在文件名与文件类型的关系上更加疑惑. 信息跨网络地传输, 并且由服务器端的脚本动态生成, 本质上不能算作真正的文件, 也就不存在 文件名. 比如说, 网页服务器需要通过其他途径告诉浏览器它们正在下载的 文件是什么类型, 这样的话针对文件, 浏览器可以采取更加智能的做法, 比 如用一个对应的程序打开文件, 或提示用户应该把下载的文件放到哪个目录 下.

最终总算有一个描述数据流内容的标准出现了. 1996 年, RFC 2045 发布, 它是描述 MIME 的 5 篇 RFC 文档的第一篇. 文档介绍的概念包括 媒体类型及其子类型, 并推荐了一种表示这些类型的语法. 如今, MIME 媒体 类型—或 “MIME 类型”—被广泛地应用在邮件程序, 网页服务器等软件中, 作为一种解决文件内容格式混乱的事实标准.

比如说, Subversion 提供的一项特性是在更新工作副本时, 支持基于行 的文件内容合并, 但是二进制文件没有 “行” 的概念, 于是, 如果文件的 svn:mime-type 属性被设置成非文本 MIME 类型 (非文本的 MIME 类型通常不以 text/ 开始, 但是也有 例外), Subversion 就不会对文件执行合并操作. 作为替代, 如果被更新的二 进制文件含有本地修改, 那文件就不会被更新, Subversion 会另外创建两个 新的文件, 其中一个的扩展名是 .oldrev, 对应文件的 BASE 版本号; 另一个的扩展名是 .newrev, 对应更新 后的版本号. 这样做是为了避免对不支持合并的文件进行合并而带来的错误.

另外, 为了能够以行为单位显示修改, 文件必须能被划分成 “行”, 如果 svn diffsvn annotate 的目标文件的 MIME 类型是非文本的, 这 两个命令默认会报错. 如果用户的文件是 XML 文件, 它们的 svn:mime-type 被设置成 application/xml, 虽然它们是人类可读的文本文件, 但 Subversion 仍然会把它们看成是非文本 文件, 幸好, 为命令添加选项 --force 可以强制 Subversion 不管文件的 MIME 类型, 直接执行操作.

[警告]警告

如果属性 svn:mime-type 的值不能说明文件内容 是文本的, 这将会给其他属性造成意想不到的影响. 例如, 二进制文件没有 行的概念, 所以 Subversion 不允许为二进制文件设置属性 svn:eol-style. 如果命令的目标是单一的文件, 那么就很 容易看出来—svn propset 会报错退出, 但是, 如果用户递归地执行属性设置命令, 可能就没那么明显了: 如果 Subversion 觉得某个文件不适合设置给定的属性, 它就会悄无声息地跳过该文件.

Subversion 提供了多种机制, 用于自动地设置属性 svn:mime-type, 详细的介绍见 “自动属性设置”一节.

另外, 如果文件设置了属性 svn:mime-type, 响应 GET 请求时, Subversion Apache 模块将会使用属性的值填充 HTTP 头部的 Content-type 字段. 如果用户使用浏览器查看仓库的内容, 这可以提示浏览器应该如何显示文件.

文件的可执行性

在很多操作系统里, 一个文件是否可以执行取决于该文件是否设置了 可执行权限位. 该位默认是不开启的, 如果用户需要可执行权限, 必须显式地 开启它. 但是记住应该为哪些检出的文件设置可执行位是一件很麻烦的事情, 所以 Subversion 提供了属性 svn:executable, 如果文件 设置了该属性, Subversion 就会在工作副本里打开文件的可执行位.

该属性对不支持可执行位的文件系统是没有效果的, 比如 FAT32 和 NTFS. [19] 另外, 尽管该属性 没有预定义的值, 在设置属性时, Subversion 强制把它的值设置为 *. 最后, 该属性只对文件有效, 对目录不起作用.

行结束标记

除非属性 svn:mime-type 进行了额外说明, 否则 Subversion 总是假设文件的内容是人类可读的. 一般来说, Subversion 会根据 自己的知识来判断是否可以对文件进行基于上下文的差异比较, 如果不能的话, 就 按字节比较差异.

Subversion 默认情况下并不关心文件的 行结束 (EOL) 标记 (end-of-line (EOL) markers ) 类型. 不幸的是, 如何结束一行, 不同的操作系统有着不同的约 定. 比如说, Windows 软件使用一对 ASCII 控制字符表示一行的结束— 一个回车符 (CR) 后面再跟一个换行符 (LF); 而 Unix 系统中的软件只用单一的换行符 (LF) 表示一行的结束.

如果文件的行结束标记与操作系统的 本地的行结束风格 不同, 有些软件可能无法正确地处理这种文件. 所以在典型情况 下, Unix 程序把来自 Windows 的文件里的回车符 (CR) 当 成一个普通字符 (通常显示成 ^M), 而 Windows 程序会 把来自 Unix 系统的文件显示成一段很长的行, 因为它们找不到用来结束一行 的回车符 (CR).

如果用户要在不同的操作系统之间分享文件, 如此敏感的 EOL 标记可不 是什么好事. 比如说有一个源代码文件, 开发人员可能会同时在 Unix 和 Windows 系统中编辑它, 如果所有开发人员使用的工具都能保留文件原来的行 结束风格, 那就不会产生什么问题.

可惜的是, 如果文件的行结束标记和本地不同, 很多程序要么不能正确地读 取并显示文件, 要么在保存时, 把文件的行结束标记转换成本地风格. 如果是前 一种情况, 开发人员在开始编辑文件之前, 需要使用一种格式转换工具 (比如 dos2unix 及其伙伴 unix2dos) 把 文件的行结束标记转换成本地风格. 如果是后一种情况就不用在编辑之前转换文件 格式. 但是两种情况都会导致文件的每一行都发生变化! 在提交修改之前, 用户 有两种选择, 一是使用格式转换工具把文件的行结束标记转换成与原来一样的 风格, 二是直接提交—使用新的行结束标记.

这种情况的结果是既浪费了时间, 也提交了很多没必要的修改. 浪费时间 已经足够烦人了, 更糟糕的是一次提交修改了文件的每一行, 这会给后面的历史 查询带来很大的麻烦—是哪几行修改解决了问题, 或者是哪一行修改引入 了语法错误.

问题的解决办法是使用属性 svn:eol-style. 如果属 性的值是有效的, Subversion 将根据属性值对文件进行特殊的处理, 这样文件 的行结束风格就不会随着操作系统的变化而变化. 属性的有效值包括:

native

文件的行结束标记是操作系统的本地风格, 换句话说, 如果一个用户 在 Windows 操作系统上检出了工作副本, 文件的 svn:eol-style 被设置成 native, 则文件将使用 CRLF 作为行结束标记. 而 Unix 用户 检出的文件的行结束标记是 LF.

注意, 不管操作系统是什么类型, Subversion 仓库中存放的文件 的行结束标记总是 LF, 这对用户来说是透明的.

CRLF

无论是什么操作系统, 文件总是使用 CRLF 作为行结束标记.

LF

无论是什么操作系统, 文件总是使用 LF 作为 行结束标记.

CR

无论是什么操作系统, 文件总是使用 CR 作为行结束标记. 这种行结束标记用得很少.



[18] 雪上加霜的是, 当时还 有一款叫作 WordPerfect 的软件也使用 .DOC 作为他们的私有文件格式的扩展名!

[19] Windows 的文件系统使用文件的扩展名 (比如 .EXE, .BAT.COM) 表示文件是可执行的.