#
之所以稱為正規(guī)(normal)格式輸出是因?yàn)檫@種格式只顯示有差別的行,不會(huì)混入任何相同的行.它稱為默認(rèn)得輸出格式的原因是為了遵守POSIX標(biāo)準(zhǔn).正規(guī)格式很少用于發(fā)布軟件補(bǔ)丁,但以此為基礎(chǔ)對(duì)理解任何一種diff的輸出格式很有用處.一般來說,正規(guī)塊(normal
hunk)的格式如下: change_command <srcfile line <srcfile
line ... >dstfile line >dstfile
line change_command的格式如下:首先是一個(gè)來自srcfile的行號(hào)或以逗號(hào)隔開的行號(hào)范圍,然后是一個(gè)命令符,接下來是一個(gè)來自dstfile的行號(hào)或以逗號(hào)隔開的行號(hào)范圍.的命令符可以為: .a--添加 .b--刪除 .c--更改
并排(side-by-side)格式雖然對(duì)于創(chuàng)建源代碼補(bǔ)丁來說沒有什么用處,但是用它直接比較源代碼文件比較容易,因?yàn)樗裺rcfile和dstfile的內(nèi)容并排顯示在屏幕上. ivan@debian $diff -y -W 80 hello.c howdy.c #include
<stdio.h> #include
<stdio.h> > #include
<stdlib.h> int main(void) int
main(void) { { char msg[] = "Hello,
Linux pr | char msg[] = "Hello, Linux
pr puts(msg); printf("Here
you are, using d | printf("Here you are, using d
return
0; | exit(EXIT_SUCCESS); }
字符">"表示該行在dstfile而不在srcfile里.類型地,字符"<"表示該行在srcfile而不在dstfile里.字符"|"標(biāo)記出兩個(gè)文件不相同的行.
以前曾提到過,在發(fā)布軟件補(bǔ)丁時(shí)很少(可能從不)使用正規(guī)和并排的塊格式.但diff產(chǎn)生的上下文(context)或統(tǒng)一(unified)的塊格式是創(chuàng)建補(bǔ)丁所采用的格式.為了產(chǎn)生上下文的差異文件(它們稱為context
diff的原因是它們顯示出了有差別的行的上下文內(nèi)容),可使用diff的-c或-C[num]選項(xiàng). 提示:和大多數(shù)GNU程序一樣,diff也支持長(zhǎng)選項(xiàng),也就是以兩個(gè)兩字符"--"開頭,后面跟著更容易記憶的名字的選項(xiàng),例如,創(chuàng)建一個(gè)上下文diff文件的長(zhǎng)選項(xiàng)是"--context=[num]".
上下文輸出舉例 $diff
-c hello.c howdy.c *** hello.c Web Aug 9 21:02:42 2000 --- howdy.c Web Aug
9 21:04:30 2000 ************* *** 1,12 **** #include
<stdio.h> int main(void) { ! char msg[ ] = "Hello,
Linux programmer!"; puts(msg); ! printf("Here you are,
using diff.\n");
! return 0; } --- 1,13 --- #include
<stdio.h> + #include <stdlib.h>
int
main(void) { ! char msg[] = "Hello, Linux programmer, from
howdy.c!"); puts(msg); ! printf("howdy.c says, `Here you are,
using diff.`\n"); !
exit(EXIT_SUCCESS); } $
上下文塊的格式采用以下一般形式: *** srcfile
srcfile_timestamp --- dstfile
dstfile_timestamp **************** *** srcfile_line_range
*** srcfile line --- dstfile line_line_range dstfile
line dstfile line...
. + -----向srcfile添加一行以創(chuàng)建dstfile . -
-----從srcfile刪除一行以創(chuàng)建dstfile . !
-----在srcfile改變一行以創(chuàng)建dstfile.srcfile中標(biāo)記"!"的每一行或一段,在dstfile中相應(yīng)的每一行或一段也標(biāo)記"!".
每一塊(hunk)都用一長(zhǎng)串最多15個(gè)星號(hào)和下一塊(hunk)分隔開來.
統(tǒng)一格式是對(duì)上下文格式的修改版本,它不顯示重復(fù)的上下文而且還用其他辦法壓縮輸出內(nèi)容.統(tǒng)一格式以下面的開頭來標(biāo)識(shí)要比較大文件: --- srcfile
srcfile_timestamp 其后是一個(gè)或多個(gè)塊(hunk),格式如下: @@ srcfile_range
dstfile_range
@@ line_from_either_file line_from_either_file 以@@開頭的每一行都標(biāo)志一個(gè)塊的開始.在塊中,上下文行以空格開頭,而有差別的行以"+"或"-"開頭,以表示相對(duì)于srcfile在此位置上添加或刪除一行. 命令diff
-u hello.c howdy.c產(chǎn)生的輸出如下: ---hello.c Web Aug 9 21:02:42
2000 +++howdy.c Web Aug 9 21:04:30 2000 @@ -1,12 +1,13
@@ #include <stdio.h> +#include
<stdlib.h>
int main(void) { - char msg [] =
"Hello,Linux programmer!"; + char msg [] = "Hello,Linux programmer,
from howdy.c!"; puts(msg); - printf("Here you are,
using diff.\n"); + printf("howdy.c says, `Here you are, using
diff.`\n"); - return 0; +
exit(EXIT_SUCCESS); } 對(duì)這一輸出進(jìn)行翻譯,用語言來描述怎么把hello.c轉(zhuǎn)變成howdy.c: .緊挨著#include
<stdio.h>一行之后加入#include <stdlib.h> .緊挨著前半個(gè)大括號(hào)之后,刪除 char
msg[] = "Hello, Linux Programmer!"; 并加入 char msg[] = "Hello, Linux
Programmer, from howdy.c!"; .緊挨著puts(msg);之后,刪除 printf("Here you
are, using diff.\n"); 并加入 printf("howdy.c says, 'Here you are,
using diff.'\n"); .緊挨著最后一個(gè)空行之后,刪除 return
0; 并加入 exit(EXIT_SUCCESS); 雖然統(tǒng)一格式既緊湊又容易閱讀,但是統(tǒng)一格式的差異文件卻有一個(gè)缺點(diǎn):目前,只有GNU
diff能產(chǎn)生統(tǒng)一格式的差異文件而且只有GNU
patch能理解統(tǒng)一格式.
要判別兩個(gè)二進(jìn)制文件的差異,只需把它們的名字作為參數(shù)傳遞給diff: $diff hello
howdy Binary files hello and howdy
differ 如果要顯示有差別的行,則使用-a選項(xiàng).但是需注意這樣做會(huì)輸出重定向到一個(gè)文件: $diff -a hello howdy >
diffs Files hello.c and howdy.c
differ 要查看兩個(gè)文本文件是否不同但又不顯示差異之處,可以使用diff的-q選項(xiàng): $diff -q hello.c
howdy.c Files hello.c and howdy.c differ
假如你想忽略某種差別.實(shí)現(xiàn)這個(gè)目的的做法是使用-I
regexp選項(xiàng). $diff -u -I include hello.c howdy.c --- hello.c Web Aug
9 21:02:42 2000 +++ howdy.c Web Aug 9 21:04:30 2000 @@ -2,11 +3,11
@@
int main(void) { - char msg[ ] = "Hello. Linux
programmer!"; + char msg[ ] = "Hello. Linux programmer, from
howdy.c!";
puts(msg); - printf("Here you are,
using diff.\n"); + printf("howdy.c says, `Here you are, using
diff.\n'"; - return
0; + exit(EXIT_SUCCESS); } 上面的例子使用了-I
regexp來忽略"include"的行.
另一組有用的diff命令行選項(xiàng)能改變它對(duì)空白的處理方式.-b選項(xiàng)讓diff忽略輸入文件中空白數(shù)量的變化;-B讓diff忽略刪除或插入空行的改動(dòng);-w在逐行比較時(shí)忽略空白的變化.-b和-w的區(qū)別在哪里?-b忽略的是輸入文件之間空白數(shù)量上的變化,而-w則忽略在原本沒有空白的地方添加的空白.
注:而2路hunk則在"===="后加上1,2或3來指出引起不同的那個(gè)文件.
$diff3 sigrot.2 sigrot.1
sigrot.3 產(chǎn)生如下的輸出(在這里因?yàn)榭臻g的原因?qū)敵鲎隽私財(cái)?: ==== 1:3c #Version
2.0 2:3c #Version 1.0 3:3c #Version
3.0 ====1 1:9,10c srcdir=$HOME/doc/signatures srcfile=$srcdir/$sigfile 2:8a 3:8a ====1 1:12c old=$(cat $srcdir/num) 2:10c 3:10c old=$(cat
num) ... 第一個(gè)hunk是3路hunk,其他的都是2路hunk.從sigrot.1或sigrot.3中生成sigrot.2時(shí),必須把從sigrot.2中來的下面兩行添加到sigrot.1或sigrot.3的第8行后: srcdir=$HOME/doc/signatures srcfile=$srcdir/$sigfile 類似地,若要依據(jù)sigrot.2來生成sigrot.1,必須把sigrot.1的第10行改為sigrot.2中來的第12行.
可以使用-m或--merge選項(xiàng)來告訴diff3對(duì)文件進(jìn)行合并,然后再手工對(duì)結(jié)果排序: $diff3
-m sigrot.2 sigrot.1 sigrot.3 > sigrot.merged
程序清單6.7
使用diff3合并選項(xiàng)產(chǎn)生的輸出 #!/usr/local/bin/bash #sigrot.sh <<<<<<<
sigrot.2 #Version 2.0 |||||||sigrot.1 #Version
1.0 ======= #Version 3.0 >>>>>>>
sigrot.3 #Rotate signatures #Suitable to be run via
cron ############################
sigfile=signature srcdir=$HOME/doc/signatures srcfile=$srcdir/$srcfile
old=$(cat $srcdir/num) let new=$(expr $old+1)
if [ -f $srcfile.$new ];
then cp $srcfile.$new $HOME/.$sigfile echo $new > $srcdir
/num else cp $srcfile.1 $HOME/.$sigfile echo 1 > $srcdir
/num fi
return
0
"<<<<<<<"標(biāo)記對(duì)應(yīng)myfile,">>>>>>>"對(duì)應(yīng)yourfile,"|||||||"對(duì)應(yīng)oldfile.在本例中,只需要最新的版本號(hào),為了成功合并3個(gè)版本,將刪除標(biāo)記行和1.0及2.0版本指定的行.
當(dāng)兩個(gè)人同時(shí)修改一個(gè)公用文件時(shí),diff3就會(huì)發(fā)揮作用.它比較兩個(gè)人做出的兩套修改內(nèi)容,創(chuàng)建第3個(gè)文件保存并后的輸出結(jié)果,并且指出雙方修改的沖突之處.diff3的語法是: diff
[options] myfile oldfile
yourfile oldfile是派生出myfile和yourfile的共同源文件. 程序清單6.4
sigrot.1 #!/bin/bash #sigrot.sh #Version 1.0 #Rotate
signatures #Suitable to be run via
cron ############################ sigfile=signature old=$(cat
num) let new=$(expr $old+1)
if [ -f $sigfile.$new ];
then cp $sigfile.$new .$sigfile echo $new >
num else cp $sigfile.1 .$sigfile echo 1 >
num fi
程序清單6.5
sigrot.2 #!/bin/bash #sigrot.sh #Version 2.0 #Rotate
signatures #Suitable to be run via
cron ############################
sigfile=signature srcdir=$HOME/doc/signatures srcfile=$srcdir/$sigfile old=$(cat $srcdir/num) let new=$(expr $old+1)
if [ -f $srcfile.$new ];
then cp $srcfile.$new $HOME/.$sigfile echo $new > $srcdir/num else cp $srcfile.1 $HOME/.$sigfile echo 1
> $srcdir/num fi
程序清單6.6
sigrot.3 #!/bin/bash #sigrot.sh #Version 3.0 #Rotate
signatures #Suitable to be run via
cron ############################
sigfile=signature old=$(cat
num) let new=$(expr $old+1)
if [ -f $sigfile.$new ];
then cp $sigfile.$new .$sigfile echo $new >
num else cp $sigfile.1 .$sigfile echo 1 >
num fi return
0;
diff3在列舉hunk的同時(shí)給出了生成這些hunk所需的一個(gè)或多個(gè)命令(仍舊使用ed形式).這些命令如下: .file:la 該hunk出現(xiàn)在第1行后,但在file中不存在這個(gè)hunk,所以如果要依據(jù)file生成其他文件,必須加入在第1行后這個(gè)hunk. .file:rc 該hunk由file的中第r行組成,因此在生成其他文件時(shí)必須對(duì)該行進(jìn)行指定的修改.
patch選項(xiàng) 選項(xiàng) 含義 -c 把輸入的補(bǔ)丁文件看作是上下文格式的差異文件 -d
dir 把dir設(shè)置為解釋補(bǔ)丁文件名的當(dāng)前目錄 -e 把輸入的補(bǔ)丁文件看作時(shí)ed腳本 -F
num|
--fuzz=NUM 把非精確匹配的fuzz因子設(shè)置為NUM行 -l 把不同的空字符序列視為相同 -n 把輸入的補(bǔ)丁文件看作是正規(guī)格式的差異文件 -pnum|
--strip=NUM 剝離文件名中的前NUM個(gè)目錄成分 -R 假定在生成補(bǔ)丁的命令中交換了老文件和新文件的次序 -s 除非方式錯(cuò)誤,否則保持緘默 -t 執(zhí)行過程中不要求任何輸入 -u 把輸入的補(bǔ)丁文件看作是統(tǒng)一格式的差異文件 -v 顯示patch的版本信息并退出
當(dāng)patch程序運(yùn)行時(shí),它會(huì)對(duì)將要改動(dòng)的每個(gè)源文件做備份,在備份文件名的末尾加上.orig作后綴.如果patch程序不能應(yīng)用某個(gè)塊(hunk),它會(huì)用補(bǔ)丁文件中存儲(chǔ)的文件名加上.rej(拒絕)后綴來保存該塊.
$diff -c sigrot.1 sigrot.2 > sigrot.patch 或者使用 $diff -u sigrot.1
sigrot.2 >
sigrot.patch 如果源代碼樹內(nèi)包含子目錄,則在使用diff時(shí)指定-r(recursive)選項(xiàng)以告訴diff在創(chuàng)建補(bǔ)丁文件時(shí)遍歷所有子目錄.
使用補(bǔ)丁的命令行如下: $patch -p0 < sigrot.patch -pnum
選項(xiàng)指定使用補(bǔ)丁前補(bǔ)丁中所包含的文件名中需要?jiǎng)冸x的"/"的重?cái)?shù).例如,如果補(bǔ)丁中的文件名是/home/kwall/src/sigrot/sigrot.1,則-p1的結(jié)果是home/kwall/src/sigrot/sigrot.1;-p4的結(jié)果是/sigrot/sigrot.1;-p則剝?nèi)チ顺罱K文件名之外的所有部分,得到sigrot.1.
如果在安裝完補(bǔ)丁后發(fā)現(xiàn)錯(cuò)誤,只要簡(jiǎn)單地在原命令行中加上-R選項(xiàng)后再安裝一次該補(bǔ)丁就能得到原來的文件: $patch
-p0 -R < sigrot.patch
版本控制術(shù)語 名稱 說明 RCS
File 在RCS目錄下的文件,由RCS控制,并通過RCS命令存取.一個(gè)RCS文件包含某一特殊文件的所有版本.通常,RCS文件的擴(kuò)展名是.v Working
file 從RCS源代碼庫(即RCS目錄)中檢索到的一個(gè)或多個(gè)文件,放置在當(dāng)前工作目錄下,并能夠被編輯. Lock 以編輯目的取回工作文件時(shí)別人就不能同時(shí)編輯這個(gè)文件.此時(shí),文件由第一個(gè)編輯它的人鎖定 Revision 源文件的一個(gè)特定版本,用數(shù)字標(biāo)識(shí).Revision的編號(hào)從1.1開始,并依次遞增,除非強(qiáng)制指定修訂版號(hào)
|