我痛恨 Git 的 10 個理由

發表於2012-03-10

Git 是一個原始碼版本控制系統,正在迅速成為開源專案的標準。它有一個強大的分散式模型,允許高階使用者用分支來處理各種棘手的問題和改寫歷史記錄。但是,要學習 Git 是需要付出更多的努力,讓人不爽的命令列介面以及 Git 是如此的忽視它的使用者。

下面是我為什麼如此痛恨 Git 的 10 個理由:

0. 複雜的資訊模型

Git 的資訊模型是很複雜的,而且你必須對他們都很瞭解。在這個方面上你看看 Subversion:有檔案、工作目錄、資源庫、版本、分支和標籤。你需要了解的就是這些東西,實際上,分支、標籤和檔案你已經瞭解,但如果使用 Git ,你擁有更多的概念需要了解:檔案、工作樹、索引、本地資源庫、遠端資源庫、遠端、提交、treeishes、分支和 stash。你需要了解比 Subversion 更多得多的知識點。

1. 讓人抓狂的命令列語法

Git 的命令列語法完全是隨意的而且不一致,例如 git pull 基本上跟 git merge 和 git fetch 一樣,git branch 和 git checkout 合併就變成 git checkout -b,git reset 命令的不同引數做的事情完全不一樣,指定檔名後命令的語義完全不同等等。

而最為壯觀的就是 git am 命令了,據我所知,這是因為 Linus 在當年某個晚上為了解決通過電子郵件閱讀補丁而使用的不同的補丁語法,特別是在郵件的標題上。

2. 蹩腳、讓人費解的文件

說起 Git 的這個文件,我唯一想說的就是“操”。他們是為電腦科學家在寫文件,而不是使用者。在這裡舉個例子:

git-push – Update remote refs along with associated objects

如果是針對使用者而言,應該描述為:

git-push – Upload changes from your local repository into a remote repository

另外一個例子:

git-rebase – Forward-port local commits to the updated upstream head

翻譯: git-rebase – Sequentially regenerate a series of commits so they can be applied directly to the head node

3. 資訊模型的擴散

剛才我在第一點提到的 Git 的資訊模型是非常複雜的,而且還想癌細胞一樣一直在擴散,當然一直在使用 Git ,就會不斷的冒出各種新的概念,例如 refs, tags, the reflog, fast-forward commits, detached head state (!), remote branches, tracking, namespaces 之類的。

4. 漏洞百出的抽象

Git 包含太多不是抽象的抽象,在定義使用者介面和實現上經常沒有任何區別,這是可以理解的,對一個高階使用者來說他需要了解一些功能的具體實現,以掌握各個命令的微妙之處。但大量的內部細節對初學者來說簡直是噩夢。有這麼一個說法,關於水暖器材和瓷器,但你必須成為一個水暖工才能知道器材如何安裝在瓷器上。

很多人對我的抱怨予以回應說:你無需使用所有的命令,你可以向 Subversion 一樣來使用 Git。這是狡辯,就好比是告訴一個老奶奶說高速公路並不可怕,她可以在高速路上靠左邊的快車道上以時速 20 公里爬行,一樣的道理。Git 並沒有提供任何有用的子集,每個命令都會連帶著對其他命令的要求,很簡單的動作經常需要很複雜的動作來撤銷或者改進。

下面是一個 Github 專案維護者的一些善意的建議:

1.在分支和 master 上尋找合併的基準: ‘git merge-base master yourbranch’

2.假設你已經提交了更改記錄,從對你的提交重新基準化到合併準,然後建立一個新分支

3.git rebase –onto <basecommit> HEAD~1 HEAD

4.git checkout -b my-new-branch

5.檢出你的 ruggedisation 分支,然後移除提交: ‘git reset –hard HEAD~1′

6.合併新的分支到 ruggedisation: ‘git merge my-new-branch’

7.檢出 master (‘git checkout master’), 合併新分支 (‘git merge my-new-branch’), 然後檢查合併後的情況,接著移除合併 (‘git reset –hard HEAD~1′).

