如果您要對 Subversion 專案做出貢獻,請先閱讀這份文件。
雖然 Subversion 最初是由 CollabNet 贊助和託管(https://www.collab.net/),但它是一個真正的開源專案,採用 Apache 授權條款,版本 2.0。許多 Subversion 開發人員由其雇主支付薪水來改善 Subversion,而其他許多人只是單純對建置更好的版本控制系統有興趣的優秀志工。
社群主要透過 IRC、郵件清單和 Subversion 儲存庫存在。若要參與
在 #svn-dev 頻道加入我們於 irc.libera.chat(使用 網路介面 或 Matrix 或任何 IRC 軟體;已封存 於此)。
加入「開發」、「提交」和「公告」郵件清單。開發清單 dev@subversion.apache.org 是幾乎所有討論進行的地方。所有開發問題都應張貼於此,儘管您可能想要先查看清單封存。提交清單會收到自動提交電子郵件。請參閱 https://subversion.dev.org.tw/mailing-lists.html 以取得詳細資訊。
從 https://svn.apache.org/repos/asf/subversion/trunk/ 取得最新開發原始碼
新的開發始終在主幹上進行。錯誤修正、增強功能和新功能會從主幹回傳到各個發行分支。
多年來,Subversion 社群每年都會在柏林舉辦一次黑客松:2016、2015、2014、2013、2012、2011 和 2010 [連結來自 archive.org,有些媒體連結失效]。
有許多方式可以加入這個專案,包括撰寫程式碼、測試和/或協助管理錯誤資料庫。如果您想貢獻一己之力,請查看
若要提交程式碼,請將您的程式碼補丁寄送至 dev@subversion.apache.org。不對,請先閱讀完本檔案的其餘部分,然後再開始將程式碼補丁寄送至 dev@subversion.apache.org。 :-)
若要協助管理問題資料庫,請閱讀問題摘要,尋找並測試無效或重複的問題。這兩種情況都很常見,前者是因為錯誤通常會在不知不覺中,因為程式碼中的其他變更而得到修正,後者是因為人們有時會在沒有注意到問題已經被回報的情況下,提交問題。如果您不確定某個問題,請在 dev@subversion.apache.org 發布問題。("Subversion:我們在此協助您協助我們!")
協助的另一種方式是在某些平台上設定 Subversion 的自動建置和測試套件執行,並將輸出寄送至 notifications@subversion.apache.org 郵件清單。請在 郵件清單頁面 查看更多詳細資訊。
最後,儘管 Subversion 專案的線上性質以及由此產生的抽象人際接觸,但重要的是要了解,所有貢獻的背後都有真實的人。以你希望被對待的方式對待所有其他社群成員。檢閱貢獻,而不是貢獻者;不要惹惱他人,也不要輕易被惹惱。
設計
一份設計規範寫於 2000 年 6 月,有點過時了。但它仍然對儲存庫的內部運作和 Subversion 的各個層級提供了良好的理論介紹。
API 文件
請參閱公開 API 文件部分以取得更多資訊。
Delta 編輯器
Karl Fogel 為 O'Reilly 的 2007 年書籍美麗的程式碼:領先的程式設計師說明他們的思考方式撰寫了一章,涵蓋Subversion 的 delta 編輯器介面的設計和使用。
網路通訊協定
WebDAV 使用文件是 Subversion 的 DAV 網路通訊協定的簡介,它是一種 HTTP 的擴充方言,並使用以「http://」或「https://」開頭的 URL。
SVN 通訊協定文件包含 Subversion ra_svn 網路通訊協定的正式說明,這是一種在埠 3690(預設)上的自訂通訊協定,其 URL 以「svn://」或「svn+ssh://」開頭。
使用者手冊
由 O'Reilly 出版的《Subversion 版本控制》是一本詳細說明如何有效使用 Subversion 的書籍。該書的文字是免費的,並且積極地進行修訂。線上版本可在https://svnbook.dev.org.tw/取得。XML 原始碼和翻譯成其他語言的版本保留在其自己的儲存庫中,網址為https://sourceforge.net/projects/svnbook/。
系統備註
系統特定面向的許多設計概念已記錄在 notes/ 目錄中的個別檔案中。
在您能貢獻程式碼之前,您需要熟悉現有的程式碼庫和介面。
檢出 Subversion 的一份副本(匿名,如果您還沒有具有提交存取權的帳戶) — 這樣您就能檢視程式碼。
在 'subversion/include/' 內有一堆具有龐大文件註解的標頭檔案。如果您讀過這些檔案,您將對實作細節有相當好的了解。以下是建議的閱讀順序
基本建構區塊: svn_string.h, svn_error.h, svn_types.h
關鍵介面: svn_delta.h
用戶端介面: svn_ra.h, svn_wc.h, svn_client.h
儲存庫和版本化檔案系統: svn_repos.h, svn_fs.h
Subversion 嘗試僅使用 C89/C90 方言的 ANSI/ISO C 以及 Apache Portable Runtime (APR) 函式庫,以保持可攜性。APR 是 Apache httpd 伺服器使用的可攜性層,更多資訊可見 https://apr.apache.org/。
由於 Subversion 非常依賴 APR,因此在不先瀏覽 APR 中的某些標頭檔案(請查看 'apr/include/')的情況下,可能很難理解 Subversion。
記憶體池: apr_pools.h
檔案系統存取: apr_file_io.h
雜湊和陣列: apr_hash.h, apr_tables.h
Subversion 也嘗試提供可靠且安全的軟體。這只能由了解 C 程式語言中安全編程的開發人員來達成。請參閱「notes/assurance.txt」以了解背後的完整依據。特別是,你應該仔細閱讀 David Wheeler 的安全編程(如 「notes/assurance.txt」 中所述)。如果你在任何時候對變更的安全性影響有任何疑問,我們強烈建議你在開發人員寄件清單中請求檢閱。
原始碼樹的粗略指南
doc/
使用者和開發人員文件。
tools/
與 Subversion 搭配使用的程式,但 Subversion 並不依賴它們。tools/ 中的程式碼由 Subversion 專案共同維護,並與 Subversion 本身採用相同的開放原始碼版權。
contrib/
與 Subversion 搭配使用的程式,但 Subversion 並不依賴它們,而且由可能參與或不參與 Subversion 開發的個人維護。contrib/ 中的程式碼為開放原始碼,但可能與 Subversion 本身採用不同的授權或版權持有者。
subversion/
Subversion 本身的原始碼(與外部函式庫相反)。
subversion/include/
Subversion 函式庫使用者的公開標頭檔。
subversion/include/private/
Subversion 函式庫內部共用的私人標頭檔。
subversion/libsvn_fs/
版本控制「檔案系統」API。
subversion/libsvn_repos/
建立在「libsvn_fs」核心上的儲存庫功能。
subversion/libsvn_delta/
樹狀結構增量、文字增量和屬性增量的共用程式碼。
subversion/libsvn_wc/
工作副本的共用程式碼。
subversion/libsvn_ra/
儲存庫存取的共用程式碼。
subversion/libsvn_client/
用戶端操作的共用程式碼。
subversion/svn/
命令列用戶端。
subversion/tests/
自動化測試套件。
Subversion 專案強烈建議在共用主幹中進行積極開發。對主幹所做的變更具有最高的可見度,並能從未發布的程式碼中獲得最大的執行次數。不過,為了讓這對所有人都有利,我們預期主幹隨時都能保持穩定。它應該可以建置。它應該可以運作。它可能還未準備好發布,但它肯定已準備好進行測試套件測試。
我們也強烈建議將大型變更拆分成數個較小、較合乎邏輯的提交 — 預期每個提交都能符合上述穩定性需求。
話雖如此,我們了解將所有這些政策套用在特別大型變更(新功能、大規模程式碼重組等)上幾乎是不可能的。在這種情況下,你可以考慮使用專門針對你的開發任務的分支。以下是讓你的基於分支的開發工作順利進行的一些準則。
基於分支的開發並無特別複雜之處。你從主幹(或從最適合作為你的工作來源和目的地的分支)建立一個分支,然後在上面進行你的工作。Subversion 的合併追蹤功能已大幅減少以這種方式工作所需的心智負擔,因此強烈建議善用該功能(使用 Subversion 1.5 或更新的用戶端,並執行所有合併至分支的根目錄和從分支的根目錄的合併)。
關於您分公司日誌訊息的政策,請注意撰寫日誌訊息的部分。
如果您正在分階段處理包含多個提交的功能或錯誤修正,並且某些中間階段還不穩定到無法進入主線,請在 /branches 中建立一個臨時分支。無需詢問,直接執行即可。在臨時分支中嘗試實驗性想法也是可以的。以上所有內容都適用於部分提交者和完整提交者。甚至適用於其他 ASF 專案的提交者,但請與我們聯繫 (在 dev@) 中自我介紹並說明您計畫處理的問題。
當您完成分支時,無論是將其合併到主線還是放棄,請記得將其移除。
另請參閱部分提交權限部分,了解我們提供對實驗性分支的提交權限的政策。
對於您預期會長期存在的分支,我們建議在分支根目錄中建立並定期更新一個名為 BRANCH-README 的檔案。此類檔案可為您提供一個絕佳的集中位置,用於描述分支的下列面向
分支的基本目的:它存在的錯誤要修正,或要實作的功能;它相關的議題編號;圍繞它的討論串清單;描述情況的設計文件。
您正在使用哪種分支管理風格:這是一個會定期與其父分支保持同步,並最終重新整合回該父分支的功能分支嗎?這是一個預計在可預見的未來不會合併回其父分支的分支嗎?它與其他分支有關嗎?
您在分支上還有哪些任務要完成?這些任務是由某人聲稱的嗎?他們需要更多設計輸入嗎?其他人如何才能幫助您?
以下是一個 BRANCH-README 檔案範例,展示了我們正在討論的內容
This branch exists for the resolution of issue #8810, per the ideas documented in /trunk/notes/frobnobbing-feature.txt. It is a feature branch, receiving regular sync merges from /trunk, and expected to be reintegrated back thereto. TODO: * compose regression tests [DONE] * add frob identification logic [STARTED (fitz)] * add nobbing bits []
為什麼這麼大驚小怪?因為這個專案理想化了溝通和協作,了解後者更有可能發生在前者被強調時。
請記住,當您將分支合併回其來源時,請刪除 BRANCH-README 檔案。
每個函式,無論是公開的還是內部的,都必須以文件註解開頭,說明該函式的功能。文件應提及函式接收的每個參數、每個可能的回傳值,以及(如果不明顯)函式可能回傳錯誤的條件。
對於內部文件,將參數名稱以大寫字母放在文件字串中,即使它們在實際宣告中不是大寫字母,以便它們對人類讀者來說顯著。
對於公開或半公開 API 函式,文件字串應放在 .h 檔案中函式的上方,在該檔案中宣告函式;否則,它會放在 .c 檔案中函式定義的上方。
對於結構類型,記錄結構的每個個別成員以及結構本身。
對於實際的原始碼,在內部記錄每個函式的區塊,以便熟悉 Subversion 的人可以瞭解正在實作的演算法。不要包含明顯或過於冗長的說明文件;註解應有助於理解程式碼,而不是阻礙理解。
例如
/*** How not to document. Don't do this. ***/
/* Make a foo object. */
static foo_t *
make_foo_object(arg1, arg2, apr_pool_t *pool)
{
/* Create a subpool. */
apr_pool_t *subpool = svn_pool_create(pool);
/* Allocate a foo object from the main pool */
foo_t *foo = apr_palloc(pool, sizeof(*foo));
...
}
相反地,記錄適當大小的程式碼區塊,如下所示
/* Transmit the segment (if its within the scope of our concern). */ SVN_ERR(maybe_crop_and_send_segment(segment, start_rev, end_rev, receiver, receiver_baton, subpool)); /* If we've set CURRENT_REV to SVN_INVALID_REVNUM, we're done (and didn't ever reach END_REV). */ if (! SVN_IS_VALID_REVNUM(current_rev)) break; /* If there's a gap in the history, we need to report as much (if the gap is within the scope of our concern). */ if (segment->range_start - current_rev < 1) { svn_location_segment_t *gap_segment; gap_segment = apr_pcalloc(subpool, sizeof(*gap_segment)); gap_segment->range_end = segment->range_start - 1; gap_segment->range_start = current_rev + 1; gap_segment->path = NULL; SVN_ERR(maybe_crop_and_send_segment(gap_segment, start_rev, end_rev, receiver, receiver_baton, subpool)); }
閱讀 Subversion 程式碼以概觀實際的記錄方式;特別是,請參閱 subversion/include/*.h 以了解 doxygen 範例。
我們使用 Doxygen 格式來記錄公開介面。這表示任何放入公開標頭檔的內容。產生的記錄會 發佈在網站 上,供最新和較早的 Subversion 來源使用。
我們只使用 doxygen 指令 中的一小部分來標記我們的來源。撰寫 doxygen 記錄時,請套用下列慣例
@a
,在類型和巨集名稱前加上 @c
。<tt>...</tt>
來顯示多個字詞,並使用 @p
來只顯示一個字詞,並以打字機字型顯示。TRUE
、FALSE
和 NULL
應全部大寫。@defgroup
和 @{...@}
將它們分組在一起。請參閱 Doxygen 手冊 以取得完整指令清單。
若要取得最新來源程式碼,請執行
svn checkout https://svn.apache.org/repos/asf/subversion/trunk/ svn-trunk
並遵循 INSTALL 檔案中的說明。(如果您沒有 svn 軟體,下載原始碼壓縮檔。)
如果您的修補程式實作新功能,或變更大量程式碼,請記得先在 dev@ 清單上討論。(在 #svn-dev 上的 IRC 也適合在郵寄清單討論之前獲得快速回饋,但不能取代郵寄清單討論。如果您在 IRC 上詢問,請等待一段時間再回應,因為並非所有人都會隨時在線上(特別是在週末)。)這樣社群才能盡快表達疑慮,並建議針對提議的功能或實作細節進行改善,如果能盡早提供回饋(甚至在撰寫任何程式碼之前),對所有相關方來說總是比較好的。
如果您對修補程式有任何疑問,請隨時在 IRC 或 dev@ 上發問。
將修補程式郵寄至 dev@subversion.apache.org,主旨行開頭為 [PATCH]。這有助於我們的 修補程式管理員 立即發現修補程式。例如
Subject: [PATCH] fix for rev printing bug in svn status
如果修補程式解決特定問題,請一併包含問題編號:"[PATCH] issue #1729: ..."。對該特定問題有興趣的開發人員會知道要閱讀郵件。
修補程式提交應包含一個邏輯變更;請不要在一個提交中混入 N 個不相關的變更,請改為傳送 N 封個別的電子郵件。
使用 svn diff -x-p 從 Subversion trunk 工作副本的頂端產生修補程式。如果您要進行 diff 的檔案不在版本控制中,您可以使用 diff -u 達到相同的效果。
請在您的修補程式中包含一則記錄訊息。一則好的記錄訊息有助於潛在的審閱者了解修補程式中的變更,並增加套用的可能性。您可以將記錄訊息放在電子郵件的內文中,或放在修補程式附件的最上方(請見下方)。無論哪種方式,都應遵循撰寫記錄訊息中提供的準則,並以三個方括號括住,如下所示
[[[ Fix issue #1729: Don't crash because of a missing file. * subversion/libsvn_ra_ansible/get_editor.c (frobnicate_file): Check that file exists before frobnicating. ]]]
(括號實際上並非記錄訊息的一部分,它們只是清楚標示記錄訊息與周圍文字區隔的一種方式。)
如果可能,請將修補程式作為附件傳送,並使用 text/x-diff
、text/x-patch
或 text/plain
的 mime 類型。大多數人的郵件閱讀器都能在其中顯示,而且將修補程式作為附件可讓他們方便地從訊息中提取修補程式。切勿以封存或壓縮的形式傳送修補程式(例如 tar、gzip、zip、bzip2),因為這會妨礙人們在郵件閱讀器中直接審閱修補程式。
如果您無法使用這些 mime 類型之一附加修補程式,或者修補程式很短,那麼直接將其包含在訊息的內文中是可以的。但請注意:有些郵件編輯器會在長行的中間插入未要求的行中斷,從而破壞內嵌修補程式。如果您認為您的郵件軟體可能會這樣做,請改用附件。
如果修補程式實作新的功能,請務必在您的郵件中完整說明該功能;如果修補程式修正錯誤,請詳細說明錯誤並提供重現步驟。這些準則的例外情況是修補程式針對問題資料庫中的特定問題時,在這種情況下,只需在您的記錄訊息中參照問題編號,如撰寫記錄訊息中所述。
在套用補丁之前,經過幾輪的回饋和變更是很正常的。如果你的補丁沒有馬上被接受,不要灰心,這並不表示你搞砸了,這只表示有很多雙眼睛在看每一份程式碼提交,而沒有任何改進空間的補丁很少見。在討論大家對你的補丁的回應後,進行適當的變更並重新提交,等待下一輪的回饋,然後重複這個步驟,直到有提交者套用它。在提交補丁之前,你可以透過檢閱和套用專案的程式碼慣例來避免一些反覆作業。
如果你在一段時間內沒有收到回應,而且沒有看到補丁被套用,這可能只是表示大家真的很忙。繼續重新張貼,並且不要猶豫指出你仍在等待回應。一種思考方式是,補丁管理高度可平行化,而且我們需要你承擔管理和編碼的責任。每一個補丁都需要有人引導它完成流程,而最適合做這件事的人就是原始提交者。
Subversion 專案中的提交者是指獲得直接提交變更至我們的版本控制資源的權限的那些人。這個專案是依據能力的,這表示(在其他事項中)專案治理是由那些做這項工作的人處理。有兩種提交權限:完全和部分。完全表示在樹狀結構中的任何地方,部分表示只在提交者的特定專業領域。雖然每項貢獻都受到重視,不論其來源,但並非每個為 Subversion 貢獻程式碼的人都會獲得提交權限。
COMMITTERS 檔案列出所有提交者,包括完全和部分提交者,並說明每個部分提交者的網域。
在某人成功貢獻一些非瑣碎的修補程式後,某些完整提交者(通常是審查並套用該貢獻者最多修補程式的人)會提議授予他們提交權限。此提議僅會寄送給其他完整提交者,後續討論是私密的,因此每個人都可以安心表達自己的想法。假設沒有異議,則會授予貢獻者提交權限。此決定是透過共識決定的;沒有正式規則規範此程序,但通常如果有人強烈反對,則不會提供權限,或是在臨時基礎上提供權限。
完整提交權限的主要標準是良好的判斷力。
您不必成為技術奇才,或展示對整個程式碼庫的深入了解,就能成為一位全權提交者。您只需要知道自己不知道的事。如果您的修補程式遵守此檔案中的準則,遵守所有通常無法量化的編碼規則(程式碼應可讀、強健、可維護等),並尊重「首先,不造成傷害」的希波克拉底原則,那麼您可能會很快獲得提交權限。您的修補程式的規模、複雜性和數量並不如您在避免錯誤和將對程式碼其他部分的影響降至最低時所表現出的謹慎程度那麼重要。許多全權提交者並未做出重大的程式碼貢獻,而是做出了許多小的、乾淨的修正,每一項都是對程式碼的明確改進。(當然,這並不表示專案需要一堆非常微不足道的修補程式,其唯一目的是獲得提交權限;知道什麼值得發布修補程式,什麼不值得,是展現良好判斷力的一部分 :-) 。)
為了協助開發人員發現新的提交者,我們會在 特殊信用格式 中記錄修補程式和其他貢獻,然後解析這些記錄以產生瀏覽器友善的 貢獻清單,並於每晚更新。如果您正在考慮提議某人獲得提交權限,並希望查看他們的所有變更,那麼 貢獻清單 可能會是最方便的地方。
全權提交者贊助部分提交者。這通常表示全權提交者已將數個修補程式套用至與建議的部分提交者相同的區域,並意識到如果此人直接提交,事情會變得更容易。慣例上建議贊助者在發出邀請之前先在 private@ 中提出此可能性,但並非必要;贊助者可信賴會做出良好的判斷。
贊助者會觀察部分提交者的前幾次提交,以確保一切順利進行。
由部分提交者提交的修補程式,即使超出該人員的範疇,該提交者也可以提交。這需要至少一位完整提交者的核准(通常表示為 +1 投票)。在這種情況下,應在記錄訊息中註明核准,如下所示
Approved by: lundblad
任何完整提交者都可以隨時為任何人提供對實驗分支的提交權限。實驗分支不一定要有很高的可能性併入主幹(雖然這始終是一個值得追求的良好目標)。更重要的是,完整提交者(實際上是所有完整提交者)將此類分支視為新開發人員的訓練場,方法是提供對提交的回饋。這些分支的目標是將新程式碼納入 Subversion,並讓新開發人員加入專案。另請參閱輕量級分支部分和這封郵件
https://svn.haxx.se/dev/archive-2007-11/0848.shtml From: Karl Fogel <kfogel@red-bean.com> To: dev@subversion.tigris.org Subject: branch liberalization (was: Elego tree conflicts work) Date: Tue, 20 Nov 2007 10:49:38 -0800 Message-Id: <87y7cswy4d.fsf@red-bean.com>
當工具被接受到contrib/區域時,我們會自動提供其作者部分提交權限以在那裡維護工具。任何完整提交者都可以贊助這項工作。通常不需要討論或投票,但如果有反對意見,則適用一般的決策程序(首先嘗試達成共識,如果無法達成共識,則在完整提交者之間投票)。
contrib/ 下的程式碼必須是開源的,但不必與 Subversion 本身具有相同的授權或著作權持有人。
任何提交者,無論是完整或部分,都可以提交修正明顯的錯字、文法錯誤和格式化問題,無論它們出現在何處,例如網頁、API 文件、程式碼註解、提交訊息等。我們依賴提交者的判斷來確定什麼是「顯而易見的」;如果您不確定,請詢問。
每當您援用「顯而易見的修正」規則時,請在提交的記錄訊息中說明。例如
------------------------------------------------------------------------ r32135 | stylesen | 2008-07-16 10:04:25 +0200 (Wed, 16 Jul 2008) | 8 lines Update "check-license.py" so that it can generate license text applicable to this year. Obvious fix. * tools/dev/check-license.py (NEW_LICENSE): s/2005/2008/ ------------------------------------------------------------------------
Subversion 專案中版本管理員的角色是處理將程式碼穩定化、封裝並發佈給一般大眾的程序。如果我們正在建造飛機,版本管理員將會是查看建造清單、在機身上噴上航空公司標誌,並將成品交付給客戶的人。
因此,擔任版本管理員並未與任何實際開發相關。您必須完成的所有工作都是非編碼的:協調人員、集中資訊,並成為宣告新的穩定版本之公開發言人。版本管理員必須執行的許多任務都是重複性的,而且未自動化,原因可能是因為尚未有人分解並撰寫工具,或者因為這些任務需要人工驗證,這使得自動化有些多餘。您可以在 製作 Subversion 版本 區段中閱讀更多有關版本程序的資訊。
您可能在這個階段認為版本管理員的職責並不光鮮亮麗,而您說得沒錯。如果您正在尋找一個能為專案帶來名聲和財富的職位,您最好實作主幹中真正需要完成的事項。如果您正在尋找能真正幫助不在乎版本的人員專注於程式碼的事項,那麼版本管理員就是您的最佳選擇。
為了鼓勵更廣泛的散布版本管理知識,RM 角色目前在各個 受害者 志工之間輪替。
Subversion 通常會有一個修補程式管理員,其工作是觀察 dev@ 郵件清單並確保沒有修補程式「從縫隙中溜走」。
這表示要觀察每個包含「[PATCH]」郵件的討論串,並根據討論串的進度採取適當的行動。如果討論串自行解決(因為修補程式已提交,或因為達成共識認為不需要套用修補程式,或其他原因),則不需要採取進一步的行動。但是,如果討論串在沒有明確決議的情況下逐漸消失,則需要將修補程式儲存在問題追蹤器中。這表示將會在追蹤器中的某個問題中新增該修補程式周圍所有討論串的摘要,以及相關郵件清單封存的連結。對於解決現有問題追蹤器項目的修補程式,則將修補程式儲存到該項目中。否則,會歸檔一個正確類型的問題(「缺陷」、「功能」或「增強」(不是「修補程式」)),將修補程式儲存到該新問題中,並在問題中記錄「patch」關鍵字。
修補程式管理員需要對 Subversion 有基本的技術了解,以及能夠瀏覽討論串並粗略了解是否已達成共識,以及如果是的話,達成什麼樣的共識。不需要實際的 Subversion 開發經驗或提交權限。熟練使用自己的郵件閱讀軟體是可選的,但建議 :-).
目前的修補程式管理員是:Gavin 'Beau' Baumanis <gavin@thespidernet.com>。
Subversion 的程式碼和標頭檔案會沿著幾個關鍵路線區分:特定於程式庫與程式庫間;公開與私有。這種分離主要是因為我們專注於適當的模組化和程式碼組織,但也因為我們作為廣泛採用的公開 API 的提供者和維護者的承諾。當您在 Subversion 中撰寫新函式時,您需要仔細考慮這些事情,在進行的同時自問一些問題
「我的新程式碼的使用者是否只限於單一程式庫中的特定原始碼檔案?」如果是這樣,您可能需要在同一個原始碼檔案中使用靜態函式。
「我的新函式是否為此程式庫中的其他原始碼需要使用,但程式庫*外部*不需要使用的類型?」如果是這樣,您需要使用非靜態、雙底線命名的函式(例如 svn_foo__do_something),其原型在適當的特定於程式庫的標頭檔案中。
「我的程式碼是否需要從不同的程式庫中存取?」在這裡,您需要回答一些額外的問題,例如「我的程式碼應該存在於我原本打算放置的程式庫中,還是應該存在於更通用的公用程式庫中,例如 libsvn_subr?」無論如何,您現在正在考慮使用程式庫間標頭檔案。但在您決定使用哪一個之前,請參閱下一個問題...
「我的程式碼是否具備乾淨、可維護的 API,可以合理地永久維護,並為 Subversion 公共 API 提供價值?」如果是,您將在 subversion/include/ 內部立即將原型新增至公共 API。如果不是,請仔細檢查您的計畫,也許您尚未選擇抽象功能的最佳方式。但有時,函式庫確實需要共用某些功能,而這些功能對 Subversion 本身以外的其他軟體來說可能沒有用。在這種情況下,請使用 subversion/include/private/ 中的私人標頭檔。
Subversion 使用 ANSI C,並遵循 GNU 編碼標準,但我們不會在函式名稱和其參數清單的開頭括號之間放置空格。Emacs 使用者可以載入 svn-dev.el 以取得正確的縮排行為(如果適當地設定 `enable-local-eval`,這裡的大部分原始檔將自動載入它)。
請閱讀 https://gnu.dev.org.tw/prep/standards.html 以完整說明 GNU 編碼標準。以下是展示最重要的格式準則的簡短範例,包括我們不使用參數清單括號前空格的例外
char * /* func type on own line */ argblarg(char *arg1, int arg2) /* func name on own line */ { /* first brace on own line */ if ((some_very_long_condition && arg2) /* indent 2 cols */ || remaining_condition) /* new line before operator */ { /* brace on own line, indent 2 */ arg1 = some_func(arg1, arg2); /* NO SPACE BEFORE PAREN */ } /* close brace on own line */ else { do /* format do-while like this */ { arg1 = another_func(arg1); } while (*arg1); } }
一般來說,即使您確定運算符優先順序,也要大方使用括號,並願意新增空格和換行符號以避免「程式碼壓縮」。別太擔心垂直密度;讓程式碼易於閱讀比在螢幕上放入額外一行更重要。
我們在程式碼和純文字散文檔中使用分頁符號(Ctrl-L 字元,ASCII 12)作為區段邊界。每個區段都以分頁符號開頭,而區段標題緊接在分頁符號之後。
這有助於使用 Emacs 分頁指令的人員,例如 `pages-directory` 和 `narrow-to-page`。這樣的人員並不像您想像的那麼少,如果您想成為其中一員,請將 (require 'page-ext) 新增至您的 .emacs,然後輸入 C-x C-p C-h。
下列慣例套用於錯誤訊息
僅在有資訊要新增至 subversion/include/svn_error_codes.h 中的「一般錯誤訊息」時,提供特定錯誤訊息。
訊息以大寫字母開頭。
嘗試將訊息保持在 70 個字元以下。
不要以句點(「.」)結尾錯誤訊息。
不要在錯誤訊息中包含換行字元。
使用單引號引述資訊(例如「『一些資訊』」)。
不要在錯誤訊息中包含錯誤發生的函式名稱。如果 Subversion 使用「--enable-maintainer-mode」組態旗標編譯,它會自行提供此資訊。
在錯誤字串中包含路徑或檔案名稱時,請務必引述它們(例如「找不到『/path/to/repos/userfile』」)。
在錯誤字串中包含路徑或檔案名稱時,請務必在包含之前使用 svn_dirent_local_style() 轉換它們(因為傳遞至 Subversion API 和從 Subversion API 傳回的路徑假設為 正規形式)。
不要使用 Subversion 特定的縮寫(例如使用「儲存庫」代替「repo」,使用「工作副本」代替「wc」)。
如果您想要在錯誤中新增說明,請在冒號後報告說明,如下所示
"Invalid " SVN_PROP_EXTERNALS " property on '%s': " "target involves '.' or '..'".
建議或其他新增內容可以在分號後新增,如下所示
"Can't write to '%s': object of same name already exists; remove " "before retrying".
嘗試保持在這些慣例的界線內,因此請避免使用其他分隔符號(例如「--」和其他的)來分隔錯誤訊息的不同部分。
另請閱讀 在地化。
(這假設您已經基本了解 APR 池運作方式;有關詳細資訊,請參閱 apr_pools.h。)
使用 Subversion 函式庫的應用程式必須在呼叫任何 Subversion 函式之前呼叫 apr_initialize()。
Subversion 的一般池使用策略可以用兩個原則來概括
建立池的呼叫層級是清除或銷毀該池的唯一位置。
在進行無界限的重複時,在進入重複之前建立一個子池,在迴圈內使用它,並在每次重複的開始時清除它,然後在迴圈完成後銷毀它,如下所示
apr_pool_t *iterpool = svn_pool_create(scratch_pool); for (i = 0; i < n; ++i) { svn_pool_clear(iterpool); do_operation(..., iterpool); } svn_pool_destroy(iterpool);
為了支援上述規則,我們使用以下池名稱作為慣例來表示各種池的生命週期
result_pool
:函式輸出應配置其中的池。結果池宣告務必出現在函式引數清單中,且絕不可在區域區塊內。(但並非所有函式都需要或有結果池。)
scratch_pool
:函式所有區域資料應配置其中的池。此池也由呼叫者提供,呼叫者可以在控制權回傳給它時立即清除此池。
iterpool
:重複池,用於迴圈內,依據上述範例。
(注意:有些舊程式碼使用單一 pool
函式引數,它同時作為結果池和暫存池。)
透過使用 iterpool 迴圈限制資料,您可以確保 O(1) 而不是 O(N) 記憶體外洩,如果函式從迴圈中突然傳回 (例如,由於錯誤)。這就是為什麼您不應該為在函式中持續存在的資料建立子池,而應該使用呼叫者傳入的池。當呼叫者的池被清除或銷毀時,該記憶體將被回收。如果呼叫者在迴圈中呼叫被呼叫者,則相信呼叫者會在每次反覆運算中清除池。相同的邏輯會傳播到整個呼叫堆疊。
您使用的池也有助於程式碼的讀者了解物件生命週期。給定的物件是否只在迴圈的一次反覆運算中使用,還是需要持續到迴圈結束後?例如,池的選擇會顯示很多關於此程式碼中正在發生的事情
apr_hash_t *persistent_objects = apr_hash_make(result_pool); apr_pool_t *iterpool = svn_pool_create(scratch_pool); for (i = 0; i < n; ++i) { const char *intermediate_result; const char *key, *val; svn_pool_clear(iterpool); SVN_ERR(do_something(&intermediate_result, ..., iterpool)); SVN_ERR(get_result(intermediate_result, &key, &val, ..., result_pool)); apr_hash_set(persistent_objects, key, APR_HASH_KEY_STRING, val); } svn_pool_destroy(iterpool); return persistent_objects;
除了在這些原則完全被理解之前編寫的一些舊式程式碼外,Subversion 中幾乎所有池的使用都遵循上述準則。
其中一個此類舊式模式是傾向於在池中配置物件,將池儲存在物件中,然後釋放該池 (直接或透過 close_foo() 函式) 以銷毀物件。
例如
/*** Example of how NOT to use pools. Don't be like this. ***/
static foo_t *
make_foo_object(arg1, arg2, apr_pool_t *pool)
{
apr_pool_t *subpool = svn_pool_create(pool);
foo_t *foo = apr_palloc(subpool, sizeof(*foo));
foo->field1 = arg1;
foo->field2 = arg2;
foo->pool = subpool;
}
[...]
[Now some function calls make_foo_object() and returns, passing
back a new foo object.]
[...]
[Now someone, at some random call level, decides that the foo's
lifetime is over, and calls svn_pool_destroy(foo->pool).]
這很誘人,但它違背了使用池的宗旨,即不要太擔心個別配置,而要擔心整體效能和生命週期群組。相反,foo_t 通常不應該有 `pool` 欄位。只要在目前的池中配置您需要的 foo 物件數量即可,當該池被清除或銷毀時,它們將同時消失。
另請參閱 例外處理 部分,了解當池被銷毀時如何清除與池相關的資源的詳細資訊。
總之
物件不應該有自己的池。物件配置到由建構函式的呼叫者定義的池中。呼叫者知道物件的生命週期,並將透過池管理它。
函數不應建立/銷毀其運作的池,它們應使用呼叫者提供的池。同樣地,呼叫者更了解函數將如何使用、使用頻率、使用次數等,因此,它應負責函數的記憶體使用。
例如,想一下一個在緊密迴圈中多次呼叫的函數。呼叫者在每次反覆運算中清除暫存池。因此,建立內部子池是不必要的,而且可能造成顯著的負擔;函數應僅使用傳入的池。
每當發生無界反覆運算時,應使用反覆運算子池。
根據以上所有內容,將池傳遞給每個函數是相當必要的。由於物件不會為自己記錄池,而且呼叫者應始終管理記憶體,因此每個函數需要一個池,而不是依賴某些隱藏的魔法池。在有限的情況下,物件可能會記錄用於其建構的池,以便它們可以建構子部分,但應仔細檢查這些情況。
另請參閱 追蹤記憶體外洩,以取得診斷池使用問題的提示。
請務必使用 APR_STATUS_IS_...() 巨集檢查 APR 狀態碼(APR_SUCCESS 除外),而不是直接比較。這對於移植到非 Unix 平台是必要的。
好的,以下是如何在 Subversion 中使用例外。
例外儲存在 svn_error_t 結構中
typedef struct svn_error_t { apr_status_t apr_err; /* APR error value, possibly SVN_ custom err */ const char *message; /* details from producer of error */ struct svn_error_t *child; /* ptr to the error we "wrap" */ apr_pool_t *pool; /* place to generate message strings from */ const char *file; /* Only used iff SVN_DEBUG */ long line; /* Only used iff SVN_DEBUG */ } svn_error_t;
如果您是錯誤的原始建立者,您會執行類似下列動作
return svn_error_create(SVN_ERR_FOO, NULL, "User not permitted to write file");
請注意 NULL 欄位... 表示此錯誤沒有子項,即它是最低層的錯誤。
另請參閱 撰寫錯誤訊息 的區段。
Subversion 內部使用 UTF-8 來儲存其資料。這也適用於「訊息」字串。假設 APR 會以目前區域設定傳回其資料,因此 APR 傳回的任何文字都需要轉換為 UTF-8,才能包含在訊息字串中。
如果您收到錯誤,您有三個選擇
自行處理錯誤。使用您自己的程式碼,或僅呼叫原始 svn_handle_error(err)。(此常式會解除錯誤堆疊,並列印出將其從 UTF-8 轉換為目前區域設定的訊息。)
當您的常式收到它打算忽略或自行處理的錯誤時,請務必使用 svn_error_clear() 清除它。任何時候未清除此類錯誤,都會構成記憶體外洩。
傳回錯誤的函式不需要初始化其輸出參數。
向上擲出錯誤,不修改
error = some_routine(foo); if (error) return svn_error_trace(error);
實際上,更好的方法是使用 SVN_ERR() 巨集,它執行相同的工作
SVN_ERR(some_routine(foo));
向上擲出錯誤,將其包裝在新的錯誤結構中,方法是將其包含為「子項」引數
error = some_routine(foo); if (error) { svn_error_t *wrapper = svn_error_create(SVN_ERR_FOO, error, "Authorization failed"); return wrapper; }
當然,有一個便利常式會建立一個包裝器錯誤,其欄位與子項相同,但您的自訂訊息除外
error = some_routine(foo); if (error) { return svn_error_quick_wrap(error, "Authorization failed"); }
使用 SVN_ERR_W() 巨集可以(並且應該)執行相同的工作
SVN_ERR_W(some_routine(foo), "Authorization failed");
在案例 (b) 和 (c) 中,重要的是要知道由您的常式配置,且與池相關聯的資源會在池被銷毀時自動清除。這表示在傳遞錯誤之前不需要清除這些資源。因此,沒有理由不使用 SVN_ERR() 和 SVN_ERR_W() 巨集。與池相關聯的資源是
記憶體
檔案
使用 apr_file_open 開啟的所有檔案都會在池清除時關閉。Subversion 在其 svn_io_file_* api 中使用此函式,這表示使用 svn_io_file_* 或 apr_file_open 開啟的檔案會在池清除時關閉。
某些檔案(例如鎖定檔案)需要在作業完成時移除。APR 有 APR_DELONCLOSE 旗標可供此目的使用。下列函式會建立在池清除時移除的檔案
apr_file_open 和 svn_io_file_open(傳遞 APR_DELONCLOSE 標記時)
svn_io_open_unique_file(在 delete_on_close 中傳遞 TRUE 時)
如果使用 svn_io_file_lock 鎖定檔案,則會將鎖定的檔案解鎖。
當定義 SVN_ERR__TRACING
時,SVN_ERR()
巨集會建立包裝錯誤。這有助於開發人員判斷錯誤原因,並可以使用 --enable-maintainer-mode
選項在 configure
中啟用。
有時,您只想傳回呼叫函式傳回的任何內容,通常在您自己的函式結束時。避免直接傳回結果的誘惑
/* Don't do this! */ return some_routine(foo);
相反,使用 svn_error_trace 元函式傳回值。這可確保在啟用時正確執行堆疊追蹤。
return svn_error_trace(some_routine(foo));
就像幾乎任何其他程式語言一樣,C 有不良的功能,使攻擊者能夠以可預測的方式使您的程式失敗,通常對攻擊者有利。這些準則的目標是讓您了解 C 的陷阱,因為它們適用於 Subversion 專案。當檢閱同儕的程式碼時,建議您牢記這些陷阱,因為即使是最熟練和偏執狂的程式設計師也會偶爾犯錯。
輸入驗證是定義合法輸入並拒絕所有其他輸入的行為。程式碼必須對所有不受信任的輸入執行輸入驗證。
安全性界線
Subversion 伺服器程式碼中的安全性邊界必須標示出來,這樣審查員才能快速判斷邊界的品質。安全性邊界存在於執行中的程式碼可以存取使用者無法存取的資訊,或程式碼以高於提出要求使用者的權限執行時。此類型的典型範例是執行存取控制的程式碼或設定 SUID 位元的應用程式。
呼叫安全性邊界的函式必須包含傳遞引數的驗證檢查。本身就是安全性邊界的函式應該稽核收到的輸入,並在以不當值呼叫時發出警報。
[### todo:需要一些 Subversion 的範例...]
字串操作
使用 apr_strings.h 中提供的字串函式,而非會寫入字串的標準 C 函式庫函式。APR 函式較為安全,因為它們會自動進行邊界檢查和目標配置。儘管在理論上,於某些情況下使用純粹的 C 字串函式是安全的(例如,當您已知道來源和目標的長度時),請無論如何使用 APR 函式,如此一來,程式碼會較不易損壞且較易於檢閱。
密碼儲存
協助使用者保密其密碼:當用戶端在本地端讀取或寫入密碼時,它應該確保檔案模式為 0600。如果檔案可供其他使用者讀取,用戶端應該退出並顯示一則訊息,告知使用者變更檔案模式,以降低外洩風險。
某些資源需要銷毀,以確保應用程式的正確運作。此類資源包括檔案,特別是因為開啟的檔案無法在 Windows 上刪除。
撰寫建立並傳回串流的 API 時,這個串流在背景中可能會堆疊在檔案或其他串流上。為了確保串流所建立的資源能正確地銷毀,它必須正確地呼叫它所建立(擁有)的串流的解構函式。
最初在 https://svn.haxx.se/dev/archive-2005-12/0487.shtml 中,之後在 https://svn.haxx.se/dev/archive-2005-12/0633.shtml 中,這以更通用的條款討論了檔案、串流、編輯器和視窗處理常式。
正如 Greg Hudson 所說
經過考量,以下是我希望我們能做到的
- 從底層物件讀取或寫入的串流擁有該物件,也就是說,關閉串流會關閉底層物件(如果適用)。
- 建立串流的層級(函式或資料類型)負責關閉它,除非適用上述規則。
- 視窗處理常式被認為是一種特殊的串流,而傳遞最後的 NULL 視窗會被視為關閉串流。
如果您將 apply_textdelta 視為建立視窗處理常式,那麼我不認為我們相差太遠。svn_stream_from_aprfile 沒有擁有其子檔案,svn_txdelta_apply 錯誤地承擔了關閉傳遞給它的視窗串流的責任,而且可能還有一些其他偏差。
不過,上述規則有一個例外。當串流作為引數傳遞給函式時(例如:svn_client_cat2() 的「out」參數),該常式無法呼叫串流的解構函式,因為它沒有建立該資源。
如果 svn_client_cat2() 建立串流,它也必須呼叫該串流的解構函式。根據上述模型,該串流會呼叫「out」參數的解構函式。不過,這是錯誤的,因為銷毀「out」參數的責任在其他地方。
為了解決這個問題,至少在串流的情況下,引入了 svn_stream_disown()。此函式包裝串流,確保它不會被銷毀,即使堆疊在它上面的任何串流都可能會嘗試這麼做。
當您呼叫一個函式,它接受可變數目的參數,並預期清單以空指標常數終止(例如 apr_pstrcat),請不要使用 NULL 符號來終止清單。根據編譯器和平台,NULL 可能或可能不是指標大小的常數;如果不是,函式可能會讀取參數清單結束後面的資料。
請改用 SVN_VA_NULL(自 1.9 版在 svn_types.h 中定義),它保證是空指標常數。例如
return apr_pstrcat(cmd->temp_pool, "Cannot parse expression '", arg2, "' in SVNPath: ", expr_err, SVN_VA_NULL);
除了 GNU 標準,Subversion 使用這些慣例
當使用路徑或檔案名稱作為大多數 Subversion API 的輸入時,請務必使用 svn_dirent_internal_style() API 將它們轉換為 Subversion 的內部/正規形式。或者,當從 Subversion API 接收路徑或檔案名稱作為輸出時,請使用 svn_dirent_local_style() API 將它們轉換為您平台預期的形式。
只使用空白來縮排程式碼,絕不使用 tab。Tab 顯示寬度沒有標準化,而且使用空白的縮排更容易手動調整。
將程式碼限制在 79 個欄位,這樣程式碼才能在最小的標準顯示視窗中良好顯示。(可以有例外,例如在宣告一個 80 個欄位的文字區塊時,縮排、引號等佔用了一些額外的欄位,如果將每一行拆成兩行會過於混亂。)
所有已發佈的功能、變數和結構都必須以對應的函式庫名稱表示,例如 libsvn_wc 的 svn_wc_adm_open。所有在函式庫私有標頭檔(例如 libsvn_wc/wc.h)中所做的函式庫內部宣告都必須在函式庫前綴後加上兩個底線(例如 svn_wc__ensure_directory)。所有對單一檔案私有的宣告(例如 libsvn_wc/update_editor.c 內部的靜態函式 get_entry_url)不需要任何額外的命名空間裝飾。需要在函式庫外使用但仍非公開的符號會放入 include/private/ 目錄中的共用標頭檔,並使用雙底線表示法。此類符號僅能由 Subversion 核心程式碼使用。
回顧
/* Part of published API: subversion/include/svn_wc.h */ svn_wc_adm_open() #define SVN_WC_ADM_DIR_NAME ... typedef enum svn_wc_schedule_t ... /* For use within one library only: subversion/libsvn_wc/wc.h */ svn_wc__ensure_directory() #define SVN_WC__BASE_EXT ... typedef struct svn_wc__compat_notify_baton_t ... /* For use within one file: subversion/libsvn_wc/update_editor.c */ get_entry_url() struct handler_baton { /* For internal use in svn core code only: subversion/include/private/svn_wc_private.h */ svn_wc__entry_versioned()
在 Subversion 1.5 之前,需要在函式庫外使用的私有符號會放入公開標頭檔,並使用雙底線表示法。此做法已被廢棄,任何此類符號都是舊有的,為了 向後相容性 而維護。
在可能會列印出來(或以其他方式提供給)使用者的文字字串中,僅在路徑和其他可引用的項目周圍使用正向引號。例如
$ svn revert foo svn: warning: svn_wc_is_wc_root: 'foo' is not a versioned resource $
過去有很多字串在第一個引號使用反引號(`foo` 而不是 'foo'),但在某些字型中看起來很糟,而且也搞亂了一些人的自動突顯,因此我們決定一律使用正向引號。
如果您使用 Emacs,請在 .emacs 檔案中放入類似以下的內容,以便在需要時取得 svn-dev.el 和 svnbook.el
;;; Begin Subversion development section (defun my-find-file-hook () (let ((svn-tree-path (expand-file-name "~/projects/subversion")) (book-tree-path (expand-file-name "~/projects/svnbook"))) (cond ((string-match svn-tree-path buffer-file-name) (load (concat svn-tree-path "/tools/dev/svn-dev"))) ((string-match book-tree-path buffer-file-name) ;; Handle load exception for svnbook.el, because it tries to ;; load psgml, and not everyone has that available. (condition-case nil (load (concat book-tree-path "/src/tools/svnbook")) (error (message "(Ignored problem loading svnbook.el.)"))))))) (add-hook 'find-file-hooks 'my-find-file-hook) ;;; End Subversion development section
當然,您需要自訂路徑以符合您的設定。您也可以讓正規表示式對字串的比對更具選擇性;例如,一位開發人員表示
> Here's the regexp I'm using: > > "src/svn/[^/]*/\\(subversion\\|tools\\|build\\)/" > > Two things to notice there: (1) I sometimes have several > working copies checked out under ...src/svn, and I want the > regexp to match all of them; (2) I want the hook to catch only > in "our" directories within the working copy, so I match > "subversion", "tools" and "build" explicitly; I don't want to > use GNU style in the APR that's checked out into my repo. :-)
我們有一個傳統,不會以個別作者的名稱標記檔案(也就是說,我們不會在原始檔最上方放入「作者:foo」或「@作者 foo」這類的文字)。這是為了避免地盤主義——即使檔案只有一個作者,我們也希望確保其他人能自由地進行變更。如果有人看起來對檔案宣示了個人所有權,人們可能會不必要地猶豫。
在一個句子的結尾和下一個句子的開頭之間放置兩個空格。這有助於閱讀,並允許人們使用他們的編輯器的句子移動和操作命令。
在整個程式碼中還有許多其他不言而喻的慣例,只有當有人無意中沒有遵循它們時才會被注意到。只要試著對事情的執行方式保持敏銳的眼光,當有疑問時,請詢問。
每個提交都需要一個日誌訊息。
日誌訊息的預期受眾是已經熟悉 Subversion 但不一定熟悉此特定提交的開發人員。通常,當有人回去閱讀變更時,他不再記住該變更周圍的所有內容。即使他是變更的作者,這也是正確的!所有討論、郵件清單串聯和所有其他內容都可能被遺忘;變更內容的唯一線索來自日誌訊息和 diff 本身。人們也會驚人頻繁地重新檢視變更:例如,在原始提交幾個月後,現在變更正被移植到維護分支。
日誌訊息是變更的引言。
如果您正在分支上工作,請在您的日誌訊息前加上
On the 'name-of-branch' branch: (Start of your log message)
以一行指示變更的一般性質來開始您的日誌訊息,並在必要時加上一個描述性的段落。
這不僅有助於讓開發人員進入正確的心態來閱讀日誌訊息的其餘部分,而且還能很好地與「ASFBot」機器人配合使用,該機器人會將每個提交的第一行回顯到 IRC 等即時論壇中。(有關詳細資訊,請參閱 https://wilderness.apache.org/ )
如果提交只是一個檔案的一個簡單變更,那麼你可以放棄一般描述,直接進入詳細描述,採用以下所示的標準檔名然後符號格式。
在整個日誌訊息中,請使用完整的句子,而不是句子片段。片段通常較為含糊,而且寫出你的意思只需要多花幾秒鐘。某些片段,例如「文件修正」、「新檔案」或「新函式」是可以接受的,因為它們是標準慣用語,所有進一步的詳細資訊都應該出現在原始碼中。
日誌訊息應命名每個受影響的函式、變數、巨集、makefile 目標、語法規則等,包括在此提交中被移除的符號名稱。這有助於人們稍後搜尋日誌。不要將名稱隱藏在萬用字元中,因為 globbed 部分可能是其他人稍後搜尋的內容。例如,這是錯誤的
* subversion/libsvn_ra_pigeons/twirl.c (twirling_baton_*): Removed these obsolete structures. (handle_parser_warning): Pass data directly to callees, instead of storing in twirling_baton_*. * subversion/libsvn_ra_pigeons/twirl.h: Fix indentation.
稍後,當有人試圖找出「twirling_baton_fast」發生了什麼事時,如果他們只搜尋「_fast」,他們可能找不到它。更好的條目應該是
* subversion/libsvn_ra_pigeons/twirl.c (twirling_baton_fast, twirling_baton_slow): Removed these obsolete structures. (handle_parser_warning): Pass data directly to callees, instead of storing in twirling_baton_*. * subversion/libsvn_ra_pigeons/twirl.h: Fix indentation.
萬用字元在「handle_parser_warning」的描述中是可以的,但僅是因為這兩個結構在日誌條目的其他地方以全名提及。
你還應該在你的日誌訊息中包含屬性變更。例如,如果你要修改 trunk 上的「svn:ignore」屬性,你可以在日誌中放入類似這樣的內容
* trunk/ (svn:ignore): Ignore 'build'.
上述內容僅適用於您維護的屬性,不適用於由 Subversion 維護的屬性,例如「svn:mergeinfo」。
請注意,每個檔案都會取得自己的項目,並以「*」為前綴,且檔案內的變更會依符號分組,符號會列在括號中,後接冒號,再接描述變更的文字。請遵循此格式,即使只變更一個檔案,一致性不僅有助於閱讀,也能讓軟體自動為記錄項目著色。
上述內容的例外情況是,如果您在多個檔案中進行完全相同的變更,請在一個項目中列出所有變更的檔案。例如
* subversion/libsvn_ra_pigeons/twirl.c, subversion/libsvn_ra_pigeons/roost.c: Include svn_private_config.h.
如果所有變更的檔案都深入位於原始碼樹中,您可以透過在變更項目之前標示共用前綴,來縮短檔案名稱項目
[in subversion/bindings/swig/birdsong] * dialects/nightingale.c (get_base_pitch): Allow 3/4-tone pitch variation to account for trait variability amongst isolated populations Erithacus megarhynchos. * dialects/gallus_domesticus.c: Remove. Unreliable due to extremely low brain-to-body mass ratio.
如果您的變更與問題追蹤器中的特定問題相關,請在記錄訊息中包含類似「問題 #N」的字串,但請務必仍摘要說明變更的內容。例如,如果一個修補程式解決了問題 #1729,則記錄訊息可能是
Fix issue #1729: Don't crash because of a missing file. * subversion/libsvn_ra_ansible/get_editor.c (frobnicate_file): Check that file exists before frobnicating.
請嘗試將相關變更放在一起。例如,如果您建立 svn_ra_get_ansible2(),並捨棄 svn_ra_get_ansible(),則這兩項應在記錄訊息中彼此相鄰
* subversion/include/svn_ra.h (svn_ra_get_ansible2): New prototype, obsoletes svn_ra_get_ansible. (svn_ra_get_ansible): Deprecate.
對於大型變更或變更群組,請將記錄項目分組成以空白行分隔的段落。每個段落應是一組達成單一目標的變更,且每個群組應從一或兩句摘要變更的句子開始。當然,真正獨立的變更應在個別提交中進行。
請參閱歸功,了解如果您提交他人的修補程式,或提交他們建議的變更,該如何歸功於他人。
永遠不應需要日誌條目來理解目前的程式碼。如果您發現自己在日誌中寫下重要的說明,您應該仔細考慮您的文字是否實際上不屬於註解,與它說明的程式碼並列。以下是一個正確執行的範例
(consume_count): If `count' is unreasonable, return 0 and don't advance input pointer.
然後,在 `cplus-dem.c` 中的 `consume_count`
while (isdigit((unsigned char)**type)) { count *= 10; count += **type - '0'; /* A sanity check. Otherwise a symbol like `_Utf390_1__1_9223372036854775807__9223372036854775' can cause this function to return a negative value. In this case we just consume until the end of the string. */ if (count > strlen(*type)) { *type = save; return 0; }
這就是為什麼一個新函式,例如,只需要一個寫著「新函式」的日誌條目 --- 所有詳細資訊都應該在原始碼中。
您可以對命名所有已變更內容的需求做出常識性的例外。例如,如果您已做出需要在程式其餘部分進行微小變更的變更(例如,重新命名變數),您不必命名所有受影響的函式,您只需說「所有呼叫者已變更」。在重新命名任何符號時,請記得同時提到舊名稱和新名稱,以利追溯;請參閱 r861020 以取得範例。
一般來說,在透過搜尋識別碼輕鬆找到條目,以及透過詳盡無遺而浪費時間或產生無法讀取的條目之間存在緊張關係。使用上述準則和您的最佳判斷,並體貼您的開發人員夥伴。(另外,使用「svn log」來查看其他人如何撰寫他們的日誌條目。)
用於文件或翻譯的日誌訊息有較為寬鬆的準則。顯然不適用於命名每個符號的要求,而且如果變更只是翻譯等持續程序中的另一個增量,甚至不需要命名每個檔案。只需簡要摘要變更,例如:「馬達加斯加語翻譯的更多工作。」請用英文撰寫您的日誌訊息,以便參與專案的每個人都能了解您所做的變更。
如果您使用分支來「檢查點」您的程式碼,而且不認為它已準備好進行檢閱,請在日誌訊息的頂端放置某種通知,在「在『xxx』分支通知」之後,例如
*** checkpoint commit -- please don't waste your time reviewing it ***
而且如果該分支上的後續提交應該進行檢閱,請在日誌訊息中提供適當的「svn diff」命令,因為 diff 可能涉及該分支上的兩個非相鄰提交,而且檢閱者不應花時間找出它們是什麼。
以一致且可解析的方式記錄程式碼貢獻非常重要。這讓我們可以撰寫腳本找出積極貢獻者,以及他們的貢獻內容,這樣我們就能 快速找出潛在的新提交者。Subversion 專案使用日誌訊息中人類可讀但機器可解析的欄位來達成此目的。
提交他人撰寫的程式碼時,請在行首使用「Patch by: 」來標示作者
Fix issue #1729: Don't crash because of a missing file. * subversion/libsvn_ra_ansible/get_editor.c (frobnicate_file): Check that file exists before frobnicating. Patch by: J. Random <jrandom@example.com>
如果有多人撰寫程式碼,請將每個人列在不同的行中,並確保每個續行都以空白開頭。非提交者應列出姓名(如果已知)和電子郵件。完整和部分提交者應列出其在 COMMITTERS 中的正規使用者名稱(該檔案的最左欄)。此外,「me」是實際提交變更者的可接受簡寫。
Fix issue #1729: Don't crash because of a missing file. * subversion/libsvn_ra_ansible/get_editor.c (frobnicate_file): Check that file exists before frobnicating. Patch by: J. Random <jrandom@example.com> Enrico Caruso <codingtenor@codingtenor.com> jcommitter me
如果有人發現錯誤或指出問題,但並未撰寫程式碼,請使用「Found by: 」(或「Reported by: 」)標示其貢獻
Fix issue #1729: Don't crash because of a missing file. * subversion/libsvn_ra_ansible/get_editor.c (frobnicate_file): Check that file exists before frobnicating. Found by: J. Random <jrandom@example.com>
如果有人提出有用的建議,但並未撰寫程式碼,請使用「Suggested by: 」標示其貢獻
Extend the Contribulyzer syntax to distinguish finds from ideas. * www/hacking.html (crediting): Adjust accordingly. Suggested by: dlr
如果有人測試程式碼,請使用「Tested by: 」
Fix issue #23: random crashes on FreeBSD 3.14. Tested by: Old Platformer (I couldn't reproduce the problem, but Old hasn't seen any crashes since he applied the patch.) * subversion/libsvn_fs_sieve/obliterate.c (cover_up): Account for sieve(2) returning 6.
如果有人檢閱變更,請使用「Review by: 」(或「Reviewed by: 」,如果你喜歡的話)
Fix issue #1729: Don't crash because of a missing file. * subversion/libsvn_ra_ansible/get_editor.c (frobnicate_file): Check that file exists before frobnicating. Review by: Eagle Eyes <eeyes@example.com>
一個欄位可以有多行,而一個日誌訊息可以包含任何欄位組合
Fix issue #1729: Don't crash because of a missing file. * subversion/libsvn_ra_ansible/get_editor.c (frobnicate_file): Check that file exists before frobnicating. Patch by: J. Random <jrandom@example.com> Enrico Caruso <codingtenor@codingtenor.com> me Found by: J. Random <jrandom@example.com> Review by: Eagle Eyes <eeyes@example.com> jcommitter
貢獻的進一步詳細資訊應在對應欄位後面的括弧中列出。這樣的括弧總是套用於其正上方的欄位;在以下範例中,欄位已間隔開來以方便閱讀,但請注意,間隔是可選的,且對於解析並非必要
Fix issue #1729: Don't crash because of a missing file. * subversion/libsvn_ra_ansible/get_editor.c (frobnicate_file): Check that file exists before frobnicating. Patch by: J. Random <jrandom@example.com> (Tweaked by me.) Review by: Eagle Eyes <eeyes@example.com> jcommitter (Eagle Eyes caught an off-by-one-error in the basename extraction.)
目前,這些欄位
Patch by: Suggested by: Found by: Review by: Tested by:
是唯一官方支援的歸功欄位(「支援」表示腳本知道要尋找這些欄位),而且廣泛用於 Subversion 記錄訊息中。未來的欄位可能會是「VERB by: 」的形式,而且有時有人可能會使用聽起來很官方但實際上並非如此的欄位,例如有幾個「Inspired by: 」的實例。這些欄位是可以的,但請盡量使用官方欄位或括號旁註,而不是自己建立欄位。此外,當報告者已在問題中記錄時,請勿使用「Reported by: 」,而是直接參照問題。
檢閱 Subversion 現有的記錄訊息,以了解如何實際使用這些欄位。主幹工作副本頂端的這個指令會有幫助
svn log | contrib/client-side/search-svnlog.pl "(Patch|Review|Suggested) by: "
注意:在某些提交訊息中看到的「Approved by: 」欄位與這些歸功欄位完全無關,而且通常不會由腳本剖析。它只是用於指出誰核准了部分提交者的提交(在他們平常的區域之外),或(在合併至釋出分支的情況下)誰投票贊成合併變更的標準語法。
Subversion 儲存庫已鏡像至 https://github.com/apache/subversion/ 上的 GitHub。
有些使用者可能會在 GitHub 中建立拉取要求。如果程式碼提交至 Subversion 儲存庫,請務必在記錄訊息中包含文字,以自動關閉拉取要求
This fixes #NNN in GitHub
若要在不提交程式碼的情況下管理拉取要求,您的 GitHub 帳戶必須連線至您的 ASF ID,而且 ASF Infra 必須將 triager 角色指派給您的帳戶。
Greg Stein 為 Subversion 編寫了一個自訂建置系統,Subversion 一直在使用 `automake` 和遞迴 Makefile。現在它使用單一頂層 Makefile,從 Makefile.in 產生(在版本控制下保留)。`Makefile.in` 反過來包含 `build-outputs.mk`,由 `gen-make.py` 腳本從 `build.conf` 自動產生。因此,後兩者在版本控制下,但 `build-outputs.mk` 不在。
以下是 Greg 描述系統的原始郵件,後面有一些關於駭入它的建議
From: Greg Stein <gstein@lyra.org> Subject: new build system (was: Re: CVS update: MODIFIED: ac-helpers ...) To: dev@subversion.tigris.org Date: Thu, 24 May 2001 07:20:55 -0700 Message-ID: <20010524072055.F5402@lyra.org> On Thu, May 24, 2001 at 01:40:17PM -0000, gstein@tigris.org wrote: > User: gstein > Date: 01/05/24 06:40:17 > > Modified: ac-helpers .cvsignore svn-apache.m4 > Added: . Makefile.in > Log: > Switch over to the new non-recursive build system. >... Okay... this is it. We're now on the build system. "It works on my machine." I suspect there may be some tweaks to make on different OSs. I'd be interested to hear if Ben can really build with normal BSD make. It should be possible. The code supports building, installation, checking, and dependencies. It does *NOT* yet deal with the doc/ subdirectory. That is next; I figured this could be rolled out and get the kinks worked out while I do the doc/ stuff. Oh, it doesn't build Neon or APR yet either. I also saw a problem where libsvn_fs wasn't getting built before linking one of the test proggies (see below). Basic operation: same as before. $ ./autogen.sh $ ./configure OPTIONS $ make $ make check $ make install There are some "make check" scripts that need to be fixed up. That'll happen RSN. Some of them create their own log, rather than spewing to stdout (where the top-level make will place the output into [TOP]/tests.log). The old Makefile.am files are still around, but I'll be tossing those along with a bunch of tweaks to all the .cvsignore files. There are a few other cleanups, too. But that can happen as a step two. [ $ cvs rm -f `find . -name Makefile.rm` See the mistake in that line? I didn't when I typed it. The find returned nothing, so cvs rm -f proceeded to delete my entire tree. And the -f made sure to delete all my source files, too. Good fugging thing that I had my mods in some Emacs buffers, or I'd be bitching. I am *so* glad that Ben coded SVN to *not* delete locally modified files *and* that we have an "undel" command. I had to go and tweak a bazillion Entries files to undo the delete... ] The top-level make has a number of shortcuts in it (well, actually in build-outputs.mk): $ make subversion/libsvn_fs/libsvn_fs.la or $ make libsvn_fs The two are the same. So... when your test proggie fails to link because libsvn_fs isn't around, just run "make libsvn_fs" to build it immediately, then go back to the regular "make". Note that the system still conditionally builds the FS stuff based on whether DB (See 'Building on Unix' below) is available, and mod_dav_svn if Apache is available. Handy hint: if you don't like dependencies, then you can do: $ ./autogen.sh -s That will skip the dependency generation that goes into build-outputs.mk. It makes the script run quite a bit faster (48 secs vs 2 secs on my poor little Pentium 120). Note that if you change build.conf, you can simply run: $ ./gen-make.py build.conf to regen build-outputs.mk. You don't have to go back through the whole autogen.sh / configure process. You should also note that autogen.sh and configure run much faster now that we don't have the automake crap. Oh, and our makefiles never re-run configure on you out of the blue (gawd, I hated when automake did that to me). Obviously, there are going to be some tweaky things going on. I also think that the "shadow" builds or whatever they're called (different source and build dirs) are totally broken. Something tweaky will have to happen there. But, thankfully, we only have one Makefile to deal with. Note that I arrange things so that we have one generated file (build-outputs.mk), and one autoconf-generated file (Makefile from .in). I also tried to shove as much logic/rules into Makefile.in. Keeping build-outputs.mk devoid of rules (thus, implying gen-make.py devoid of rules in its output generation) manes that tweaking rules in Makefile.in is much more approachable to people. I think that is about it. Send problems to the dev@ list and/or feel free to dig in and fix them yourself. My next steps are mostly cleanup. After that, I'm going to toss out our use of libtool and rely on APR's libtool setup (no need for us to replicate what APR already did). Cheers, -g -- Greg Stein, http://www.lyra.org/
以下是給那些變更或測試組態/建置系統的人的一些建議
From: Karl Fogel <kfogel@collab.net> To: dev@subversion.tigris.org Subject: when changing build/config stuff, always do this first Date: Wed 28 Nov 2001 Yo everyone: if you change part of the configuration/build system, please make sure to clean out any old installed Subversion libs *before* you try building with your changes. If you don't do this, your changes may appear to work fine, when in fact they would fail if run on a truly pristine system. This script demonstrates what I mean by "clean out". This is `/usr/local/cleanup.sh' on my system. It cleans out the Subversion libs (and the installed httpd-2.0 libs, since I'm often reinstalling that too): #!/bin/sh # Take care of libs cd /usr/local/lib || exit 1 rm -f APRVARS rm -f libapr* rm -f libexpat* rm -f libneon* rm -f libsvn* # Take care of headers cd /usr/local/include || exit 1 rm -f apr* rm -f svn* rm -f neon/* # Take care of headers cd /usr/local/apache2/lib || exit 1 rm -f * When someone reports a configuration bug and you're trying to reproduce it, run this first. :-) The voice of experience, -Karl
建置系統是所有在主幹上工作的開發人員的重要工具。有時,對建置系統所做的變更對一位開發人員來說運作得很好,但無意間中斷了另一位開發人員的建置系統。
為了防止生產力損失,任何提交者(全部或部分)都可以立即還原任何建置系統變更,這些變更中斷了他們在所選平台上有效進行開發的能力,作為一般例行公事,不必擔心被指控反應過度。還原變更的提交訊息應包含說明備註,說明為何還原變更,包含足夠的詳細資料,以便在 dev@ 上開始討論問題,如果有人選擇回覆提交郵件。
但是,應小心不要進入「預設還原模式」。如果您能快速修復問題,請這麼做。如果不能,請停下來思考一分鐘。在您思考過後,仍然沒有解決方案,請繼續還原變更,並將討論帶到清單中。
變更還原後,由還原變更的原始提交者重新提交其原始變更的修復版本,如果根據還原提交者的理由,他們非常確定其新版本絕對已修復,或者在再次提交之前,提交已修改的版本供還原提交者測試。
有關如何使用和新增測試到 Subversion 的自動化測試架構的說明,請閱讀 subversion/tests/README 和 subversion/tests/cmdline/README。
ASF 基礎架構 團隊管理一個 BuildBot 建置/測試農場。Subversion 專案的 Buildbot 瀑布位於此處
有關建置服務的更多資訊,請前往 ci2.apache.org。
如果您想接收有關 buildbot 建置和測試失敗的通知,請訂閱 notifications@ 郵件清單。
Buildbot 在 Infra 儲存庫 中進行設定,特別是 subversion.py 檔案。
From: Karl Fogel <kfogel@collab.net> Subject: writing test cases To: dev@subversion.tigris.org Date: Mon, 5 Mar 2001 15:58:46 -0600 Many of us implementing the filesystem interface have now gotten into the habit of writing the test cases (see fs-test.c) *before* writing the actual code. It's really helping us out a lot -- for one thing, it forces one to define the task precisely in advance, and also it speedily reveals the bugs in one's first try (and second, and third...). I'd like to recommend this practice to everyone. If you're implementing an interface, or adding an entirely new feature, or even just fixing a bug, a test for it is a good idea. And if you're going to write the test anyway, you might as well write it first. :-) Yoshiki Hayashi's been sending test cases with all his patches lately, which is what inspired me to write this mail to encourage everyone to do the same. Having those test cases makes patches easier to examine, because they show the patch's purpose very clearly. It's like having a second log message, one whose accuracy is verified at run-time. That said, I don't think we want a rigid policy about this, at least not yet. If you encounter a bug somewhere in the code, but you only have time to write a patch with no test case, that's okay -- having the patch is still useful; someone else can write the test case. As Subversion gets more complex, though, the automated test suite gets more crucial, so let's all get in the habit of using it early. -K
SVN_DBG 除錯工具是一個 C 預處理器巨集,它將除錯輸出傳送至 stdout(預設)或 stderr,同時不干擾 SVN 測試套件。
它提供了一個除錯工具(例如 gdb)的替代方案,或者提供額外的資訊來協助使用除錯工具。它在無法使用除錯工具的情況下特別有用。
svn_debug 模組包含兩個除錯輔助巨集,它們會印出呼叫的檔案:行,以及 printf 型式的引數到 #SVN_DBG_OUTPUT
stdio 串流(預設為 #stdout)
SVN_DBG( ( const char *fmt, ...) ) /* double braces are neccessary */和
SVN_DBG_PROPS( ( apr_hash_t *props, const char *header_fmt, ...) )
控制 SVN_DBG 輸出
--enable-maintainer-mode
配置 svn,就會啟用 SVN_DBG。
SVN_DBG_QUIET
變數設定為 1。
SVN_DBG
和 SVN_DBG_PROPS
巨集的任何執行個體。(又稱:不要忘記在患者體內遺留手術刀!)
SVN_DBG 巨集定義和程式碼位於
顯示 SVN_DBG 巨集用法的範例修補程式
Index: subversion/libsvn_fs_fs/fs_fs.c =================================================================== --- subversion/libsvn_fs_fs/fs_fs.c (revision 1476635) +++ subversion/libsvn_fs_fs/fs_fs.c (working copy) @@ -2303,6 +2303,9 @@ get_node_revision_body(node_revision_t **noderev_p /* First, try a cache lookup. If that succeeds, we are done here. */ SVN_ERR(get_cached_node_revision_body(noderev_p, fs, id, &is_cached, pool)); + SVN_DBG(("Getting %s from: %s\n", + svn_fs_fs__id_unparse(id), + is_cached ? "cache" : "disk")); if (is_cached) return SVN_NO_ERROR;
顯示 SVN_DBG_PROPS 巨集用法的範例修補程式
Index: subversion/svn/proplist-cmd.c =================================================================== --- subversion/svn/proplist-cmd.c (revision 1475745) +++ subversion/svn/proplist-cmd.c (working copy) @@ -221,6 +221,7 @@ svn_cl__proplist(apr_getopt_t *os, URL, &(opt_state->start_revision), &rev, ctx, scratch_pool)); + /* this can be called with svn proplist --revprop -r <rev> */ + SVN_DBG_PROPS((proplist,"The variable apr_hash_t *proplist contains: ")); if (opt_state->xml) { svn_stringbuf_t *sb = NULL;
'mod_dav_svn.so' 包含主要的 Subversion 伺服器邏輯;它在 mod_dav 中作為模組執行,而 mod_dav 則在 httpd 中作為模組執行。如果 httpd 可能使用動態共用模組,您可能需要在 mod_dav_svn 中設定中斷點之前,先在 ~/.gdbinit 中 set breakpoint pending on。或者,您可以啟動 httpd,中斷它,設定中斷點,然後繼續
% gdb httpd (gdb) run -X ^C (gdb) break some_func_in_mod_dav_svn (gdb) continue
-X 開關等於 -DONE_PROCESS 和 -DNO_DETACH,這分別可確保 httpd 以單一執行緒執行,並保持連接到 tty。一旦它啟動,它就會靜候並等待要求;這時您按下 control-C 並設定中斷點。
您可能想要查看 Apache 的執行時間記錄
/usr/local/apache2/logs/error_log /usr/local/apache2/logs/access_log
以協助判斷可能出錯的地方,以及中斷點的設定位置。
或者,在工作副本中執行 ./subversion/tests/cmdline/davautocheck.sh --gdb,將使用該工作副本中的 mod_dav_svn 啟動 httpd。然後,您可以針對它執行個別的 Python 測試:./basic_tests.py --url=https://127.0.0.1:3691/。
ra_svn 中的錯誤通常會以下列不明確的錯誤訊息之一顯示
svn: Malformed network data svn: Connection closed unexpectedly
(第一個訊息也可能表示資料串流在隧道模式中因使用者點檔案或掛勾指令碼而損毀;請參閱 問題 #1145。)第一個訊息通常表示您必須偵錯用戶端;第二個訊息通常表示您必須偵錯伺服器。
使用 --disable-shared --enable-maintainer-mode 的建置偵錯 ra_svn 最為容易。使用後者的選項,錯誤訊息將會精確地告訴您中斷點的設定位置;否則,請在 marshal.c:vparse_tuple() 的結尾處查詢行號,該處會傳回「網路資料格式錯誤」錯誤。
若要偵錯用戶端,只需在 gdb 中將其拉起,設定中斷點,然後執行有問題的指令
% gdb svn (gdb) break marshal.c:NNN (gdb) run ARGS Breakpoint 1, vparse_tuple (list=___, pool=___, fmt=___, ap=___) at subversion/libsvn_ra_svn/marshal.c:NNN NNN "Malformed network data");
有幾項有用的資訊
回溯會精確地告訴您哪個通訊協定交換失敗。
「print *conn」會顯示連線緩衝區。read_buf、read_ptr 和 read_end 代表讀取緩衝區,可以顯示封送器正在檢視的資料。(由於 read_buf 通常不會在 read_end 處以 0 終止,請小心錯誤地假設緩衝區中有垃圾資料。)
格式字串決定封送器預期會看到什麼。
若要偵錯守護程式模式中的伺服器,請在 gdb 中將其拉起,設定中斷點(通常用戶端上的「連線意外關閉」錯誤表示伺服器上的「網路資料格式錯誤」錯誤,儘管它也可能表示核心傾印),然後使用「-X」選項執行它以提供單一連線
% gdb svnserve (gdb) break marshal.c:NNN (gdb) run -X
然後執行有問題的用戶端命令。從那裡開始,就像除錯用戶端一樣。
在通道模式下除錯伺服器比較麻煩。您需要在 svnserve 的 main() 附近加上類似「{ int x = 1; while (x); }」的內容,並將產生的 svnserve 放到伺服器上的使用者路徑中。然後開始一個作業,gdb 附加伺服器上的程序,「設定 x = 0」,並按需要逐步執行程式碼。
追蹤用戶端和伺服器之間的網路流量有助於除錯。有幾種方法可以進行網路追蹤(此清單並非詳盡無遺)。
在進行網路追蹤時,您可能需要停用壓縮功能,請參閱 servers 組態檔中的 http-compression 參數。
使用 Wireshark(以前稱為「Ethereal」)竊聽對話。
首先,請確定在同一個 wireshark 會話中的擷取之間,您按了「清除」,否則來自一個擷取的篩選器(例如,HTTP 擷取)可能會干擾其他擷取(例如,ra_svn 擷取)。
假設您已清除,然後
下拉「擷取」功能表,並選擇「擷取篩選器」。
如果要除錯 http://(WebDAV)通訊協定,則在彈出的視窗中,選擇「HTTP TCP 埠 (80)
」(這會產生篩選器字串「tcp 埠 http
」)。
如果要除錯 svn://(ra_svn)通訊協定,則選擇「新增」,為新的篩選器命名(例如,「ra_svn」),並在篩選器字串方塊中輸入「tcp 埠 3690
」。
完成後,按一下確定。
再次前往「擷取」功能表,這次選擇「介面」,並按一下適當介面旁的「選項」(您可能需要介面「lo」,表示「迴路」,假設伺服器會在與用戶端相同的機器上執行)。
取消勾選適當的核取方塊,以關閉混雜模式。
按一下右下角的開始按鈕開始擷取。
執行您的 Subversion 軟體用戶端。
在作業完成時按一下停止圖示(以太網路介面卡上方的紅色 X),或按一下擷取->停止。現在您已完成擷取。它看起來像是一長串的清單。
按一下通訊協定欄位進行排序。
然後,按一下第一個相關的列以選取它;通常這只是第一列。
按一下滑鼠右鍵,然後選取追蹤 TCP 串流。您將會看到 Subversion 軟體用戶端 HTTP 轉換的請求/回應配對。
上述說明適用於 Wireshark 的圖形版本(版本 0.99.6),不適用於稱為「tshark」的命令列版本(對應於「tethereal」,在 Wireshark 稱為 Ethereal 時)。
另一種方法是在 Subversion 軟體用戶端和伺服器之間設定一個記錄代理伺服器。執行此動作的一個簡單方法是使用 socat 程式。例如,若要記錄與 svnserve 執行個體的通訊,請執行下列命令
socat -v TCP-LISTEN:9630,reuseaddr,fork TCP4:localhost:svn
然後,使用 svn://127.0.0.1:9630/ 的 URL 基底執行您的 svn 命令;socat 會將來自埠 9630 的流量轉送至正常的 svnserve 埠(3690),並會將所有雙向流量列印至標準錯誤,並加上 < 和 > 符號作為前置詞以顯示流量的方向。
若要從加密的 https:// 連線記錄可讀的 HTTP,請執行一個使用 TLS 連線至伺服器的 socat 代理伺服器
socat -v TCP-LISTEN:9630,reuseaddr,fork OPENSSL:example.com:443
然後將其用作純文字 http:// 連線的代理程式
svn ls http://example.com/svn/repos/trunk \ --config-option servers:global:http-proxy-host=localhost \ --config-option servers:global:http-proxy-port=9630 \ --config-option servers:global:http-compression=no
socat 代理程式會記錄純文字 HTTP,同時與伺服器的所有網路流量都會使用 TLS 加密。
如果您正在除錯 http 客戶端/伺服器設定,可以使用網路除錯代理程式,例如 Charles 或 Fiddler。
設定好此類代理程式後,您需要設定 Subversion 以使用代理程式。這可以使用 servers 組態檔中的 http-proxy-host 和 http-proxy-port 參數來完成。您也可以使用這些選項在命令列中指定代理程式 --config-option 'servers:global:http-proxy-host=127.0.0.1' --config-option 'servers:global:http-proxy-port=8888'。
我們使用 APR 池,這使得我們不太可能出現嚴格意義上的記憶體外洩;我們分配的所有記憶體最終都會被清除。但有時操作會佔用比應有的更多記憶體;例如,檢出大型原始碼樹不應使用比檢出小型原始碼樹更多的記憶體。當發生這種情況時,通常表示我們正在從生命週期過長的池中分配記憶體。
如果您有喜愛的記憶體外洩追蹤工具,您可以使用 --enable-pool-debug (這將使每個池分配使用自己的 malloc()) 設定,安排在操作過程中退出,然後執行。如果不是,以下是另一種方法
使用 --enable-pool-debug=verbose-alloc 設定。務必重新建置所有 APR 和 Subversion,以便每個分配都能取得檔案和行資訊。
執行操作,將 stderr 導向檔案。希望您有大量的磁碟空間。
在檔案中,您會看到許多類似以下的列
POOL DEBUG: [5383/1024] PCALLOC ( 2763/ 2763/ 5419) \ 0x08102D48 "subversion/svn/main.c:612" \ <subversion/libsvn_subr/auth.c:122> (118/118/0)
您最關心的是第十個欄位(引號中的欄位),它會提供您建立此配置的檔案和行號。前往該檔案和行,並找出配置的生命週期。在上述範例中,main.c:612 表示此配置是在 svn 軟體用戶端的頂層配置中建立的。如果這是操作期間重複多次的配置,這表示記憶體外洩的來源。第十一欄位(括號中的欄位)會提供配置本身的檔案和行號。
Subversion 專案歡迎改善其網站。然而,這個程序並不只要在瀏覽器中按一下「另存新檔」,編輯並寄出變更即可。首先,許多頁面實際上是由三個以上的檔案組成,因此瀏覽器無法儲存正確呈現的副本。
因此,如果您計畫提交實質變更,我們建議您取得原始碼副本,並設定測試鏡像網站來檢查您的變更。
當然,對於小變更,通常只要視覺檢查修補程式就已足夠。
網站的原始碼可從 Subversion 儲存庫取得。若要瀏覽原始碼,請前往 https://svn.apache.org/repos/asf/subversion/site/
若要下載副本至 ~/projects/svn
(這是本頁面其餘部分使用的位置),請使用下列指令
mkdir -p ~/projects/svn cd ~/projects/svn svn co https://svn.apache.org/repos/asf/subversion/site/ site
如果你下載到其他位置,你將需要調整你的網路伺服器設定中的路徑以指向那裡。
Subversion 網站使用 伺服器端包含 (SSI) 在網路伺服器中組合網頁。這表示要驗證你可能想要做的任何變更,你需要透過連接到安裝在你系統上的伺服器的網路瀏覽器檢視相關網頁,可能是 Apache 2.2 或 Apache 2.4。
以下步驟應提供一個 Apache 虛擬主機,它可以在 Unix 類型的系統上正確呈現 Subversion 網站的本機副本。這可能會位於 /etc/apache2, /etc/httpd
或類似目錄中,具體取決於你的系統。這些說明已在 Apache 2.2 和 Apache 2.4 上進行測試。
/home/user/projects/svn/site
中site/publish
目錄作為主伺服器或虛擬主機的 DocumentRoot。mod_include.so
Options +Includes
AddOutputFilter INCLUDES .html
將所有內容組合在一起,範例虛擬主機設定如下
<VirtualHost *:8080> ServerAdmin webmaster@localhost DocumentRoot /home/user/projects/svn/site/publish <Directory /home/user/projects/svn/site/publish/> Options +Includes AddOutputFilter INCLUDES .html </Directory> ErrorLog ${APACHE_LOG_DIR}/error.log # Possible values include: debug, info, notice, warn, error, crit, # alert, emerg. LogLevel debug CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>
重新啟動或重新載入伺服器後,如果你使用以下連結,你應該會看到 Subversion 社群指南網站變更 頁面的副本:
http://127.0.0.1:8080/docs/community-guide/(none)#web_mirror
請驗證所有對網站進行重大變更的修補程式。
如果您已根據此頁面建議設定網站鏡像,請使用命令列來擷取您已變更頁面的正確呈現副本,方法為
wget http://127.0.0.1:8080/docs/community-guide/YOUR_CHANGED_PAGE.html
然後將產生的檔案上傳至 HTML 驗證器,例如 W3C 驗證器服務。
撰寫有關專案網頁的修補程式的記錄訊息時,例如
https://subversion.dev.org.tw/docs/community-guide/some_page.html#section-name
在記錄訊息中列出修補程式中修改的檔案名稱,相對於 site/
目錄,並列出已新增或修改的區段錨點,如下所示
* docs/community-guide/some_page.html (section-name): fixed issue xyz
如需 Subversion 修補程式需求的完整說明,請遵循專案 一般修補程式指南 和 記錄訊息指南。
以下建議是根據多年來使用 Subversion 郵件清單的經驗,並針對在這些清單上最常看到的問題提出說明。它不應被視為郵件清單禮儀的完整指南 —如果您需要,可以在網路上很輕易地 找到其中一個。
如果您在發布到我們的郵件清單時遵循這些慣例,您的文章更有可能被閱讀和回答。
如有疑問,請寄信至 users@subversion.apache.org,而非 dev@subversion.apache.org。users@ 清單上有許多經驗豐富的人員(包括一些 Subversion 維護人員) —他們可能能夠回答您的問題,或者如果您認為您已找到錯誤,他們可以判斷它是否為真正的錯誤。當您想建議新功能時,您甚至應該發布到 users@:許多功能建議都是之前討論過的想法,而 users@subversion.apache.org 郵件清單上的某個人通常能夠判斷您的建議是否屬於這種情況。
請不要在使用者@中無法獲得答案後,將其作為最後的手段發佈到 dev@。這兩個清單有不同的章程:使用者@是一個支援論壇,dev@是一個開發討論清單。當一個支援問題在使用者@中沒有得到解答時,這很不幸,但這並不表示這個問題適合在 dev@ 中提出。
當然,如果郵件是關於 Subversion 中可能的錯誤,並且在使用者@中沒有得到任何反應,那麼在 dev@ 中詢問是沒問題的 — 錯誤是一個開發主題。而程式碼修補程式應該始終直接發送到 dev@。
有時,當對某個主題非常熱衷時,很容易回應郵件串中的每則訊息。請不要這樣做。我們的郵件清單已經流量很高,而追蹤每則訊息只會增加雜訊。
相反地,請閱讀整個郵件串,仔細思考你要說什麼,選擇一則訊息來回覆,然後說明你的想法。偶爾回覆串中兩則不同的訊息可能是合理的,但僅在主題開始分歧時才這樣做。
請不要使用超過 72 個欄位的行。許多人使用 80 個欄位的終端機來閱讀他們的電子郵件。透過在 72 個欄位中撰寫文字,你可以留出空間讓引號字元在後續的回覆中加入,而不會強制重新換行文字。當然,72 個欄位的限制僅適用於訊息的散文部分。如果你要發佈程式碼修補程式,請參閱程式碼修補程式的區段。
有些郵件程式會進行一種自動換行,也就是在你撰寫郵件時,顯示器會顯示實際上不存在的換行符號。當郵件到達清單時,它不會有你認為它有的換行符號。如果你的郵件編輯器執行此操作,請尋找你可以調整的設定,以使其顯示真正的換行符號。
將每個句子的第一個字母大寫,並使用段落。如果您要顯示螢幕輸出或其他類型的範例,請將其偏移,使其與散文明顯分開。如果您沒有執行這些操作,您的郵件將會比原本的更難以閱讀,而且許多人根本不會費心閱讀。
回應清單文章時,請務必使用您的郵件閱讀器的「追蹤」、「回覆全部」或「群組回覆」功能。否則,您的郵件將只會寄給原始文章的作者,而不是寄給整個清單。除非有理由私下回覆,否則最好總是回覆清單,以便每個人都可以觀看並學習。(此外,許多經常收到對其文章的私人回應的人表示,他們希望這些回應改為寄給清單。)
請注意,Subversion 郵件清單不會修改 回覆至 標頭,以將回應重新導向至清單。他們會將 回覆至 設為原始寄件者設定的任何值,原因請參閱 https://www.unicom.com/pw/reply-to-harmful.html 中所列,特別是「最小損害原則」和「找不到回家的路」部分。偶爾,有人會發文詢問我們為何不設定 回覆至 標頭。有時候,那個人會提到 https://marc.merlins.org/netrants/reply-to-useful.html,其中提供了修改 回覆至 欄位的論點。清單管理員知道這兩份文件,並認為論點的雙方都有其優點,但最後決定不修改 回覆至 標頭。請不要再提起這個話題。
請勿透過回覆現有文章來開始新的討論串(主旨)。請改為開始一封新的郵件,即使這表示您必須手動寫出清單地址。如果您回覆現有文章,您的郵件閱讀器可能會包含將您的文章標記為該討論串中後續文章的元資料。變更 主旨 標頭不足以防止這件事!許多郵件閱讀器仍會保留足夠的元資料,將您的文章放入錯誤的討論串中。如果發生這種情況,不僅有些人看不到您的文章(因為他們忽略了該討論串),而且正在閱讀該討論串的人也會浪費時間在您離題的文章上。避免這種情況最安全的方法是,永遠不要使用「回覆」來開始新的主題。
(問題的根源實際上是,有些郵件介面並未指出「回覆」功能所產生的訊息與新訊息之間的差異。如果您使用此類程式,請考慮向其開發人員提交增強要求或補丁程式,以顯示差異。)
如果您確實需要在保留討論串的同時變更 主旨 標頭(可能是因為討論串已轉移到其他主題),請透過在括號中加上舊主旨的新主旨發布文章,如下所示
Blue asparagus | |_ Re: Blue asparagus | |_ Yellow elephants (was: Re: Blue asparagus) <-- ### switch ### | |_ Re: Yellow elephants
請不要反射性地責備他人頂部發文。「頂部發文」是指將回覆文字置於引文文字上方,而不是穿插其中或置於其下方。通常,引文文字會提供理解回覆文字的基本背景,因此頂部發文會造成阻礙。有時,人們會在應該穿插發文或底部發文時頂部發文,而其他人會因此責備他們。如果你必須責備,請溫和地進行,而且絕對不要為了指出像這樣的小問題而額外發文。甚至在某些情況下,頂部發文是較好的選擇,例如,當回覆簡短且一般,且適用於長篇引文文字的整體時。因此,頂部發文總是需要判斷,而且即使在不適當的情況下進行,它也不是什麼大不便。
如果你來這裡是為了尋求如何引用的建議,而不是如何不因他人糟糕的引用習慣而生氣的建議,請參閱 https://www.netmeister.org/news/learn2quote.html(德語:http://www.afaik.de/usenet/faq/zitieren/download/zitieren-alles.html)。
請參閱 這裡,以取得關於如何傳送修補程式的建議。請注意,你可以傳送修補程式來修改這些網頁,以及修改程式碼;網頁的儲存庫網址為 https://svn.apache.org/repos/asf/subversion/site/。
請盡可能使用 ASCII 或 ISO-8859 文字。不要發佈 HTML 郵件、RichText 郵件或其他可能對純文字郵件閱讀器不透明的格式。關於語言:我們沒有僅限英文的政策,但你可能會透過以英文發文獲得最佳結果,因為它是名單參與者中最多人共用的語言。
Subversion 並非完美的軟體。它包含錯誤、缺乏功能,且有進步的空間,就像其他任何軟體一樣。與大多數軟體專案一樣,Subversion 專案使用問題追蹤工具來管理已知的軟體未解決問題。但或許與大多數軟體專案不同的是,我們試著讓我們的問題追蹤器相對沒有垃圾。這並不是說我們不希望聽到 Subversion 的問題,畢竟,我們無法修復我們不知道已損壞的部分。只是我們發現管理不善的問題追蹤器會造成更多阻礙,而不是幫助。
這封郵件幾乎說明了一切(除了現在您應該在發佈到 dev@ 清單之前發佈到 users@ 清單)
From: Karl Fogel <kfogel@collab.net> Subject: Please ask on the list before filing a new issue. To: dev@subversion.tigris.org Date: Tue, 30 Jul 2002 10:51:24 (CDT) Folks, we're getting tons of new issues, which is a Good Thing in general, but some of them don't really belong in the issue tracker. They're things that would be better solved by a quick conversation here on the dev list. Compilation problems, behavior questions, feature ideas that have been discussed before, that sort of thing. *Please* be more conservative about filing issues. The issues database is physically much more cumbersome than email. It wastes people's time to have conversations in the issues database that should be had in email. (This is not a libel against the issue tracker, it's just a result of the fact that the issues database is for permanent storage and flow annotation, not for real-time conversation.) If you encounter a situation where Subversion is clearly behaving wrongly, or behaving opposite to what the documentation says, then it's okay to file the issue right away (after searching to make sure it isn't already filed, of course!). But if you're a) Requesting a new feature, or b) Having build problems, or c) Not sure what the behavior should be, or d) Disagreeing with current intended behavior, or e) Not TOTALLY sure that others would agree this is a bug, or f) For any reason at all not sure this should be filed, ...then please post to the dev list first. You'll get a faster response, and others won't be forced to use the issues database to have the initial real-time conversations. Nothing is lost this way. If we eventually conclude that it should be in the issue tracker, then we can still file it later, after the description and reproduction recipe have been honed on the dev list. Thank you, -Karl
以下是我們要求大家在報告問題或要求對 Subversion 進行增強時遵守的政策。
首先,確定這是一個錯誤。如果 Subversion 沒有按照您的預期執行,請在文件和郵件清單檔案中尋找證據,證明它應該按照您的預期執行。當然,如果這是常識,例如 Subversion 剛剛毀損了您的資料並導致您的顯示器冒出煙霧,那麼您可以相信自己的判斷。但如果您不確定,請先在使用者郵件清單 users@subversion.apache.org 上詢問,或在 IRC irc.libera.chat,頻道 #svn(網路介面 或 Matrix)中詢問。
您還應該在錯誤追蹤器中搜尋,看看是否有人已經報告此錯誤。
一旦你確定這是個錯誤,而且我們還不知道,你可以做的最重要的事情就是提出一個簡單的說明和重現步驟。例如,如果你最初發現的錯誤涉及到十次提交的五個檔案,請嘗試只用一個檔案和一次提交來重現它。重現步驟越簡單,開發人員成功重現錯誤並修復它的可能性就越大。
當你寫下重現步驟時,不要只寫下你讓錯誤發生的步驟文字說明。相反地,提供你執行的一系列確切命令的逐字記錄,以及它們的輸出。使用剪下和貼上來執行此操作。如果涉及到檔案,請務必包含檔案名稱,甚至包含你認為可能相關的內容。最好的方法是將你的重現步驟打包成一個腳本;這對我們很有幫助。以下是一個此類腳本的範例:repro-template.sh 適用於類 Unix 系統和 Bourne shell,或 repro-template.bat 適用於 Windows shell(由 Paolo Compieta 提供);我們歡迎為其他系統提供類似的範本腳本。
快速健全性檢查:你*正在*執行最新版本的 Subversion,對吧? :-) 錯誤可能已經修復;你應該針對最新的 Subversion 開發樹測試你的重現步驟。
除了重現步驟之外,我們還需要你重現錯誤的環境的完整說明。這表示
當您擁有所有這些資訊後,您就可以準備撰寫報告。從清楚描述錯誤是什麼開始。也就是說,說明您預期 Subversion 的行為,並與其實際行為進行對比。雖然錯誤對您來說可能很明顯,但對其他人來說可能並不那麼明顯,因此最好避免猜謎遊戲。接著說明環境描述和重現步驟。如果您還想包含對原因的推測,甚至修復錯誤的修補程式,那就太好了 — 請參閱修補程式提交指南。
將所有這些資訊發佈到 dev@subversion.apache.org,或者如果您已經在那裡並被要求提交問題,請前往問題追蹤器並按照那裡的說明進行操作。
謝謝。我們知道提交有效的錯誤報告需要大量工作,但一份好的報告可以節省開發人員數小時的時間,並讓錯誤更有可能獲得修復。
如果錯誤出在 Subversion 本身,請寄信至 users@subversion.apache.org。一旦確認為錯誤,便會有人(可能是你)將其輸入 問題追蹤器 中。(或者如果你相當確定這是錯誤,請直接發布到我們的開發人員清單 dev@subversion.apache.org。但如果你不確定,最好先發布到 users@;那邊有人可以告訴你遇到的行為是否預期。)
如果錯誤出現在 APR 函式庫中,請向以下兩個郵件清單報告:dev@apr.apache.org、dev@subversion.apache.org。
如果錯誤出現在 Neon HTTP 函式庫中,請向以下郵件地址報告:neon@webdav.org、dev@subversion.apache.org。
如果錯誤出現在 Apache Serf HTTP 函式庫中,請向以下郵件地址報告:dev@serf.apache.org、dev@subversion.apache.org。
如果錯誤出現在 Apache HTTPD 2.x 中,請向以下兩個郵件清單報告:dev@httpd.apache.org、dev@subversion.apache.org。Apache httpd 開發人員郵件清單流量很高,因此你的錯誤報告貼文可能會被忽略。你也可以在 https://apache-httpd.dev.org.tw/bug_report.html 提交錯誤報告。
如果錯誤出現在你的地毯上,請給它一個擁抱並保持舒適。
問題追蹤里程碑是 Subversion 開發人員組織其工作並與彼此和 Subversion 使用者群組溝通的重要面向。除了在執行高階問題分類時主要使用的一些里程碑外,專案的問題追蹤里程碑傾向以反映版本號碼及其變異來命名。里程碑會依問題的狀態用於略有不同的目的,因此了解這些區別非常重要。
對於開啟的問題(狀態為 OPEN、IN PROGRESS 或 REOPENED 的問題),里程碑表示開發人員針對該問題解決方案所鎖定的 Subversion 版本。一般來說,我們使用 次要版本-consider 形式的里程碑來表示問題的解決方案正被考慮作為我們希望在 次要版本.0 中發布的項目。例如,我們認為可以且應該新增到 Subversion 1.9.0 的功能將獲得 1.9-consider 里程碑。出於顯而易見的原因,這些發布目標的準確性會隨著時間推移而越來越差,因此鼓勵使用者不要將它們視為開發人員社群具有約束力的承諾。
在任何時間點,社群中都會有「下一個重大版本」的工作正在進行。當該版本開始成形時,開發人員會更了解哪些問題是該版本的「必須具備」功能(也稱為「版本阻礙因素」)、哪些是「很不錯的附加功能」,以及哪些功能應該完全延後到未來的版本。問題里程碑是使用來傳達這些決策結果的機制。被視為版本阻礙因素的問題會從 次要版本-考慮 里程碑移到 次要版本.0 里程碑;「很不錯的附加功能」會保留在 次要版本-考慮 里程碑;而從版本延後的問題會重新設定里程碑為 另一個次要版本-考慮 或 未排程,這取決於我們是否明確預測何時會處理該問題。
延續前一個範例,隨著 Subversion 1.9.0-to-be 的開發進度,開發人員會評估我們計畫在該版本中推出的功能。如果我們認為不應該在沒有該功能的情況下發布 Subversion 1.9,我們會將其里程碑從 1.9-考慮 變更為 1.9.0;如果我們希望在有該功能的情況下發布,但不想承諾,我們會將里程碑保留為 1.9-考慮;如果我們很清楚我們不會在 1.9.x 發行系列中實作該功能,我們會將問題重新設定里程碑為其他內容(例如 1.10-考慮)。
次要版本.0 里程碑的準確性非常重要,因為開發人員傾向於在重大版本週期的最後幾天使用這些問題來集中他們的精力。
對於已修正問題(狀態為 已解決 且解決方案為 已修正),問題里程碑會採用新的實用功能:追蹤最先包含該問題解決方案的 Subversion 發行版本。無論給定問題的目標發行版本為何,一旦問題已解決,其里程碑就應該反映最先包含該解決方案的發行的確切版本號碼。
對於其他已關閉的問題(那些不是「開放」且並未真正「已修正」的問題),問題里程碑往往幾乎沒有意義。當問題本身因為是重複的,或因為是無效或不準確的報告而實際上被忽略時,嘗試維護該追蹤器欄位幾乎沒有意義。
在這些狀態之間轉換問題時必須小心。已解決的開放問題需要調整其里程碑,以反映將首先反映該變更的 Subversion 版本。已回溯移植到先前版本串流的已解決問題需要調整其里程碑,以指向該先前版本的版本號碼。最後,已解決但已 重新開啟 的問題需要重新評估其里程碑,以確定問題是否為版本阻斷器 (次要版本.0) 或不是 (次要版本-考慮)。在這種情況下,可以諮詢問題的變更歷程,以查看在問題已解決並已修正之前使用了哪個里程碑。
當問題提交時,它會進入特殊里程碑「---」,表示未設定里程碑。這是一個暫存區,問題會保留在其中,直到有人有機會查看問題並決定如何處理。
當您按里程碑排序時,未設定里程碑的問題會首先列出,而問題分類是瀏覽所有 開放問題(從未設定里程碑的問題開始)的程序,確定哪些問題重要到現在就必須修正,哪些可以等到另一個版本,哪些是現有問題的重複,哪些已經解決,等等。對於每個仍保持開放的議題,這也表示必須確保適當地設定各種欄位:類型、子元件、平台、作業系統、版本、關鍵字(如果有),等等。
以下是程序的概述(在此範例中,1.5 是下一個版本,因此緊急問題會轉到該版本)
for i in issues_marked_as("---"): if issue_is_a_dup_of_some_other_issue(i): close_as_dup(i) elif issue_is_invalid(i): # A frequent reason for invalidity is that the reporter # did not follow the "buddy system" for filing. close_as_invalid(i) elif issue_already_fixed(i): version = fixed_in_release(i) move_to_milestone(i, version) close_as_fixed(i) elif issue_unreproducible(i): close_as_worksforme(i) elif issue_is_real_but_we_won't_fix_it(i): close_as_wontfix(i) elif issue_is_closeable_for_some_other_reason(i): close_it_for_that_reason(i) # Else issue should remain open, so DTRT with it... # Set priority, environment, component, etc, as needed. adjust_all_fields_that_need_adjustment(i) # Figure out where to put it. if issue_is_a_lovely_fantasy(i): move_to_milestone(i, "blue-sky") if issue_is_not_important_enough_to_block_any_particular_release(i): move_to_milestone(i, "nonblocking") elif issue_resolution_would_require_incompatible_changes(i): move_to_milestone(i, "2.0-consider") elif issue_hurts_people_somewhat(i): move_to_milestone(i, "1.6-consider") # or whatever elif issue_hurts_people_a_lot(i): move_to_milestone(i, "1.5-consider") elif issue_hurts_and_hurts_and_should_block_the_release(i): move_to_milestone(i, "1.5")
本文件提供有關 Subversion 開發人員如何回應安全性問題的資訊。若要回報問題,請參閱 安全性回報說明。
Subversion 的首要任務是確保資料安全。為了達成此目的,Subversion 開發社群非常重視安全性。我們展現此決心的方法之一是不假裝自己是密碼學或安全性專家。我們不為 Subversion 編寫一堆專有的安全性機制,而是教導 Subversion 與由該領域知識人士提供的安全性函式庫和通訊協定進行互操作。例如,Subversion 將線路加密委託給 OpenSSL 等程式。它將驗證和基本授權委託給 Cyrus SASL 或 Apache HTTP Server 及其豐富的模組所提供的機制。只要我們能透過使用第三方提供的函式庫和 API 來利用安全性專家的知識,我們就會繼續這麼做。
本文件說明我們在收到或發現可能被歸類為具有安全性影響的問題時採取的步驟,其用意是補充 Apache 指南 中針對相同問題提供的承諾。
安全性問題應在 private@subversion.apache.org + security@apache.org 討論。security@subversion.apache.org 是針對這兩個清單的方便別名。(請注意,與 security@httpd.a.o 不同,它不是郵寄清單,因此您無法單獨訂閱/取消訂閱它。)
我們在以下位置發布先前安全性公告清單:https://subversion.dev.org.tw/security/
我們在 PMC 的私人儲存庫中追蹤進行中的問題:https://svn.apache.org/repos/private/pmc/subversion/security
此文件通常可以分為三個部分,依據具體性遞增
Subversion 發行管理員使用一套步驟,編碼在名為 release.py 的 Python 程式碼中。此程式碼可用於執行發行程序中大多數的自動化步驟。使用 -h 選項執行它以取得更多資訊。
除了下列專案特定指南外,有志成為發行管理員的人員可能也想要閱讀一般 Apache 發行政策。它們有時看起來有點拼湊,但能提供一般最佳實務和 Subversion 在較大的 ASF 生態系統中如何運作的良好概念。
Subversion 使用「MAJOR.MINOR.PATCH」發行編號。我們不使用「偶數 == 穩定,奇數 == 不穩定」慣例;任何不帶限定詞的三元組都表示穩定發行
1.0.1 --> first stable patch release of 1.0 1.1.0 --> next stable minor release of 1.x after 1.0.x 1.1.1 --> first stable patch release of 1.1.x 1.1.2 --> second stable patch release of 1.1.x 1.2.0 --> next stable minor release after that
發行的順序是半非線性的 — 1.0.3 可能在 1.1.0 之後推出。但它只是「半」非線性,因為我們最終會宣告一個修補程式線已失效,並告訴人們升級到下一個次要發行,因此從長遠來看,編號基本上是線性的。
數字可能有多位數。例如,1.7.19 是 1.7.x 線中的第十九個修補程式發行;它在 1.7.2 之後三年,在 1.7.20 之前三個月發行。
Subversion 發行可能會在版本號之後加上文字限定詞,這些文字限定詞都代表發行前程序中的各種步驟。從最不穩定到最穩定
限定詞 | 意義 | 範例 | svn --version 的輸出 |
---|---|---|---|
Alpha | 我們知道或預期會有問題,但徵求有興趣的個人進行測試。 | subversion-1.7.0-alpha2 | 版本 1.7.0(Alpha 2) |
Beta | 我們不預期會有問題,但還是小心為妙。 | subversion-1.7.0-beta1 | 版本 1.7.0(Beta 1) |
RC(候選版本) | 此版本是候選版本,準備成為最終建議版本。如果沒有發現嚴重錯誤,-rc 標籤將會移除,且此版本的內容將宣告穩定。 | subversion-1.7.0-rc4 | 版本 1.7.0(候選版本 4) |
當您「make install」subversion-1.7.0-rc1 時,它仍然會安裝為「1.7.0」,這是理所當然的。限定詞是版本中的元資料;我們希望每個後續的預發行版本覆寫前一個版本,而最終版本覆寫最後一個預發行版本。
對於工作副本建置,沒有 tarball 名稱需要擔心,但「svn --version」仍然會產生特殊輸出
version 1.7.1-dev (under development)
版本號碼是專案正在進行中的下一個版本。重要的是要說「開發中」。這表示建置來自工作副本,這在錯誤報告中很有用。
當我們希望新功能在我們進入正式的 穩定期 之前獲得廣泛測試時,我們有時會發行 alpha 和 beta tarball。即使有「alpha1」、「alpha2」等版本,也不需要進行任何 beta 版本;我們可以跳到「rc1」。然而,在某些情況下,beta 版本會很有用:例如,如果我們不確定 UI 決策,並希望在將其納入正式候選版本之前獲得更廣泛的使用者回饋。
Alpha 和 beta 版本僅適用於想要協助測試且了解在最終版本之前可能會有不相容變更的人。簽署需求由發行管理員決定。通常,RM 只會要求每個平台 1 或 2 個簽署,並告訴簽署者,只要他們認為程式碼夠穩定,值得其他人測試,即使他們的測試顯示出小錯誤,他們仍然可以簽署。RM 應要求簽署者在簽署時附上任何錯誤的說明,以便在宣布 alpha 或 beta 版本時可以發布這些問題。
當 alpha 或 beta 公開宣佈時,應堅決警告發行套件打包者不要打包它。請參閱 Hyrum K. Wright 的這封郵件,以取得良好的範例。
我們的相容性規則(如下所述 詳述)僅在經過認可和發布最終 x.y.0 版本後才開始適用。出現在 trunk 或 alpha/beta/rc 預發布中的任何 API、通訊協定和磁碟格式均不受 任何 相容性承諾約束;如果我們發現有充分的理由,我們可能會在最終發布之前任意變更它們。我們甚至可能會完全移除我們不滿意的介面或序列化格式。
這對於持久資料(工作副本和儲存庫)來說特別是一個問題,因為我們可能不會在最終發布中提供升級路徑(舊版格式的程式碼路徑或指定腳本)。(當然,我們可能會為測試我們預發布版本的開發人員和使用者提供此類腳本;但我們沒有義務這樣做。)因此,預發布版本絕不應該被信任為任何用於長期安全保存的資料。
同時,我們希望提醒讀者,指出 API 設計錯誤的最佳時機是在它們發布並固定之前,換句話說,是在初始設計和預發布階段。
如果由於某些非程式碼問題(例如,封裝故障)需要快速重新發布發布或候選發布,只要 tarball 尚未 經過簽章認可,就可以重複使用相同的名稱。但是,如果它已上傳到標準發行區域並附有簽章,或者重新發布是基於使用者可能執行的程式碼變更,則必須捨棄舊名稱並使用下一個名稱。
如果在準備發佈的 tarball 發佈並宣布給使用者之前,舊名稱被捨棄,則捨棄的名稱會被視為非公開發佈,且文件(例如 CHANGES 和標籤的記錄訊息)應更新以反映這一點。(請參閱 1.8.7 以取得範例。)捨棄發佈的標籤和 tarball 會保留在儲存庫記錄中,但它們不受一般使用支援(相反地,它們已知有發佈阻擋錯誤)。
Subversion 遵循嚴格的相容性,其準則與 APR 相同(請參閱 https://apr.apache.org/versioning.html),加上一些稍後說明的延伸。這些準則用於確保各種形式的用戶端/伺服器互通性,並確保使用者在 MAJOR.MINOR Subversion 版本之間有明確的升級路徑。
相容性可以跨越許多軸:從 API 和 ABI 到命令列輸出格式。我們嘗試平衡修改現有架構以支援新功能的需求,同時在最大可能範圍內支援目前的使用者。一般概念是
在同一個 MAJOR.MINOR 行中不同修補程式版本之間升級/降級絕不會中斷程式碼。它可能會導致錯誤修正消失/重新出現,但 API 簽章和語意保持不變。(當然,語意可能會以適於錯誤修正的微不足道方式改變,但不會以強迫呼叫程式碼調整的方式改變。)
升級到同一個主要版本中的新次要版本可能會導致出現新的 API,但不會移除任何 API。寫入舊次要號碼的任何程式碼都將與該行中任何後續的次要號碼搭配使用。但是,如果已撰寫利用新 API 的新程式碼,則事後降級可能無法運作。
(偶爾會發現錯誤,需要稍微修改舊 API 的行為。這通常只會在各種特殊情況和其他不常見的區域中表現出來。這些變更會記錄為 API 勘誤表,針對每個 MAJOR.MINOR 版本。)
當主要版本號碼變更時,所有賭注都取消。這是唯一一次可以完全重設 API 的機會,雖然我們會盡量不移除介面,但我們會利用它來稍微清理一下。
Subversion 擴充 APR 指南,以涵蓋用戶端/伺服器相容性問題
伺服器(或用戶端)的修補程式或次要版本號碼版本絕不會破壞與同一主要版本中的用戶端(或伺服器)的相容性。不過,版本提供的最新功能可能在未對連線的另一端進行相應升級的情況下不受支援。特別是更新 ra_svn 程式碼時,請遵守下列原則
可以將欄位新增至任何組;舊用戶端會直接忽略它們。(目前,封送實作不允許您將數字或布林值放在組的選用部分,但變更此設定並不會影響通訊協定。)
當資訊新增至 API 呼叫時,我們可以使用此機制。
在連線建立時間,用戶端和伺服器會交換功能關鍵字清單。
我們可以使用此機制進行更複雜的變更,例如引入管線化或從 API 呼叫中移除資訊。
可以新增新的指令;嘗試使用不受支援的指令會導致錯誤,可以檢查並處理該錯誤。
協定版本號碼可以升級,以允許優雅地拒絕舊客戶端或伺服器,或允許客戶端或伺服器偵測它必須以舊方式執行作業的時間。
此機制是最後的手段,在功能關鍵字難以管理時使用。
工作副本和儲存庫格式在同一個次要系列的所有修補程式版本中,具有向後和向前相容性。它們在同一個主要系列的所有次要版本中具有向前相容性;然而,次要版本允許建立一個工作副本或儲存庫,該工作副本或儲存庫無法與先前的次要版本搭配使用,其中「建立」可能表示「升級」以及「建立」。
Subversion 不會散發二進位套件,而是依賴 第三方套件封裝器來執行此作業。幸運的是,許多個人和公司已自願在這方面提供協助,我們感謝他們的付出。
如果您是第三方封裝者,您可能會遇到某些情況,例如錯誤修正或其他變更對您的使用者很重要,而且您想要比標準 Subversion 發行週期更快地讓他們取得這些變更。或者您可能會在本地維護一組修補程式,這些修補程式對您的目標受眾有益。如果可能,建議使用修補程式程序,並讓您的變更獲得接受並套用至主幹,以便在正常的 Subversion 發行時程中發布。
但是,如果您覺得您需要進行 Subversion 開發人員社群不會廣泛接受的變更,或需要提供對未發布功能的早期存取,您應該遵循下列準則。這些準則旨在協助防止使用者社群產生混淆,並讓您的發行和官方 Subversion 發行都盡可能成功。
首先,請務必遵循ASF 商標政策。您需要將您的發行與標準 Subversion 發行區分開來,以減少您的自訂發行可能造成的任何混淆。
其次,考慮在公開的 Subversion 儲存庫中建立一個分支,以追蹤您的變更,並讓您的自訂變更有可能併入 Subversion 主線。(如果您還沒有,請要求提交存取權。)
第三,如果您的自訂版本可能會產生與主線 Subversion 無關的錯誤報告,請與自訂版本的使用者保持聯繫,以便攔截和過濾這些報告。但當然,最好的選擇是從一開始就不要處於這種情況——您的自訂版本與主線 Subversion 的差異越大,它引發的混淆就越多。如果您必須製作自訂版本,請嘗試讓它們盡可能暫時且不分歧。
當引入 API 的新改良版本時,舊版本會保留以維持相容性,至少會保留到下一個主要版本 (2.0.0)。然而,我們會將舊版本標記為已棄用並指向新版本,讓大家知道如果可能的話,請改寫為新的 API。在棄用時,請提及引入棄用標記的版本,並指向新的 API。如果可能,請用新的 API 的 diff 取代舊的 API 文件。例如
/** * Similar to svn_repos_dump_fs3(), but with a @a feedback_stream instead of * handling feedback via the @a notify_func handler * * @since New in 1.1. * @deprecated Provided for backward compatibility with the 1.6 API. */ SVN_DEPRECATED svn_error_t * svn_repos_dump_fs2(svn_repos_t *repos, svn_stream_t *dumpstream, svn_stream_t *feedback_stream, svn_revnum_t start_rev, svn_revnum_t end_rev, svn_boolean_t incremental, svn_boolean_t use_deltas, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool);
當主要版本號碼變更時,系列中「最佳」的新 API 通常會取代所有舊的 API(假設它包含其功能),而且它會採用原始 API 的名稱。因此,在 1.1.x 中將 'svn_repos_dump_fs
' 標記為已棄用並不表示 2.0.0 沒有 'svn_repos_dump_fs
',它只是表示函式的簽章會不同:它會有 1.1.x 中 svn_repos_dump_fs2
(或 svn_repos_dump_fs3
,或其他)所擁有的簽章。編號後綴名稱會消失,而且會再次出現單一的(閃亮、新的)svn_repos_dump_fs
。
此替換策略的一個例外是,舊函數的命名完全不令人滿意。棄用是一個修正的機會:我們給新的 API 一個全新的名稱,將舊 API 標記為已棄用,指向新的 API;然後在主要版本變更時,我們移除舊 API,但不要將新 API 重新命名為舊名稱,因為它的新名稱很好。
次要和主要版本在發布前會經歷一段穩定期,並在發布後保持在維護(錯誤修正)模式。要開始發布程序,我們 建立一個「A.B.x」分支,根據最新的主幹。
新的 A.B.0 版本的穩定期通常持續四週,並允許我們進行保守的錯誤修正並發現重大問題。穩定期從版本為 A.B.0-rc1 的候選版本 tarball 開始。隨著阻擋錯誤的修正,可能會建立進一步的候選版本 tarball;例如,如果發現一組語言繫結已損壞,則在修正後建立新的候選版本是明智的,以便可以測試這些語言繫結。
一旦建立 A.B.x 分支,就永遠不會直接提交任何原始碼變更;變更會在經過表決後從主幹回傳到 A.B.x 分支,其程序說明如下一節。
在穩定期的最後一週開始時,如果自上次以來有任何重大變更待處理,則應建立新的候選版本 tarball。穩定期的最後一週是保留給重大錯誤修正的;次要錯誤的修正應延後到 A.B.1 版本。重大錯誤是非邊緣案例崩潰、資料毀損問題、重大安全漏洞或其他同樣嚴重的問題。
在某些情況下,穩定期將會延長
如果為了修復錯誤而必須進行潛在破壞性的變更,整個為期四週的穩定化期間將重新開始。潛在破壞性的變更是指可能以無法預測的方式影響 Subversion 的許多部分,或涉及新增大量新程式碼的變更。任何不相容的 API 變更(僅在新的版本為 A.0.0 版本時才允許)都應視為潛在破壞性的變更。
如果在穩定化期間的最後一週進行了重大錯誤修正,則最後一週將重新開始。最後的 A.B.0 版本始終與一週前製作的候選版本相同(但有以下所討論的例外情況)。
在 A.B.0 版本發布後,當錯誤修正有需要時,將發布修補程式版本(A.B.1、A.B.2 等)。修補程式版本不需要四週的浸泡期,因為只有保守的變更才會進入該行。
某些類型的提交可以在不重新開始浸泡期的情況下納入 A.B.0,或在不影響測試時程或發布日期的情況下納入後續版本
無需投票
需要投票
僅影響 tools/、packages/ 或 bindings/ 的任何變更。
對列印輸出的變更,例如錯誤和使用訊息,只要格式字串「%
」代碼及其引數未被更動即可。
注意:訊息翻譯變更的要求比 C 程式碼中的文字訊息寬鬆。允許在 .po 檔案中變更格式指定符號,因為它們的有效性可以機械檢查(使用 GNU gettext 的 msgfmt 上的 -c 旗標)。如果使用 GNU gettext,則會在建置時執行此操作。
當然,核心程式碼變更需要投票,並重新開始浸泡或測試期間,因為否則變更可能未經充分測試。
必須先在 A.B.x/STATUS 檔案中提出變更 A.B.x 行。每個提案包含一個簡短的識別區塊(例如,主線或相關行提交的修訂編號,或可能是問題編號)、變更的簡要說明、最多一行說明為何應該在 A.B.x 中、可能的一些注意事項/疑慮,最後是投票。注意事項和疑慮旨在成為簡短摘要,以幫助讀者了解。不要使用 STATUS 檔案進行實際討論;請改用 dev@。
以下是範例,可能與條目一樣複雜
* r98765 (issue #56789) Make commit editor take a closure object for future mindreading. Justification: API stability, as prep for future enhancement. Branch: 1.8.x-r98765 Notes: There was consensus on the desirability of this feature in the near future; see thread at http://... (Message-Id: blahblah). Merge with --accept=mc. Concerns: Vetoed by jerenkrantz due to privacy concerns with the implementation; see thread at http://... (Message-Id: blahblah) Votes: +1: ghudson, bliss +0: cmpilato -0: gstein -1: jerenkrantz
任何人都可以投票,但只有相關領域的完整提交者和部分提交者才有約束力投票。當提交者投下不具約束力的票(例如部分提交者投票給他提名領域之外的變更),他們應該將他們的票註解為不具約束力,如下所示
* r31833 svndumpfilter: Don't match prefixes to partial path components. Fixes #desc4 of issue #1853. Votes: +1: danielsh, hwright +1 (non-binding): stylesen
此區別在所有類型的投票中都會產生,包括回溯投票、發布投票和神話般的 因未達成共識而產生的投票,但原因不同。在發布投票中,此區別是發布進入 ASF 法律保護傘的法律要求,而在回溯投票中,它更接近於諮詢區別。畢竟,如果有人因充分理由對變更投 -1 票,他們的認證並不重要;如果他們的分析正確,變更將不會被回溯。同樣地,如果變更未收到 所需數量的 有約束力的 +1 票,但有一些非約束力的 +1 票,這可能有助於它獲得批准。
換句話說,回溯程序的目的是確保不穩定的變更不會進入修補程序發布。投票通過迫使每個變更接受一定程度的審查來達到此目的。由於業力無法轉移,我們以有約束力的票數來衡量「審查量」,但與以往一樣,任何人都可以對程序提供意見並獲得聆聽。
投票者對變更的意見編碼為 +1、-1、+0 或 -0。
定義「否決」或參照定義
如果您投出否決票(即 -1),請在疑慮欄位中說明原因,並附上清單討論的網址或訊息 ID(如果有)。如果您在提交否決票時無法取得討論串,您可以稍後再回來新增連結。
-0 票表示您對變更有點意見,請在 dev@ 上說明您的理由,或在括號中加以總結,但不會阻礙共識。
對變更投票 +1 不僅表示您原則上同意變更。這表示您已徹底審查變更,並發現它正確且儘可能不具破壞性。當它提交到發布分支時,記錄訊息將包含所有投票支持它的人員姓名,以及原始作者和提交變更的人員。所有這些人員都被視為對錯誤負有同等責任。提交者被信任知道他們不知道的事情,並且不會輕易投出 +1 票。
如果您已檢閱某個修補程式,且您喜歡它,但有一些保留意見,您可以寫「+1(概念)」然後在清單上詢問您擔心的問題。如果您喜歡一般概念,但尚未仔細檢閱修補程式,您可以寫「+0」。這兩個投票都不計入總計,但它們有助於追蹤關注變更且可能願意花更多時間在變更上的人員。
對於非 LTS(「常規」)發行版本,如果變更收到兩個 +1 且沒有否決票,則該變更會獲得核准。(只有具約束力的投票才算數;請見上文。)
對於LTS 發行版本,如果變更收到三個 +1 且沒有否決票,則該變更會獲得核准。(只有具約束力的投票才算數;請見上文。)
儘管有上述規定,對於任何發行版本,僅影響非核心程式碼(例如,工具/、套件/、繫結/、測試腳本等)且不影響建置系統的變更,可以獲得該領域的正式提交者或部分提交者一個 +1,任何其他提交者的至少一個 +0 或「概念 +1」,且沒有否決票。
目標是讓至少兩雙眼睛檢視變更,而不要求每位審閱者都具備與領域維護者相同的專業知識。這樣一來,人們可以審閱一般健全性、準確的評論、明顯的錯誤等,而不必被迫聲明「是的,我了解這些變更的每個細節,並已測試過它們」。
在建議變更 STATUS 之前,您應該嘗試將其合併到分支中,以確保它不會產生合併衝突。如果發生衝突,請從發布分支建立一個新的臨時分支,並將您的變更合併,並解決衝突。分支應命名為 A.B.x-rYYYY,其中 YYYY 是 STATUS 檔案中變更的第一個版本。在 STATUS 檔案中新增一個備註,說明臨時分支的存在,格式為 Branch: A.B.x-rYYYY 或 Branch: ^/subversion/branches/A.B.x-rYYYY 標頭(使用此確切格式;指令碼會分析它)。如果變更涉及進一步的工作,您可以將這些版本合併到分支中。當從 STATUS 中移除此變更的項目時,也應移除此臨時分支,以避免 /branches 目錄混亂。
在極少數情況下,如果要對 A.B.x 分支進行變更,但不是從主幹回溯變更,也會使用臨時分支。
如果您提名一個項目,導致合併衝突,直到另一個提名被合併,請注意提名。在項目中放置「Depends:」標頭;這將使每小時「偵測有合併衝突的提名」buildbot 工作保持綠色。(「Depends:」標頭的值不會被分析。)
tools/dist/nominate.pl 指令碼(在主幹中)自動化新增新提名的程序。同一個指令碼也有 REPL 迴圈,有助於審查提名和投票的程序;請參閱 tools/dist/README.backport(在主幹中)。
注意:關於臨時分支的 STATUS 變更,包括投票,總是保留在主要發布分支上。
在實際發布之前,請寄送電子郵件給翻譯人員,要求更新 .po 檔案。從主幹的 COMMITTERS 檔案中取得他們的電子郵件地址,使用類似於以下的指令
sed -e '/^ *Translat.*:$/,/:$/!d' -e 's/^ *[^ ]* *\([^>]*>\).*/\1/;t;d' COMMITTERS
包含由以下指令產生的翻譯狀態報告
./tools/po/l10n-report.py
這應在所有在地化字串在發布時已穩定為最終形式後執行,但應在實際發布前有充裕的時間,讓翻譯人員完成工作。依經驗法則,請至少在預定發布前一週寄出通知,最好更早。如果許多字串已變更,例如從新分支發布的第一個版本,則讓更多時間過去。
因此,一個發布分支已穩定,而您正準備推出版本。推出程序的詳細資訊由 release.py 輔助指令碼自動化。若要執行此指令碼,您需要一個 Subversion 主幹工作副本。執行 release.py -h 以取得可用子指令的清單。
在您實際推出檔案之前,您需要設定一個白室推出環境。此環境必須包含一些建置工具的原始版本。
您不應使用此軟體的發行版本,因為它們通常會以無法移植的方式進行修補(例如,Debian 的 libtool 修補程式:#291641、#320698。)tools/dist/release-lines.yaml 中提供的版本號碼通常應重新考慮,並在 A.B.0 發行前的時間內增加至最新的穩定上游發行版本。僅應在仔細考慮後才變更 A.B.x 系列中的版本。
Autoconf、Libtool 和 SWIG:選擇一個目錄來包含 Subversion RM 職責所需的特製建置工具,例如 /opt/svnrm。使用 release.py build-env 指令設定、建置和安裝這三個軟體。
mkdir -p /opt/svnrm && cd /opt/svnrm && $SVN_SRC_DIR/tools/dist/release.py build-env X.Y.Z
滾動指令碼還需要以下指令:pax、xgettext、m4 和 python -c 'import yaml'。
從您的作業系統套件中安裝這些指令。(在 Debian 系統上,指令為 apt install pax gettext m4 python-yaml subversion。)
滾動前:
建立 tarball:執行
./release.py roll X.Y.Z 1234release.py 完成後,您將在 /opt/svnrm/deploy 目錄中取得 tarball。
測試一個或兩個 tarball
a) tar zxvf subversion-X.Y.Z.tar.gz; cd subversion-X.Y.Z b) ./configure See INSTALL, section III.B for detailed instructions on configuring/building Subversion. If you installed Apache in some place other than the default, as mentioned above, you will need to use the same --prefix=/usr/local/apache2 option as used to configure Apache. You may also want to use --enable-mod-activation, which will automatically enable the required Subversion modules in the Apache config file. c) make d) make check e) make install (this activates mod_dav) f) make davcheck For this, start up Apache after having configured according to the directions in subversion/tests/cmdline/README. Make sure, that if you maintain a development installation of apache, that you check the config file and update it for the new release area where you're testing the tar-ball. (Unless you rename the tree which gets extracted from the tarball to match what's in httpd.conf, you will need to edit httpd.conf) g) make svncheck First, start up svnserve with these args: $ subversion/svnserve/svnserve -d -r \ `pwd`/subversion/tests/cmdline -d tells svnserve to run as a daemon -r tells svnserve to use the following directory as the logical file system root directory. After svnserve is running as a daemon 'make svncheck' should run h) Then test that you can check out the Subversion repository with this environment: subversion/svn/svn co https://svn.apache.org/repos/asf/subversion/trunk i) Verify that the perl, python, and ruby swig bindings at least compile. If you can't do this, then have another developer verify. (see bindings/swig/INSTALL for details) Ensure that ./configure detected a suitable version of swig, perl, python, and ruby. Then: make swig-py make check-swig-py sudo make install-swig-py make swig-pl make check-swig-pl sudo make install-swig-pl make swig-rb make check-swig-rb sudo make install-swig-rb j) Verify that the javahl bindings at least compile. If you can't do this, then have another developer verify. (see subversion/bindings/javahl/README for details) Ensure that ./configure detected a suitable jdk, and then possibly re-run with '--enable-javahl', '--with-jdk=' and '--with-junit=': make javahl sudo make install-javahl make check-javahl k) Verify that the ctypes python bindings at least compile. If you can't do this then have another developer verify. (see subversion/bindings/ctypes-python/README for details) Ensure that ./configure detected a suitable ctypesgen, and then possibly re-run with '--with-ctypesgen': make ctypes-python sudo make install-ctypes-python make check-ctypes-python l) Verify that get-deps.sh works and does not emit any errors. ./get-deps.sh
使用 GnuPG 簽署版本
使用 release.py 簽署版本release.py sign-candidates X.Y.Z這將執行等同於以下命令的命令
gpg -ba subversion-X.Y.Z.tar.bz2 gpg -ba subversion-X.Y.Z.tar.gz gpg -ba subversion-X.Y.Z.zip並將 gpg 簽章附加到對應的 .asc 檔案。
Subversion 作業
使用反映最終版本的 svn_version.h 建立標籤。使用以下方式執行此動作
release.py create-tag X.Y.Z 1234
注意:請務必建立標籤,即使是候選版本。
create-tag 會提升原始分支中 STATUS 和 svn_version.h 檔案的版本號碼。如果您剛執行 1.0.2,則兩個檔案都應該有 1.0.3 的正確值,以此類推。
將 tarball、簽章和檢查碼提交到 https://dist.apache.org/repos/dist/dev/subversion 有 release.py 子命令可自動執行此步驟
release.py post-candidates 1.7.0
宣布候選版本可供測試和簽署
傳送電子郵件到 dev@ 清單,內容類似於 這封信
Subject: Subversion X.Y.Z up for testing/signing The X.Y.Z release artifacts are now available for testing/signing. Please get the tarballs from https://dist.apache.org/repos/dist/dev/subversion and add your signatures there. Thanks!
調整 #svn-dev 上的主題,提到「X.Y.Z 已準備好進行測試/簽署」
更新問題追蹤器,以提供適當的版本/里程碑。如果要發布新的次要版本,應新增 1.MINOR.x 的版本。所有版本都應新增下一個版本的版本(例如 1.MINOR.x+1)。如果您沒有權限執行此動作,請在 IRC 上詢問或傳送電子郵件到 dev@ 清單。
Subversion 版本透過全球 內容傳遞網路 (CDN) 分發。(這已於 2021 年底取代了之前的 ASF 鏡像網路。不過,仍可能存在其他組織選擇繼續鏡像 ASF 版本。)
最終使用者能夠驗證他們下載的原始碼套件的真實性非常重要。檢查碼足以偵測下載過程中的損毀,但為了防止惡意個人或鏡像操作員散布替代套件,每個原始碼套件都必須由 Subversion PMC 成員加密簽署。這些簽章使用每個提交者的私人 PGP 金鑰完成,然後與版本一起發布,以便最終使用者驗證已下載套件的完整性。
在 Subversion 版本正式公開之前,需要
在建立初始 tarball 組時,版本管理員也會建立第一組簽章。雖然 tarball 本身可以在 people.apache.org 上建置,但重要的是簽章不能在那裡產生。簽署 tarball 需要私人金鑰,而將私人金鑰儲存在 ASF 硬體上強烈不建議。在簽署 tarball(使用下列程序)後,版本管理員應將簽章上傳到初步散布位置,並將它們放在與 tarball 相同的目錄中。
PMC 成員以及熱情的社群成員應從初步散布位置下載 tarball,執行測試,然後提供他們的簽章。這些簽章的公開金鑰應透過 id.apache.org 納入 ASF LDAP 實例。(Subversion 提交者和 PMC 成員的目前公開金鑰清單每天會從 LDAP 自動產生。)建議版本管理員在宣布版本之前至少等待 5 天以取得簽章,讓測試版本的任何人可以在宣布之前完成簽署版本。
簽署 tarball 表示您聲明某些事項。在宣布您的簽署時,請在郵件中指出您已採取哪些步驟來驗證 tarball 是否正確,例如驗證內容是否與儲存庫中的正確標籤相符。在所有 RA 層和 FS 後端執行 make check 也是個好主意,以及建置和測試繫結。
若要取得發行候選版本,請查看 https://dist.apache.org/repos/dist/dev/subversion 的工作副本。驗證發行管理員在 tarball 上的 PGP 簽章。release.py 會自動執行此步驟
release.py get-keys release.py --target /path/to/dist/dev/subversion/wc check-sigs 1.7.0-rc4
在驗證、解壓縮和測試 tarball 之後,您應該使用 gpg 建立武裝分離簽章來簽署。若要將您的簽章附加到 .asc 檔案,請使用類似下列的指令
gpg -ba -o - subversion-1.7.0-rc4.tar.bz2 >> subversion-1.7.0-rc4.tar.bz2.ascrelease.py 腳本可以自動執行此步驟
release.py --target /path/to/dist/dev/subversion/wc sign-candidates 1.7.0-rc4
在加入您的簽章後,將本機修改的 .asc 檔案提交到 dist.apache.org 儲存庫。
如果您已下載並測試 .tar.bz2 檔案,則可以簽署內容相同的 .tar.gz 檔案,而無需另外下載和測試。訣竅是解壓縮 .bz2 檔案,並使用 gzip 進行封裝,如下所示
bzip2 -cd subversion-1.7.0-rc4.tar.bz2 \ | gzip -9n > subversion-1.7.0-rc4.tar.gz
產生的檔案應與發行管理員產生的檔案相同,因此可以如上所述進行簽署。若要驗證檔案是否相同,您可以使用檢查碼或發行管理員的簽章,這兩者都應與 tarball 一起提供。
但是,如果檢查碼不相同,則不一定是檔案簽章錯誤或檔案已遭到竄改。很有可能是您沒有與發行管理員相同的 gzip 版本。
在 tarball 建立完成,所有簽章建立並驗證後,此版本即可準備發布。本節說明發布 Subversion 版本所需的步驟。
Subversion 人工製品透過全球 內容傳遞網路 (CDN) 來傳遞。原始碼 下載頁面 會自動協助使用者選擇合適的下載連結。我們通常只會在專案的傳遞目錄中,為受支援的版本線主機最新的穩定版本,而所有先前的 Subversion 版本都可以在 檔案 中取得。
若要上傳版本至 CDN
release.py move-to-dist 1.7.0這會將 tarball、簽章和檢查碼從 ^/dev/subversion 移至 ^/release/subversion。內容傳遞網路 (CDN) 大約需要 15 分鐘的時間來接收新版本。檔案也會自動接收版本。雖然執行 move-to-dist 會移動簽章檔案,但提交者仍然可以提交新的簽章至 ^/release/subversion;然而,這些簽章需要 15 分鐘的時間才會出現在 CDN 上。任何此類簽章都不得包含在版本公告中,除非已在提交後經過 15 分鐘。
在這個時間點,版本可能已公開,但最好等到 CDN 接收後再宣布。在 15 分鐘的時間過後,讓 CDN 有足夠的時間同步,版本管理員將會發送公告並發布變更至 Subversion 網站,如下所述。
這也是清理 ^/release/subversion 中任何舊版本的好時機;每個受支援版本線中只有最新的版本應在該目錄中。已在 ^/release/subversion 中提供至少 24 小時的版本將繼續在檔案中提供。您可以使用以下方式清理舊版本
release.py clean-dist
在 reporter.apache.org 上提交新版本的版本號碼。下列指令
curl -u USERNAME "https://reporter.apache.org/addrelease.py?date=`date +%s`&committee=subversion&version=VERSION&xdate=`date +%F`"將新增版本,它可能應該新增到 release.py。
即使下列步驟指示直接更新已發佈的網站,您可以在 ^/subversion/site/staging 上準備變更。在這種情況下
從 ^/subversion/site/publish 進行追趕合併。
將任何變更提交到 ^/subversion/site/staging,並在 https://subversion-staging.apache.org 上查看結果。
準備發佈時,將變更合併回 ^/subversion/site/publish(檢閱合併,以防 staging 上有其他尚未準備好合併的變更)。
對於任何版本,包括預先發佈版本(alpha/beta/rc)
編輯 ^/subversion/site/publish/download.html 以記錄最新版本。使用 release.py write-downloads 來產生表格。如果這是穩定版本,請更新 [version] 或 [supported] ezt 巨集定義(例如 [define version]1.7.0[end]);如果這是預先發佈版本,請取消 <div id="pre-releases"> 的註解;如果這是已淘汰預先發佈版本的 1.x.0 版本,請重新註解它。
將新消息項目新增至 ^/subversion/site/publish/news.html 以宣布版本發佈。將相同項目新增至 ^/subversion/site/publish/index.html 上的新聞清單,並同時移除該頁面中最舊的新聞項目。使用 release.py write-news 產生範本新聞項目,然後自訂該項目。新聞項目中有一個區段應包含指向公告郵件的連結。目前已將其註解掉,稍後會新增連結。如果您在發佈日期之前產生範本,請確認日期是否正確。
此外,如果這是穩定版本 X.Y.Z(而非 alpha/beta/rc)
在 ^/subversion/site/publish/doap.rdf 上列出新版本
每個受支援的次要版本都應有一個 <release> 區段,且 <created> 和 <revision> 已更新為目前的發佈日期和修補程式版本號碼。請勿變更檔案中的任何其他內容(尤其是 <Project> 下的 <created> 是 Subversion 專案建立的日期)。
在 ^/subversion/site/publish/docs/release-notes/release-history.html 上列出新版本
此外,如果這是新的次要版本 X.Y.0
更新 ^/subversion/site/publish/docs/release-notes/index.html 上「受支援版本」區段中的社群版本支援層級。
更新 release.py 中的 supported_release_lines,必要時移除舊行。
從 ^/subversion/site/publish/docs/release-notes/X.Y.html 中移除「草稿」警告。
在 ^/site/publish/docs/api/X.Y 和 ^/site/publish/docs/javahl/X.Y 中建立或更新版本化文件快照,並確保與這些目錄同層的「latest」符號連結始終指向最新版本系列的目錄。
範例
VER=1.12 DOCS_WC=~/src/svn/site/staging/docs TAG_BUILD_DIR=~/src/svn/tags/$VER.x/obj-dir cd $TAG_BUILD_DIR make doc cp -a doc/doxygen/html $DOCS_WC/api/$VER cp -a doc/javadoc $DOCS_WC/javahl/$VER for D in $DOCS_WC/api $DOCS_WC/javahl; do svn add $D/$VER rm $D/latest && ln -s $VER $D/latest done svn ci -m "In 'staging': Add $VER API docs." $DOCS_WC/api $DOCS_WC/javahl
更新索引頁 docs/index.html#api 上指向 API 文件的連結。
在發佈日期提交對「publish」的修改(或從「staging」合併至「publish」)。
新的次要版本(編號為 1.x.0)可能會附有新聞稿。所有可能的新聞稿詳細資訊都由 private@ 清單處理,並與 press@a.o 協調。
根據經驗法則,在浸漬開始時,在 private@ / press@ 上開始一個執行緒 在浸漬開始時;給予 press@ 過長的預警時間比過短的時間要好。
撰寫版本公告,參考之前的公告作為指導。請記得在公告中包含 URL 和檢查碼!release.py write-announcement 子指令會建立一個範本公告,可以針對特定情況自訂。如果版本修正了安全性問題,請傳遞 --security 旗標,以在輸出中產生正確的主旨、副本和說明。
如果社群支援等級會隨著此版本而變更,請務必在使用 release.py 產生公告之前,更新 release.py 中的 recommended_release 變數。
從您的 @apache.org 電子郵件地址發送公告。(如果從任何其他地址發送,寄往 announce@ 的郵件會反彈。為獲得最佳結果,請遵循 提交者電子郵件 頁面上的說明,並透過官方郵件中繼傳送您的訊息。)請確保您的郵件程式不會將 URL 換行到多行。
注意:我們會在宣布版本之前更新網站,以確保版本公告中的任何連結都是有效的。在宣布版本之後,會將連結新增到版本公告電子郵件中,並新增到網站中。
有兩個 announce@ 郵件清單會張貼發布公告:Subversion 專案的 announce@subversion.apache.org 清單,以及 ASF 全體的 announce@apache.org 清單。您發送至 ASF 全體的 announce@ 清單的訊息可能會被拒絕。這會產生一則管理通知,主旨行如下:退回 announce@apache.org 的郵件。命令郵件清單軟體拒絕訊息的管理員可能會忘記在拒絕訊息中簽名,導致拒絕訊息變成匿名,而拒絕理由也可能無效。無論如何,保持冷靜,並將拒絕訊息轉發至 dev@ 郵件清單,以便專案可以討論是否需要採取任何措施。(如有必要,可以透過 announce-owner@ 處理方式聯絡 announce@ 郵件清單管理員。)
更新各種 Subversion 相關 IRC 頻道中的主題,例如 libera.chat 上的 #svn 和 #svn-dev。
如果這是 X.Y.0 發布,請更新已變更支援狀態的任何分支的 STATUS 檔案最上方的社群支援等級。這通常會是 X.Y.x/STATUS、X.$((Y-1)).x/STATUS,如果新發布是 LTS 發布,則也會是支援最久的 LTS 分支的 STATUS 檔案。
更新 ^/subversion/site/publish/news.html 和 ^/subversion/site/publish/index.html,取消註解並新增連結至發布公告電子郵件。
接著,發布管理員就可以去享受他的 $favorite_beverage 了。
會為每個新的主要和次要發布建立新的發布分支。因此,例如,在準備發布版本 2.0.0 或版本 1.3.0 時,會建立新的發布分支。然而,在準備發布 1.3.1(修補版本增量)時,會使用在 1.3.0 時建立的發布分支。
如果您正在準備修補發布,則不需要建立發布分支。您只需從目前次要版本系列發布分支中斷的地方繼續即可。
建立新發行分支的時間點充其量只是模糊的。一般來說,我們有每 6 個月發行一個新次要版本的軟性排程。因此,在先前的次要版本發行後約 4 個月,是開始提議分支的適當時機。但請記住,這是有彈性的,取決於正在開發的功能。
檢閱 路線圖。在分支之前,是否應該處理任何未完成的項目?
檢閱現任穩定分支的 STATUS 檔案,找出未完成的 -0 和 -1 投票。是否有人反對將包含在新分支中的程式碼?(即使有,也不應阻擋分支,但應展開討論,以便在推出發行分支之前解決問題。)
執行任何全樹、機械化的變更。(非機械化的變更應早先發生,以利檢閱。)這可簡化後續的合併。範例包括 移除尾隨空白、填補錯誤漏洞、修正 C 標頭中的不變數(另一種情況)以及 搜尋並取代程式碼。(這也是執行其他定期家務任務的好時機,例如 靜態 分析。)
檢閱新的和已變更的 API,以瞭解其設計和樣式(例如 Doxygen 標記、未記錄的參數、不建議使用、公開/私人狀態等)。
執行相容性 測試,針對現任次要版本。
一旦大家同意建立新的版本分支,版本管理員會使用以下其中一個程序建立它(用您準備的版本取代 A.B,例如 1.3 或 2.0)。
建立版本分支的大部分工作都可以使用 tools/dist/release.py 自動化。
在一個空的目錄中執行此命令,它會建立一些暫時的簽出。
release.py --verbose create-release-branch A.B.0
如果之前沒有執行,請為專案網站建立版本說明範本。
release.py --verbose write-release-notes A.B.0 > .../docs/release-notes/A.B.html svn add .../docs/release-notes/A.B.html svn ci -m "Add release notes template." .../docs/release-notes/A.B.html
此區段中的大部分步驟都可以使用 tools/dist/release.py 自動化—請參閱上方—但如果版本管理員想要手動執行,這裡有文件說明。
使用伺服器端複本建立新的版本分支。
svn cp ^/subversion/trunk \ ^/subversion/branches/A.B.x \ -m "Create the A.B.x release branch."
編輯 trunk 上的 subversion/include/svn_version.h,並增加裡面的版本號碼。請勿提交這些變更。
trunk 上的版本號碼總是反映您剛建立分支的版本之後的主要/次要版本(例如 2.0.x 分支的 2.1.0,以及 1.3.x 分支的 1.4.0)。
編輯 trunk 上的 subversion/bindings/javahl/src/org/apache/subversion/javahl/NativeResources.java,並增加 SVN_VER_MINOR。請勿提交這些變更。
編輯 trunk 上的 subversion/tests/cmdline/svntest/main.py,並增加 SVN_VER_MINOR。請勿提交這些變更。
編輯 trunk 上的 CHANGES,為即將推出的版本新增一個新的區段(如果尚未新增),以及為未來要建立的次要版本新增一個新的區段。每個區段都以
Version A.B.0 (?? ??? 20XX, from /branches/A.B.x) https://svn.apache.org/repos/asf/subversion/tags/A.B.0
目前先將發布日期留空。它會保持這樣直到發布時間。
提交這些變更,並附上類似以下內容的日誌訊息
Increment the trunk version number to A.$((B+1)), and introduce a new CHANGES section, following the creation of the A.B.x release branch. * subversion/include/svn_version.h, subversion/bindings/javahl/src/org/apache/subversion/javahl/NativeResources.java, subversion/tests/cmdline/svntest/main.py (SVN_VER_MINOR): Increment to $((B+1)). * CHANGES: New section for A.$((B+1)).0.
在發布分支上建立一個新的 STATUS 檔案。
確保所有 buildbot 建構器都在建構新的發布分支。
將 A.B 加入 https://svn.apache.org/repos/infra/infrastructure/buildbot/aegis/buildmaster/master1/projects/subversion.conf 中的 MINOR_LINES 清單。
建立一個範本發布說明文件,site/publish/docs/release-notes/A.B.html
請有適當存取權的人將 A.B.x 分支加入 回傳合併機器人。
決定發布是常規還是 LTS,並將決定記錄在 release.py 的 tools/dist/release-lines.yaml 中的 lts_release_lines。
回傳合併機器人在 svn-qavm1 機器上每晚執行一次,在 svnsvn 本地使用者帳戶下,使用 svn-role Subversion 帳戶名稱提交。
此組態目前需要具有機器管理員存取權的人來管理分支集的變更。
機器人會合併每個 A.B.x 分支上已核准的回傳,而這些分支在 ~svnsvn/src/svn/A.B.x 處有 WC 目錄。
那裡的結帳是透過執行類似以下內容(作為 svnsvn 使用者,例如使用 sudo)建立的
svn checkout --depth=empty https://svn-master.apache.org/repos/asf/subversion/branches ~svnsvn/src/svn svn up ~svnsvn/src/svn/A.B.x # for each supported branch
儲存庫網址是 svn-master.a.o,因為回傳合併器會在迴圈中執行 svn ci && svn up,並假設 svn up 會將其更新到它剛剛提交的版本。當從鏡像更新時(且 svn.a.o 可能指向鏡像),這並 不能保證。buildbot 從屬程式也會因為相同原因執行此操作。
每個分支都位於 WC 根目錄的子目錄中。若要新增分支,請使用 svn up 填入原始碼樹
sudo -H -u svnsvn svn up ~svnsvn/src/svn/A.B.x
若要移除不再支援的分支,請使用 svn up -r0
sudo -H -u svnsvn svn up -r0 ~svnsvn/src/svn/Z.Z.x
可以在 machines/svn-qavm1/ 和 Subversion PMC 的 私人儲存庫 中找到更多有關設定的說明。在 machines/ 的歷史記錄中,也有關於先前版本的歷史說明。
CHANGES 檔案是專案變更日誌檔案。在發行前,必須更新此檔案,以列出自上次發行以來的所有變更。
以下說明手動處理程序。如需部分自動化,請參閱
release.py write-changelog
對於修補程式發行,這相當容易:您只需瀏覽自上次「黃金」版本以來的分支提交日誌,並記錄所有有趣的合併。對於次要和主要發行,這會更複雜:您需要在自上次發行分支分岔以來,瀏覽主幹上的提交日誌,並記錄那裡的變更。程序相同,但更長,而且更複雜,因為它涉及過濾掉已回溯到先前發行分支並從中發行的變更集。
請記住,CHANGES 應始終在主幹上編輯,然後在必要時合併到發行分支中。將所有發行的所有變更記錄在主幹上的 CHANGES 檔案中非常重要,這不論是為了日後的參考,還是為了讓未來的發行分支包含所有先前變更紀錄的總和。
保持每個變更的項目符號簡潔,最好不要超過一行。有時這可能是一個挑戰,但它確實有助於提高文件整體的可讀性。問問自己:如果描述需要超過一行,也許我太詳細了?
執行 svn log --stop-on-copy ^/subversion/branches/A.B.x。這應該會提供對 A.B.x 分支所做的所有變更,包括對 A.B.x 分支進行的反向移植。然後,你需要移除已在前一個主要/次要分支的微發行版中發布的變更紀錄。在先前的發行分支上執行 svn log -q --stop-on-copy,然後撰寫一個腳本來分析修訂編號並將它們從你的主要紀錄輸出中移除。(Karl 和 Ben 過去使用 emacs 巨集來執行此操作,但建議我們撰寫一個更通用的腳本。)(更新:現在,svn mergeinfo --show-revs eligible 應簡化取得相關修訂的集合—使用次要分支作為來源,並將先前的次要分支作為目標。)
從最舊到最新閱讀該紀錄,並在進行時總結重點。訣竅在於知道要撰寫哪個詳細程度:你不想提到每個微小的提交,但你也不想太籠統。在開始新區段之前,先閱讀幾頁 CHANGES 檔案來設定你的篩選器等級,這樣才能保持一致性。
作為 發行穩定化 的一部分,CHANGES 應在錯誤修正移植到發行分支時更新。一般而言,如果您將修訂或修訂群組 (即 STATUS 中的項目) 合併到發行分支,您也應在主幹上新增項目至 CHANGES,並遵循上述相同的準則。此清單會在修補版本發行時合併到發行分支。
在實務上,並非每次修正回傳到發行分支時,都會更新 CHANGES。通常,發行經理會在進行修補版本發行的第一步時更新 CHANGES。
取得應在 CHANGES 中提及的回傳清單的便利方法,是使用與在 Subversion 網站上填入 即將推出的修補版本 的相同工具。這是 https://svn.apache.org/repos/asf/subversion/site/tools 中的 upcoming.py 指令碼。在目前的作業目錄為次要分支的作業副本根目錄時執行它。
翻譯已分為兩個領域。首先,有傳送給連線用戶端的伺服器訊息翻譯。此問題已 暫時擱置。其次是用戶端及其函式庫的翻譯。
gettext 套件提供翻譯訊息的服務。它使用 xgettext 工具從來源中擷取字串以進行翻譯。這透過擷取 _(), N_() 和 Q_() 巨集的自變數來運作。_() 用於允許函式呼叫的內容中(通常是靜態初始值設定函式以外的所有內容)。N_() 用於 _() 未使用時。標記為 N_() 的字串需要在程式碼中參照時傳遞至 gettext 翻譯常式。例如,請參閱 subversion/svn/help-cmd.c 中標頭和尾端的處理方式。Q_() 用於具有單數和複數版本的訊息。
除了 _(), N_() 和 Q_() 巨集之外,U_() 也用於標記不會翻譯的字串,因為一般來說翻譯內部錯誤訊息並無幫助。這只會影響大多數使用者永遠不會看到的模糊錯誤訊息(由 Subversion 中的錯誤或非常特殊的儲存庫損毀所造成)。使用 U_() 的原因是明確指出並非忘記 gettext 呼叫。
當使用 gettext 常式的直接呼叫(*gettext 或 *dgettext)時,請記住 Subversion 程式碼大多是函式庫程式碼。因此,預設領域不一定是 Subversion 自身的領域。在函式庫程式碼中,您應該使用 gettext 函式的 dgettext 版本。領域名稱定義在 PACKAGE_NAME 定義中。
在地化的所有必要設定都由 svn_private_config.h(適用於 *nix)和 svn_private_config.hw(適用於 Windows)中的 ENABLE_NLS 條件式控制。請務必放置
#include "svn_private_config.h"
作為需要本地化的任何檔案中最後的 include。
另請注意,_(), Q_() 和 *gettext() 呼叫的回傳值為 UTF-8 編碼;這表示它們應該翻譯成目前正在撰寫的區域設定,作為任何形式的程式輸出。
GNU gettext 手冊 (https://gnu.dev.org.tw/software/gettext/manual/html_node/gettext_toc.html) 在其「準備程式來源」區段中提供了關於撰寫可翻譯程式的其他資訊。其提示主要適用於字串組合。
目前可用的翻譯可以在 儲存庫的 po 區段 中找到。如果您想要開始進行尚未提供的翻譯,請聯絡 dev@subversion.apache.org。翻譯討論會在該清單中進行。
Makefile 建置目標 locale-gnu-*(用於維護 po 檔案)需要 GNU gettext 0.13 或更新版本。請注意,這並非編譯 *.po 檔案成 *.mo 檔案的必要條件。
在開始新的翻譯之前,請聯絡 Subversion 開發郵件清單以確保您不會重複工作。另請注意,此專案強烈偏好由多人維護的翻譯:向清單寄送您的意向郵件可能會幫助您找到支持者。
在那之後,您應該執行下列步驟
./autogen.sh
./configure
make locale-gnu-pot
subversion/po
目錄中執行 msginit --locale LOCALE -o LOCALE.po
。LOCALE 是用於識別您的語言環境的 ll[_LL] 語言和國家/地區代碼。步驟 (2) 和 (3) 會產生 Makefile;步驟 (4) 會產生 subversion/po/subversion.pot
Subversion 專案有一個 政策,不會在檔案中放入名稱,因此請套用以下所述的兩個變更。
新產生的 .po 檔案中的標頭如下所示
# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
請將該區塊替換為以下文字
# <Your language> translation for subversion package # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License.
.po 檔案中的第一個翻譯區塊包含兩行,如下所示
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
請將它們替換為以下兩行
"Last-Translator: Subversion Developers <dev@subversion.apache.org>\n" "Language-Team: YOUR LANGUAGE <dev@subversion.apache.org>\n"
待記錄
在提交到郵件清單或提交到儲存庫之前,請確定您的 po 檔案「已編譯」。您可以在 Makefile 為基礎的系統上執行下列步驟來執行此動作
./autogen.sh
./configure
(使用適當的引數)make locale
autogen.sh 步驟很重要,因為它會將新的 po 檔案新增為「locale」建置目標的相依性。但請注意,在您新增新的翻譯後,步驟 1 和 2 只需要執行一次。
請勿將大型 po 檔案郵寄至郵件清單。dev@subversion.apache.org 上有許多訂閱者連線速度較慢,不希望透過電子郵件收到大型檔案。請改為將 po 檔案放置在網際網路上供人下載,並貼上 URL 即可。如果您沒有可用的網站,請在 dev@ 上詢問,有人會協助您尋找位置。
當然,如果您有 Subversion 儲存庫的提交權限,只要滿足所有其他需求,您就可以直接將 po 檔案提交到儲存庫。
建置系統中基於 Makefile 的部分包含一個建置目標,以利維護現有的 po 檔案。若要在具有 GNU gettext 的系統上更新 po 檔案,請執行
make locale-gnu-po-update
若要僅更新特定語言,您可以使用
make locale-gnu-po-update PO=ll
其中 ll 是不含副檔名的 po 檔案名稱 (例如:PO=sv)。
建議使用兩次提交來更新 .po:一次在「make locale-gnu-po-update」之後,另一次在翻譯完成之後。這樣有兩個好處
gettext(1)
會產生許多行號變更,這會讓產生的 diff 難以讓其他翻譯人員檢閱。透過兩次提交,所有行號變更都會儲存在第一次提交中,而第二次提交則包含所有實際翻譯,沒有額外的垃圾。編輯 trunk 中的 po 檔案相當簡單,但當這些變更要傳輸到發行分支時,就會變得有點複雜。專案政策是不在發行分支上進行任何直接變更,提交至分支的所有內容都應從 trunk 合併。這也適用於 po 檔案。使用 svn merge
來執行這項工作可能會導致衝突和模糊訊息,這是因為 gettext 變更了行號和字串格式所致。
svn merge
來執行分支更新時存在的任何複雜性。適用下列規則
建立 locale-gnu-po-update
上述清單是分支上 po 檔案允許的所有操作的完整列舉。
可以使用此指令將 trunk 版本 X 的 YY.po 中的訊息合併到您的分支工作副本中
svn cat -r X ^/subversion/trunk/subversion/po/YY.po | \ po-merge.py YY.po
在某些 gettext 實作中,我們必須確保 mo 檔案(無論是透過專案取得或是在本機建立)使用 UTF-8 編碼。此需求源自於 Subversion 內部使用 UTF-8,某些實作會翻譯成目前的語言環境,以及 bind_textdomain_codeset()
在不同實作之間無法移植的事實。
某些 gettext 實作會使用 msgid ""(空字串)的區段來保留管理資料。建議的標頭之一是「Last-Translator:」欄位。由於 Subversion 專案有政策不針對特定檔案中的貢獻者命名,而是在儲存庫記錄訊息中給予肯定,因此您不得在此欄位中輸入您的姓名。
由於某些工具需要此欄位才能將 po 檔案視為有效(例如 Emacs PO 模式),因此您可以將「dev@subversion.apache.org」輸入此欄位。
專案已標準化引號的使用方式。有些翻譯團隊也做了同樣的事。如果你的語言環境沒有翻譯團隊,或者他們沒有標準化引號,請遵循本指南其他地方的專案指南。如果他們有:請遵循他們 :-)