如何優雅地使用 Git?


1. 一個專業的shell環境, Windows上的msysgit有自帶的git shell. 如果是*nix, 我建議自己config一個和主shell無關的shell, 如zsh, 把PS1改成能顯示分支的

2. 大量使用alias, 縮短所有命令的名字

3. Git顯示漂亮日誌的小技巧

4. 選一個好用的merge tool, Win上 我個人喜歡Araxis Merge, 其他系統我都是kdiff3

5. 做好release branch, develop branch, 以及hot fix branch

最好推薦一本書, 叫&, 各國語言都有


如果你使用 Vim 編輯器,那麼推薦你安裝 Fugitive 插件。它不但讓你不用再在 Vim 與 Terminal 之間切來切去,甚至還提供了 Terminal 上不具備的功能。我只在這裡簡略地展示一下,更詳細的介紹,推薦觀看 Vimcasts 上關於 Fugitive 的介紹。

  1. A complement to command line git
  2. Working with the git index
  3. Resolving merge conflicts with vimdiff
  4. Browsing the git object database
  5. Exploring the history of a git repository

Gdiff

在 Vim 中運行 :Gdiff,可直接分窗口打開當前文件的 staged version (左)和 working tree version (右)。方便又直觀。

Gstatus

修改文件後,在 Vim 中運行 :Gstatus,可以在預覽窗口中看到熟悉的 git status 界面。游標標記需保存的修改項後,按 - 可快速 add 之。按 C 可進行 commit。什麼?只不過換了個地方做同樣的事?不僅如此。注意下圖,你可以在 commit message 中利用 Vim 的自動完成功能。媽媽再也不用擔心我 commit 時寫錯函數名了!

Gblame

一圖勝萬言。不用多說。

Glog

用 :Glog 隨時查看當前文件的所有版本。


強烈推薦Source Tree,支持windows和mac os。

同時支持Git和HG,並支持GitHub和Bitbucket,再不用輸密碼什麼的。

UI設計挺好,支持全局.ignore文件。

附傳送門:Free Mercurial and Git Client for Windows and Mac


oh-my-zsh git plugin with git alias makes you to use git any time, don"t forget to configure your ssh key to get access the repo.


在git裡面加了十多條alias在圈子裡什麼水平?

感覺alias要被我玩壞了。

md-blog/git/git-config.sh at master 路 lexdene/md-blog 路 GitHub


  1. 循序漸進, 實踐中學習

    git博大精深, 命令眾多, 每個命令的參數又很多. 不要想著看一遍書或者文檔, 然後就可以記住所有的使用方法. 應該在實踐中學習, 吸收大家的經驗, 逐漸提高.
  2. 不排斥alias, 善用alias

    同意之前的回答, alias會影響對git本身命令的熟悉程度. 不過對已經熟悉的命令, 結合自身情況適用alias肯定是事半功倍的事情.
  3. 適用圖形界面

    這裡推薦GitX. 最開始用純命令行, 後來用了GitHub官方客戶端之後, 查看diff就用GUI了. 再後來接觸了GitX之後, 就不再使用GitHub客戶端了. 如果只是看history的話, 命令行里再好看的git lg也不如GitX里用起來方便.
  4. 冷僻的命令

    filter-branch, 用腳本的方式修改大量的提交. 如果你想把你的項目開源, 開源之前應該肯定需要用到這個命令.

    bisect, 其實在了解這個命令之前, 一直在用人肉的方式來模擬這個過程. 知道這個命令之後就方便多了.
  5. hook

    客戶端hook, 以及伺服器端hook. 可以用客戶端hook做一些基本的檢查, 也能起到事半功倍的效果.

    比如空格和tab鍵. 我們的項目里要求大家用四個空格來代替tab, 為了達到這個目的, 要求在Eclipse或者IntelliJ里做設置. 但是新成員很可能會忽略這一點, 然後merge到代碼庫里. 用pre-commit hook可以做檢查, 在commit的時候就給出warning.


1. 熟練掌握常用命令

如果尚不能熟練使用工作、生活中常用的一些git命令,敲擊命令的時候一腦袋問號,我相信這絕逼不是高雅。clone有哪些常用參數?push的時候什麼時候可以簡寫?錯誤操作如何挽回?分支到底是個什麼玩意,怎麼才能玩得轉?等等問題,都屬於日常使用過程中經常遇到,或有很大機率會遇到的,應該熟練掌握。遇到此類問題思維不卡頓方能高雅初現。