8.提交新的分支 (‘git push origin my-new-branch’) 並記錄 pull 請求

翻譯:“奶奶,在高速公路上開車很容易的。鬆開離合器,讓轉速超過 6000 轉使車輪打滑,然後進入第一個彎道並上高速公路,看路牌到出口前,使用手剎飄逸轉向出口。

5. 維護簡單,但是提交麻煩

Git 很強大的一點就是程式碼基準庫的維護,你必須合併來自大量不同源的提交,非常適合大規模並行開發。但是這些都不是為大多數 Git 的使用者設計的,他們只是需要編寫程式碼,可能好幾個月都在同一個分支上,對他們來說 Git 是帶有 4 個手柄的雙鍋的咖啡機,但使用者只想立即喝到咖啡。

有趣的是,我並不認為這是 Git 在設計中做的權衡。它完全是忽視了真正的使用者需求、混淆架構和介面。如果你是一個架構師,那麼 Git 是很棒的。但對使用者來說它很糟糕,已經有不少人在為 Git 編寫一些簡化的介面,例如 easygit。

6. 不安全的版本控制

作為一個版本控制系統而言,它必須承諾的就是:一旦程式碼提交到系統,那麼我將保證程式碼的安全,你做的任何改動你都可以找回。而 Git 食言了,有很多方法可以讓整個資料庫完全崩潰而且不可恢復:

1.git add . / … / git push -f origin master

2.git push origin +master

3.git rebase -i <some commit that has already been pushed and worked from> / git push

7. 將版本控制庫維護者的責任移給貢獻者

在傳統的開源專案中,只需要一個人負責處理分支和合並這樣複雜的操作,那就是維護者。而其他人只需要簡單的更新提交、更新提交、不斷的更新提交。而現在 Git 讓每個使用者都需要了解作為維護者才需要知道的各種操作,煩不勝煩。而維護者呢,無所事事,翹起二郎腿喝咖啡。

8. Git 的歷史是一堆謊言

開發工作主要的產出就是原始碼,一個維護良好的程式碼歷史就對一個產品來說非常的重要,關於重新基準化有很多的爭論,多數是依賴於對凌亂合併和不可讀的日子的審美判斷。而重新基準化為開發者提供一個“乾淨整潔”的卻毫無用途歷史記錄,而實際上正確的解決方法是更好的日誌輸出以及對不想要的合併進行過濾。

9. 簡單任務也要諸多命令

如果你在開發一個開源專案,你做了一些改變,然後想與其他人分享,你只需要:

1.修改程式碼

2.執行 svn commit

如果你增加了一些新檔案:

1.新增檔案

2.svn add

3.svn commit

如果你的專案託管在 Github 類的網站中,那麼你需要:

1.Make some changes

2.git add [not to be confused with svn add]

3.git commit

4.git push

5.到此為止,你的更改只完成了一半,接下來你需要登入到 Github,查詢你的提交,然後釋出一個 “pull request” ,這樣其他人才可以獲取你的改動

在現實中,Github 的維護者希望你的改動是功能方面的分支,他們會要求你這樣操作:

1.git checkout master [to make sure each new feature starts from the baseline]

2.git checkout -b newfeature

3.Make some changes

4.git add [not to be confused with svn add]

5.git commit

6.git push

7.然後登入到 Github,切換到你的新特性分支,釋出 “pull request”

為了將你的更改從你的本地目錄中移到實際的專案資源庫,你需要:add, commit, push, “click pull request”, pull, merge, push.

下面是一個流程圖向你展示一個典型的開發者在 Subversion 上要做的工作:

我痛恨 Git 的 10 個理由

“Bread and butter” 是與遠端 SVN 資料庫操作的命令和概念。

然後我們再來看看如果你的專案託管在 Github 上會是怎樣的:

我痛恨 Git 的 10 個理由

如果 Git 的強大之處是分支和合並,那麼它的弱點就是讓簡單的任務變得非常複雜。

 

相關文章