<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ### 在分支間拷貝修改 現在你與Sally在同一個項目的并行分支上工作:你在私有分支上,而Sally在主干(*trunk*)或者叫做開發主線上。 由于有眾多的人參與項目,大多數人擁有主干拷貝是很正常的,任何人如果進行一個長周期的修改會使得主干陷入混亂,所以通常的做法是建立一個私有分支,提交修改到自己的分支,直到這階段工作結束。 所以,好消息就是你和Sally不會互相打擾,壞消息是有時候分離會*太*遠。記住“閉門造車”策略的問題,當你完成你的分支后,可能因為太多沖突,已經無法輕易合并你的分支和主干的修改。 相反,在你工作的時候你和Sally仍然可以繼續分享修改,這依賴于你決定什么值得分享,Subversion給你在分支間選擇性“拷貝”修改的能力,當你完成了分支上的所有工作,所有的分支修改可以被拷貝回到主干。 ### 拷貝特定的修改 在上一章節,我們提到你和Sally對`integer.c`在不同的分支上做過修改,如果你看了Sally的344版本的日志信息,你會知道她修正了一些拼寫錯誤,毋庸置疑,你的拷貝的文件也一定存在這些拼寫錯誤,所以你以后的對這個文件修改也會保留這些拼寫錯誤,所以你會在將來合并時得到許多沖突。最好是現在接收Sally的修改,而不是作了許多工作之后才來做。 是時間使用**svn merge**命令,這個命令的結果非常類似**svn diff**命令(在第3章的內容),兩個命令都可以比較版本庫中的任何兩個對象并且描述其區別,舉個例子,你可以使用**svn diff**來查看Sally在版本344作的修改: ~~~ $ svn diff -r 343:344 http://svn.example.com/repos/calc/trunk Index: integer.c =================================================================== --- integer.c (revision 343) +++ integer.c (revision 344) @@ -147,7 +147,7 @@ case 6: sprintf(info->operating_system, "HPFS (OS/2 or NT)"); break; case 7: sprintf(info->operating_system, "Macintosh"); break; case 8: sprintf(info->operating_system, "Z-System"); break; - case 9: sprintf(info->operating_system, "CPM"); break; + case 9: sprintf(info->operating_system, "CP/M"); break; case 10: sprintf(info->operating_system, "TOPS-20"); break; case 11: sprintf(info->operating_system, "NTFS (Windows NT)"); break; case 12: sprintf(info->operating_system, "QDOS"); break; @@ -164,7 +164,7 @@ low = (unsigned short) read_byte(gzfile); /* read LSB */ high = (unsigned short) read_byte(gzfile); /* read MSB */ high = high << 8; /* interpret MSB correctly */ - total = low + high; /* add them togethe for correct total */ + total = low + high; /* add them together for correct total */ info->extra_header = (unsigned char *) my_malloc(total); fread(info->extra_header, total, 1, gzfile); @@ -241,7 +241,7 @@ Store the offset with ftell() ! */ if ((info->data_offset = ftell(gzfile))== -1) { - printf("error: ftell() retturned -1.\n"); + printf("error: ftell() returned -1.\n"); exit(1); } @@ -249,7 +249,7 @@ printf("I believe start of compressed data is %u\n", info->data_offset); #endif - /* Set postion eight bytes from the end of the file. */ + /* Set position eight bytes from the end of the file. */ if (fseek(gzfile, -8, SEEK_END)) { printf("error: fseek() returned non-zero\n"); ~~~ **svn merge**命令幾乎完全相同,但不是打印區別到你的終端,它會直接作為*本地修改*作用到你的本地拷貝: ~~~ $ svn merge -r 343:344 http://svn.example.com/repos/calc/trunk U integer.c $ svn status M integer.c ~~~ **svn merge**的輸出告訴你的`integer.c`文件已經作了補丁(patched),現在已經保留了Sally修改―修改從主干“拷貝”到你的私有分支的工作拷貝,現在作為一個本地修改,在這種情況下,要靠你審查本地的修改來確定它們工作正常。 在另一種情境下,事情并不會運行得這樣正常,也許`integer.c`也許會進入沖突狀態,你必須使用標準過程(見第三章)來解決這種狀態,或者你認為合并是一個錯誤的決定,你只需要運行**svn revert**放棄。 但是當你審查過你的合并結果后,你可以使用**svn commit**提交修改,在那一刻,修改已經合并到你的分支上了,在版本控制術語中,這種在分支之間拷貝修改的行為叫做*搬運*修改。 當你提交你的修改時,確定你的日志信息中說明你是從某一版本搬運了修改,舉個例子: ~~~ $ svn commit -m "integer.c: ported r344 (spelling fixes) from trunk." Sending integer.c Transmitting file data . Committed revision 360. ~~~ 你將會在下一節看到,這是一條非常重要的“最佳實踐”。 **為什么不使用補丁?** 也許你的腦中會出現一個問題,特別如果你是Unix用戶,為什么非要使用**svn merge**?為什么不簡單的使用操作系統的**patch**命令來進行相同的工作?舉個例子: ~~~ $ svn diff -r 343:344 http://svn.example.com/repos/calc/trunk > patchfile $ patch -p0 < patchfile Patching file integer.c using Plan A... Hunk #1 succeeded at 147. Hunk #2 succeeded at 164. Hunk #3 succeeded at 241. Hunk #4 succeeded at 249. done ~~~ 在這種情況下,確實沒有區別,但是**svn merge**有超越**patch**的特別能力,使用**patch**對文件格式有一定的限制,它只能針對文件內容,沒有方法表現*目錄樹*的修改,例如添加、刪除或是改名。如果Sally的修改包括增加一個新的目錄,**svn diff**不會注意到這些,**svn diff**只會輸出有限的補丁格式,所以有些問題無法表達。 但是**svn merge**命令會通過直接作用你的工作拷貝來表示目錄樹的修改。 一個警告:為什么**svn diff**和**svn merge**在概念上是很接近,但語法上有許多不同,一定閱讀第9章來查看其細節或者使用**svn help**查看幫助。舉個例子,**svn merge**需要一個工作拷貝作為目標,就是一個地方來施展目錄樹修改,如果一個目標都沒有指定,它會假定你要做以下某個普通的操作: 1. 你希望合并目錄修改到工作拷貝的當前目錄。 1. 你希望合并修改到你的當前工作目錄的相同文件名的文件。 如果你合并一個目錄而沒有指定特定的目標,**svn merge**假定第一種情況,在你的當前目錄應用修改。如果你合并一個文件,而這個文件(或是一個有相同的名字文件)在你的當前工作目錄存在,**svn merge**假定第二種情況,你想對這個同名文件使用合并。 如果你希望修改應用到別的目錄,你需要說出來。舉個例子,你在工作拷貝的父目錄,你需要指定目標目錄: ~~~ $ svn merge -r 343:344 http://svn.example.com/repos/calc/trunk my-calc-branch U my-calc-branch/integer.c ~~~ ### 合并背后的關鍵概念 你已經看到了**svn merge**命令的例子,你將會看到更多,如果你對合并是如何工作的感到迷惑,這并不奇怪,很多人和你一樣。許多新用戶(特別是對版本控制很陌生的用戶)會對這個命令的正確語法感到不知所措,不知道怎樣和什么時候使用這個特性,不要害怕,這個命令實際上比你想象的簡單!有一個簡單的技巧來幫助你理解**svn merge**的行為。 迷惑的主要原因是這個命令的*名稱*,術語“合并”不知什么原因被用來表明分支的組合,或者是其他什么神奇的數據混合,這不是事實,一個更好的名稱應該是**svn diff-and-apply**,這是發生的所有事件:首先兩個版本庫樹比較,然后將區別應用到本地拷貝。 這個命令包括三個參數: 1. 初始的版本樹(通常叫做比較的*左邊*), 1. 最終的版本樹(通常叫做比較的*右邊*), 1. 一個接收區別的工作拷貝(通常叫做合并的*目標*)。 一旦這三個參數指定以后,兩個目錄樹將要做比較,比較結果將會作為本地修改應用到目標工作拷貝,當命令結束后,結果同你手工修改或者是使用**svn add**或**svn delete**沒有什么區別,如果你喜歡這結果,你可以提交,如果不喜歡,你可以使用**svn revert**恢復修改。 **svn merge**的語法允許非常靈活的指定參數,如下是一些例子: ~~~ $ svn merge http://svn.example.com/repos/branch1@150 \ http://svn.example.com/repos/branch2@212 \ my-working-copy $ svn merge -r 100:200 http://svn.example.com/repos/trunk my-working-copy $ svn merge -r 100:200 http://svn.example.com/repos/trunk ~~~ 第一種語法使用*URL@REV*的形式直接列出了所有參數,第二種語法可以用來作為比較同一個URL的不同版本的簡略寫法,最后一種語法表示工作拷貝是可選的,如果省略,默認是當前目錄。 ### 合并的最佳實踐 #### 手工追蹤合并 合并修改聽起來很簡單,但是實踐起來會是很頭痛的事,如果你重復合并兩個分支,你也許會合并*兩次*同樣的修改。當這種事情發生時,有時候事情會依然正常,當對文件打補丁時,Subversion如果注意到這個文件已經有了相應的修改,而不會作任何操作,但是如果已經應用的修改又被修改了,你會得到沖突。 理想情況下,你的版本控制系統應該會阻止對一個分支做兩次改變操作,必須自動的記住那一個分支的修改已經接收了,并且可以顯示出來,用來盡可能幫助自動化的合并。 不幸的是,Subversion不是這樣一個系統,類似于CVS,Subversion并不記錄任何合并操作,當你提交本地修改,版本庫并不能判斷出你是通過**svn merge**還是手工修改得到這些文件。 這對你這樣的用戶意味著什么?這意味著除非Subversion以后發展這個特性,你必須手工的記錄這些信息。最佳的方式是使用提交日志信息,像前面的例子提到的,推薦你在日志信息中說明合并的特定版本號(或是版本號的范圍),之后,你可以運行**svn log**來查看你的分支包含哪些修改。這可以幫助你小心的依序運行**svn merge**命令而不會進行多余的合并。 在下一小節,我們要展示一些這種技巧的例子。 #### 預覽合并 因為合并只是導致本地修改,它不是一個高風險的操作,如果你在第一次操作錯誤,你可以運行**svn revert**來再試一次。 有時候你的工作拷貝很可能已經改變了,合并會針對存在的那一個文件,這時運行**svn revert**不會恢復你在本地作的修改,兩部分的修改無法識別出來。 在這個情況下,人們很樂意能夠在合并之前預測一下,一個簡單的方法是使用運行**svn merge**同樣的參數運行**svn diff**,另一種方式是傳遞`--dry-run`選項給merge命令: ~~~ $ svn merge --dry-run -r 343:344 http://svn.example.com/repos/calc/trunk U integer.c $ svn status # nothing printed, working copy is still unchanged. ~~~ `--dry-run`選項實際上并不修改本地拷貝,它只是顯示實際合并時的狀態信息,對于得到“整體”的印象,這個命令很有用,因為**svn diff**包括太多細節。 **Subversion與修改集** 每一個人對于“修改集”的概念都有些不一樣,至少對于版本控制系統的“修改集特性”這一概念有著不同的期望,根據我們的用途,可以說修改集只是一個有唯一名字的一系列修改集合,修改也許包括文件內容的修改,目錄樹結構的修改,或是元數據的調整,更通常的說法,一個修改集就是我們可以引用的有名字的補丁。 在Subversion里,一個全局的修訂版本號N標示一個版本庫中的樹:它代表版本庫在N次提交后的樣子,它也是一個修改集的隱含名稱:如果你比較樹N與樹N-1,你可以得到你提交的補丁。出于這個原因,想象“版本N”并不只是一棵樹,也是一個修改集。如果你使用一個問題追蹤工具來管理bug,你可以使用版本號來表示特定的補丁修正了bug―舉個例子,“這個問題是在版本9238修正的”,然后其他人可以運行**svn log -r9238**來查看修正這個bug的修改集,或者使用**svn diff -r9237:9238**來看補丁本身。Subversion合并命令也使用版本號作為參數,可以將特定修改集從一個分支合到另一個分支:**svn merge -r9237:9238**將會合并修改集#9238到本地拷貝。 #### 合并沖突 就像**svn update**命令,**svn merge**會把修改應用到工作拷貝,因此它也會造成沖突,因為**svn merge**造成的沖突有時候會有些不同,本小節會解釋這些區別。 作為開始,我們假定本地沒有修改,當你**svn update**到一個特定修訂版本時,修改會“干凈的”應用到工作拷貝,服務器產生比較兩樹的增量數據:一個工作拷貝和你關注的版本樹的虛擬快照,因為比較的左邊同你擁有的完全相同,增量數據確保你把工作拷貝轉化到右邊的樹。 但是**svn merge**沒有這樣的保證,會導致很多的混亂:用戶可以詢問服務器比較*任何*兩個樹,即使一個與工作拷貝毫不相關的!這意味著有潛在的人為錯誤,用戶有時候會比較兩個錯誤的樹,創建的增量數據不會干凈的應用,**svn merge**會盡力應用更多的增量數據,但是有一些部分也許會難以完成,就像Unix下**patch**命令有時候會報告“failed hunks”錯誤,**svn merge**會報告“skipped targets”: ~~~ $ svn merge -r 1288:1351 http://svn.example.com/repos/branch U foo.c U bar.c Skipped missing target: 'baz.c' U glub.c C glorb.h $ ~~~ 在前一個例子中,`baz.c`也許會存在于比較的兩個分支快照里,但工作拷貝里不存在,比較的增量數據要應用到這個文件,這種情況下會發生什么?“skipped”信息意味著用戶可能是在比較錯誤的兩棵樹,這是經典的驅動器錯誤,當發生這種情況,可以使用迭代恢復(**svn revert --recursive**)合并所作的修改,刪除恢復后留下的所有未版本化的文件和目錄,并且使用另外的參數運行**svn merge**。 也應當注意前一個例子顯示`glorb.h`發生了沖突,我們已經規定本地拷貝沒有修改:沖突怎么會發生呢?因為用戶可以使用**svn merge**將過去的任何變化應用到當前工作拷貝,變化包含的文本修改也許并不能干凈的應用到工作拷貝文件,即使這些文件沒有本地修改。 另一個**svn update**和**svn merge**的小區別是沖突產生的文件的名字不同,在[“解決沖突(合并別人的修改)”一節]( "解決沖突(合并別人的修改)"),我們看到過更新產生的文件名字為`filename.mine`、`filename.rOLDREV`和`filename.rNEWREV`,當**svn merge**產生沖突時,它產生的三個文件分別為 `filename.working`、`filename.left`和`filename.right`。在這種情況下,術語“left”和“right”表示了兩棵樹比較時的兩邊,在兩種情況下,不同的名字會幫助你區分沖突是因為更新造成的還是合并造成的。 #### 關注還是忽視祖先 當與Subversion開發者交談時你一定會聽到提及術語*祖先*,這個詞是用來描述兩個對象的關系:如果他們互相關聯,一個對象就是另一個的祖先,或者相反。 舉個例子,假設你提交版本100,包括對`foo.c`的修改,則foo.c@99是foo.c@100的一個“祖先”,另一方面,假設你在版本101刪除這個文件,而在102版本提交一個同名的文件,在這個情況下,`foo.c@99`與`foo.c@102`看起來是關聯的(有同樣的路徑),但是事實上他們是完全不同的對象,它們并不共享同一個歷史或者說“祖先”。 指出**svn diff**和**svn merge**區別的重要性在于,前一個命令忽略祖先,如果你詢問**svn diff**來比較文件`foo.c`的版本99和102,你會看到行為基礎的區別,區別命令只是盲目的比較兩條路徑,但是如果你使用**svn merge**是比較同樣的兩個對象,它會注意到他們是不關聯的,而且首先嘗試刪除舊文件,然后添加新文件,你會看到`A foo.c`后面緊跟`D foo.c`。 大多數合并包括比較包括祖先關聯的兩條樹,因此**svn merge**這樣運作,然而,你也許會希望合并命令能夠比較兩個不相關的目錄樹,舉個例子,你有兩個目錄樹分別代表了賣主軟件項目的不同版本(見[“賣主分支”一節]( "賣主分支")),如果你使用**svn merge**進行比較,你會看到第一個目錄樹被刪除,而第二個樹添加上! 在這個情況下,你只是希望**svn merge**能夠做一個以路徑為基礎的比較,忽略所有文件和目錄的關系,增加`--ignore-ancestry`選項會導致命令象**svn diff**一樣。(相應的,`--notice-ancestry`選項會使**svn diff**象合并命令一樣行事。) 在將來,Subversion項目將會計劃(或者發明)一種擴展補丁格式來描述目錄樹改變。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看