2. 關於alias

堅決反對任何alias!這確實能夠帶來使用上的方便,不是一點半點,這是好的一面。但是因為git的多樣性,每個子命令往往都帶有眾多參數,這些參數能夠通過多種形式的匹配達到最符合當前使用場景的目的。而這也正是git的魅力之處(此處不評論svn,各位自行腦補),大量使用alias嚴重影響使用者對git本身命令的熟知程度,以及git的操作性。說嚴重了,離開了你的alias,git形同陌路。沒有魅力的git,形同陌路的git,這又哪有什麼高雅可言呢?

3. 偏門命令

filter-branch命令想必很少人會用,不過這個命令卻有著超級強悍的戰鬥力,可批量修改commit;

blame/bisect等命令的熟練使用可以快速幫助開發者定位問題;

rebase雖可能屬於常用命令,但是其用法多變,有如72變般讓普通使用者難以琢磨;

rev-list/caf-file命令在日常使用中就更少了,但是有些情景下偶爾用處來還是很方便快捷的。

等等等等git的偏門命令,雖不常用,但是如果在恰當的時候、恰當的情景下,偶爾用出來那麼一兩次解決大大小小的問題。優雅程度直線上升有沒有?

4. 關於shell和git圖形界面

對於shell和git的圖形界面個人認為沒有必要糾結,也沒有任何必要追求完全的個性化。ubuntu下的自帶shell我可以用的來;裝個terminator是好看了點,當然照樣用的來;Windows下裝個git那麼撮的shell也完全不影響使用;當然了,如果你給我一個mac,照用不誤。正如優雅人士在什麼情況、什麼場景中都是優雅的,不是因為別的外在因素,而是因為其自身的形象與氣質。


Oh shit, Git! 快速解決Git最常見問題 - 譯棧 - 知乎專欄

幾種最常見的問題,掌握之後,大部分時候會很輕鬆了。


說到`優雅`,這個要求就很高了,上面的回答里我只覺得GIT與VIM搭是很`優雅`的。自己這裡補充下Linus Torvalds給出的使用Git的建議,主要關於分支的管理方面,我覺得能達到的話,在分支管理方面的話就很`優雅`了。原文鏈接如下:

發明人Linus Torvalds給出的Git使用建議

該文精彩的論述了什麼時候用rebase,什麼時候不能用。同時分析了使用Pull,Merge,Push的時機。其中主要提到了如下一系列的觀點。我讀後感覺`優雅`就是一個美妙的平衡。

"clean history"

"Merging too much vs too little"

never EVER destroy other peoples history

Keep your own history readable

Don"t expose your crap

Don"t merge upstream code at random points

Don"t merge downstream code at random points either


永遠保持工作區乾淨。

重複1萬次。

永遠不要git push -f

重複1萬次。


良好排版的原文見我的博客gg(思密達)———good use of git,一個實用的git分支模型v0.2 ? Fmajor"s Blog

寫在前面:在我建議你使用git前,首先要給你潑一盆冷水,見博文我痛恨git的10個理由,以下為文中的片段:

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

如果你是一個架構師,那麼 Git 是很棒的。但對用戶來說它很糟糕,已經有不少人在為 Git 編寫一些簡化的介面,例如 easygit。

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

git是如此的強大,強大到你都不知道該怎麼使用它才好了…

本文提出了一個「git該怎麼在科研實踐中輕鬆的使用」的一個模型,包含眾多的規範來約束你git的使用方法。所謂沒有規矩不成方圓,遵循了模型中的約束條件後,你的git倉庫會變得清晰、優雅起來;你會享受你那結構清晰的network圖(而不是之前那亂糟糟的圖形),而你的合作者也能從你的提交序列中清楚的認識到你的工作思路。

當然,每次使用git的時候都要小心翼翼的遵循這些規範是一件困難的事情。所以我開發了一套腳本,Fmajor/gg 路 GitHub

gg(good use of git),來傻瓜式的實現下述的模型。

=============模型開始的分割線===============

模型思想基於A successful Git branching model,結合本人的學習工作實際和腦洞,升級為此模型。

聲明:本文只討論模型,並不討論模型的具體實現過程,技術密集文章恐懼患者請放心食用。

一、引言:版本控制

二、模型術語、假設、約定和其用途

對於關注此問題的人來說以上兩點不必多說.

下面進入本回答正題

========開始回答問題的分割線==========

用途:此模型主要用於實現三種類型的任務

1.開發型:

舉例:進行新程序的開發/論文的寫作/小組合作完成一件工作等

特點:在進行這類工作時我們主要的行為有

1.為工作不斷增加新特性(新的程序功能/論文新的章節/工作新的任務)

2.當工作的狀態相對穩定的時候,發布出一個階段性成果(程序的一個發布版本/論文的n稿完成/工作的一個階段完成)

3.發現並修改工作中的錯誤,進一步完善工作(程序bug的發現與debug/論文的修改/工作的完善)

4.經常需要進行大膽的實驗,需要方便和安全的試錯環境(debug中的嘗試/論文中的新想法/工作中完成任務的新方法)

下圖:開發型工作的開發流程示例

2.使用型:

舉例:並不進行程序的開發,而是使用別人的程序,完成自己的工作。比如在網上下載了一個數值相對論的模擬程序,我用他來進行兩個模擬:

1.雙黑洞的繞轉

2.光線在黑洞附近的傳播行為

每完成一個任務,我都需要修改程序的配置文件和提供一些初始數據,也就是說我每次用這個程序只能完成一個模擬,當我想進行另外一項模擬的時候就需要重新修改一些文件,而我需要時不時的在兩個模擬工作間進行切換。

特點:這種類型的任務是以工作為中心的,程序是為工作服務的,我們的主要行為有

1.選定適當的程序版本,開始進行工作

2.以選定的程序為基礎,修改程序的配置文件,推進工作

3.發現所使用的程序有新版本,決定嘗試升級程序(更新的原則是不求最新,但求能用)

3.1.發現新版本的程序果然給力,從此將工作移植到這個版本的程序上

3.2.發現還是使用老版本的程序比較好(更穩定?更習慣那種程序介面?新程序有新bug?),回到升級前的狀態繼續推進工作

3.3.在新老程序的基礎上獨立的向前推進

4.完成工作

下圖:使用型工作的流程示例

3.開發使用型:

以上兩種類型的合體,只需要把自己開發出的穩定版本程序作為工作所使用的程序即可

假設:存在以下幾種類型的分支

1.master類型分支,名為?|master或master,其中?為開發代號

2.develop類型分支,名為?|develop或develop,其中?為開發代號

3.feature類型分支,名為feature/*或?|feature/*,其中*為特徵描述

4.release類型分支,名為release-*或?|release-*,其中*為要發布的版本號

5.hotfix類型分支,名為hotfix-*或?|hotfix-*,其中*為要發布的版本號

6.issues類型分支,名為issues/*或?|issues/*,其中*為問題描述

7.trials類型分支,名為?%trials.*,?為此分支的父分支,*為描述的名稱(或直接為?%trials)

8.basedOn類型分支,名為basedOn或?|basedOn,?為其來源的master分支的開發代號

9.work類型分支,名為work.***/basedOn-?-*,***代表此描述此work的名稱,?為其所基於的分支的開發代號,最後一個*代表其在?|basedOn上所基於的分支的版本號或狀態名

下面介紹模型中的約定,並定義gg-*這樣的抽象動作來完成約定中的行為

約定:

1.每一次的提交都必須有意義:

 git在每次提交的時候要求輸入對此提交的概括,這個概括不能為空。

  正確的提交概括:更新了程序doc

  錯誤的提交概括:我剛才幹了些啥?

2.開發型任務中的master類型與develop類型分支必須成對出現,master分支的推進只能來源與release分支和hotfix分支的合併,禁止在master分支上直接提交。

註解:master分支上只有我們推送上去的穩定版本的程序,develop分支上的程序一直處於開發狀態,不穩定。

在開發型任務中使用gg-init進行版本控制的初始化,建立配套的master~develop分支對。

在使用型任務中使用gg-work-init進行版本控制的初始化,拉取需要使用的穩定版本程序的master分支,並初始化對應的basedOn分支(見9)。

3.feature類型分支滿足:

 3.1.只能從develop類型分支上創建

 3.2.最終必須合併到develop類型分支

 3.3.最終分支被刪除

註解:每當有新特性需要加入的時候,我們應該從develop類型分支上新建一個feature類型分支,完成新特性的開發和測試後將特性合併到develop類型分支上。

在develop類型分支上使用gg-feature-open featureName建立並轉向一個名為feature/featureName的新分支

在一個feature類型分支上使用gg-feature-close把這個分支的工作合併到develop類型分支上,刪除此分支,完成一個特性的開發

4.release類型分支滿足:

 4.1.只能從develop類型分支上創建

 4.2.最終必須同時合併到master類型分支(發布新的版本)和develop類型分支(基於新版本的進一步開發)

 4.3.最終分支被刪除

註解:每當工作進入到一個較為穩定階段的時候,我們可以使用gg-release-open versionNum建立並轉向一個名為release-versionNum的臨時分支,在這個分支上允許進行小的改動(比如修改一下readme文件中的版本號),然後使用gg-release-close將此版本合併(發布)到master類型分支上,同時合併到develop類型分支上,然後刪除此分支。

5.hotfix類型分支滿足:

 5.1.只能從master類型分支上創建

 5.2.最終必須同時合併到master類型分支(發布新的熱補丁版本)和develop類型分支(基於新版本的進一步開發)

 5.3.最終分支被刪除

註解:當新版本發布後發現必須馬上解決的嚴重bug時,我們應該使用gg-hotfix-open versionNum建立並轉向一個名為hotfix-versionNum的臨時分支,在這個分支上完成bug的修復,然後使用gg-hotfix-close將此版本合併(發布)到master類型分支上,同時合併到develop類型分支上,然後刪除此分支。

6.issues類型分支滿足:

 6.1.只能從develop類型分支上創建

 6.2.最終必須合併到develop類型分支

 6.3.最終分支被刪除

註解:每當有(比較複雜的)問題需要解決的時候,我們應該從develop類型分支上新建一個issues類型分支,完成問題的調試後合併到develop類型分支上。

在develop類型分支上使用gg-issues-open featureName建立並轉向一個名為issues/issuesName的新分支

在一個issues類型分支上使用gg-issues-close把這個分支的工作合併到develop類型分支上,然後刪除此分支,解決了一個複雜的問題

issues類型和feature類型的實現方式一模一樣,僅僅有名字上面的差別。

7.trials類型分支滿足:

 7.1.可以從除了release類型分支以外的任何類型分支上創建

 7.2.在這個分支上請發揮想像力大膽實驗

這個分支最後的結局可能為

 7.3.1.接受實驗結果,把實驗過程併入父分支,稱為good-close

 7.3.2.實驗結果不理想,放棄實驗結果,從實驗開始前重新來過,稱為bad-close

 7.4.最終分支被刪除

註解:在滿足條件的分支A上工作,時不時會冒出一些大膽的想法,這個時候使用gg-trials-open trialsName創建並轉向一個名為A/trials.trialsName的實驗分支,在這個分支上進行瘋狂的實驗,然後

 1.使用gg-trials-good-close完成實驗的和其父分支的合併,刪除此分支或

 2.使用gg-trials-bad-close進行狀態指針的備份並刪除此分支。

以上是開發型工作所需要的全部模型,對於使用型的工作,還需要

8.basedOn類型分支滿足:

 8.0.從name|master建立並初始化為name|basedOn

 8.1.只能從對應的master分支fork到此分支

 8.2.禁止在這個分支上提交

註解:這個分支是一個為了使工作流程更為清晰的緩存分支,分支上只有從master穩定分支上挑選出來的自己在工作中將要(嘗試)使用的穩定版本。在basedOn類型分支上使用gg-select 版本號 從對應的master分支上選出一個穩定版本或使用gg-select-the-latest從對應的master分支上選擇最新的版本,fork到這個分支,並加上inUse-versionNum的標籤

從master到此分支的行為是fork,即有可能此分支的log為 (init)v1.0===&>v0.9=====&>v0.8======&>v1.3,這個分支上的commit來源於master,但是其分支提交歷史與master分支無關

9.work類型分支滿足:

 9.1.只能從basedOn類型分支上創建

 9.2.可以藉助basedOn分支升級

註解:

1.創建工作:假設我們已經在A.basedOn分支上選出了最新的需要使用的程序版本v1.0,這時候在A|basedOn上使用gg-work-open-from-current-state workName創建並切換到work-workName/basedOn-A-v1.0分支,開始進行工作,或者使用首先移動到A|basedOn 上面的 inUse-v0.5 版本,然後使用gg-work-open-from-current-state workName,創建並切換到work-workName/basedOn-A-v0.5分支。

2.升級工作:假設我們在工作分支work.workName/basedOn-devCode-tagName上工作,這個時候有人通知你你使用的程序的最新版本發布了,於是你pull origin master將master分支更新為最新的版本號newVersionNum,然後在basedOn分支上使用gg-select-the-leatest將新分支fork到basedOn分支,然後回到工作分支,使用gg-work-update自動創建work-workName/basedOn-newVersionNum,解決完合併衝突後你的工作已經升級為基於最新版本的程序,這個時候你可以測試這個新版本來決定是否使用,也可以隨時切換為老版本繼續在上面工作。如果使用gg-work-update-with tagsOnbasedOn則使用basedOn分支上的特定版本的程序對此程序進行升級(也有可能是「降級」),總之就是一個update的操作。

對於開發使用型的任務,只需要把自己開發出的穩定版本程序作為工作所使用的程序即可

總結:

我們需要知道最最最最基本的git 命令如

  1. git add
  2. git commit -a
  3. git push
  4. git pull
  5. git checkout

本模型提出了以下這些操作

開發型任務中可以使用的:

gg-init

gg-feature-open

gg-feature-close

gg-release-open

gg-release-close

gg-hotfix-open

gg-hotfix-close

gg-issues-open

gg-issues-close

gg-trials-open

gg-trials-good-close

gg-trials-bad-close

使用型任務中可以使用的:

gg-select

gg-select–the-leatest

gg-work-open-from-current-state

gg-work-update

gg-work-update-with

這些操作的具體實現包括一些約束條件的檢測(嚴格遵照上述模型才能提交)和一些git的操作,將在Fmajor/gg 路 GitHub中一一實現

這就是我在日常的學習工作實踐中使用的(幾乎)所有關於git的命令,所用即所想,拋掉多餘的操作,專註於工作的本身,同時使工作有非常清晰的結構,便於自己欣賞和小組合作.

如果好用,請到github上給我點一顆星星哦~

歡迎討論此模型~


安裝github Windows客戶端,sync一下,特別爽。


github for windows從此免去了維護那個不知道什麼key的煩惱,給用戶名密碼直接clone!


不用那麼複雜吧。Git 就是很簡單的幾個原則嘛。1. 有任何想法的時候首先branch ;2. push 出去以後千萬不要rebase 。然後就行了。


優雅地使用Git之前,先要了解Git的背景由來。

任何事物,即使其自身很優雅,但你對它沒興趣,那麼對你而言就是不優雅的。

另外,從技術上來講:《Git權威指南》是非常棒的一本書,學好了就能從技術上優雅使用Git了。Git權威指南(《程序員》雜誌「2011年度十大最具技術影響力圖書」,Git官方維護人范凱聯袂推薦)


不改gitconfig情況下,SourceTree很好用


github客戶端超慢的載入速度,功能又少,除了界面比較好看以外我是沒有看到別的任何優點.

win平台都沒有人提Git Extension這個強力的git GUI,可以內置VS不說,pull和push的速度都能基本達到shell命令行的速度了。

mac平台我現在用的是GitX(rowanj/gitx · GitHub),是GitX的一個分支,感覺功能也夠了。基本的push和pull還是命令行。

mac上的SourceTree,在我下載那會有一個冗長的註冊流程,而且在我註冊總是失敗,我就轉投gitX了(未註冊可以試用30天),我是很不能明白一個免費軟體為何還要用戶強制註冊的緣由了。。

===更新===

居然沒人點up vote。。那我只好來添加點基本的GUI優勢了。。

我經常會需要commit一個文件的部分修改而不是所有的修改,這個用git extension(GitX也可以,我猜source tree也是可以的)可以很簡單的做到。


了解了Git之後,使用圖形化界面版本,比如SourceTree


tig


emacs 的話用magit


推薦閱讀:

github for windows安裝失敗了,怎麼辦?
github上怎麼刪除一個文件夾?
github 自己創建了一個項目A,我的同事fork一個B,當我的項目更新的時候,怎麼樣在他fork的repo上進行相應的更新?
Git commits歷史是如何做到如此清爽的?
使用git,用命令好還是客戶端好?

TAG:版本控制系統 | 編程 | 信息技術IT | Git |