Git版本控制使用方法入門教程

1.概述 linux

對於軟件版本管理工具,酷訊決定摒棄CVS而轉向Git了。 git

爲何要選擇Git? 你真正學會使用Git時, 你就會以爲這個問題的回答是很是天然的。然而當真正須要用文字來回答時,卻以爲文字好像不是那麼夠用。 咳,該則麼回答呢? 程序員

其實,關鍵的問題不在於如何回答這個問題。 問題的關鍵是公司已經決定使用它了。那麼,咱們的程序員們! 請開動大家的瀏覽器,請拿出你的搜索引擎工具,去本身發掘答案吧。在這裏,我只能給大家一個最朦朧的感受。 瀏覽器

Git和 CVS、SVN不一樣,是一個分佈式的源代碼管理工具。Linux內核的代碼就是用Git管理的。它很強,也很快。它給咱們帶來的直接好處有: 服務器

1. 傻瓜都會的初始化,git init, git commit -a, 就完了。對於隨便寫兩行代碼就要放到代碼管理工具裏的人來講,再合適不過。也能夠拿git作備份系統,或者同步兩臺機器的文檔,都很方便。 ssh

2. 絕大部分操做在本地完成,不用和集中的代碼管理服務器交互,終於能夠隨時隨地大膽地check in代碼了。 只有最終完成的版本才須要向一箇中心的集中的代碼管理服務器提交。 分佈式

3. 每次提交都會對全部代碼建立一個惟一的commit id。不像CVS那樣都是對單個文件分別進行版本的更改。因此你能夠一次性將某次提交前的全部代碼check出來,而不用考慮到底提交過那些文件。(其實SVN也能夠作到這點) 工具

4. branch管理容易多了,不管是創建新的branch,仍是在branch之間切換都一條命令完成,不須要創建多餘的目錄。 學習

5. branch之間merge時,不只代碼會merge在一塊兒,check in歷史也會保留,這點很是重要。 搜索引擎

6. … 太多了

固然,Git也會帶給咱們一些困難,首先,你想要使用好git, 就要真正明白它的原理,理解它的觀念,對以那些CVS的熟手來講,改變你已經固有的純集中式源代碼管理的觀念尤其重要,同時也會讓你以爲有些困難。在使用 git的初期,你可能會以爲有些困難,但等你逐漸明白它時,你絕對會喜歡上它。這是必定的,就像我問你「喜歡一個溫吞如水、毫無感受的主婦,仍是喜歡一個 奔放如火,讓你愛的癡狂恨的牙癢的情人 」同樣毋庸置疑。

下面,就讓咱們進入學習Git之旅…

請記住,這只是一個很是簡單並且初級的教程, 想要成爲git的專家,須要各位同事不斷的本身深刻挖掘。

2. Git基礎命令

2.1 建立Git庫—git-init

大家曾經建立過CVS的庫麼?應該不多有人操做過吧?由於不少人 都是從CVS庫裏checkout代碼。一樣,在合做開發中,若是你不是一個代碼模塊的發起者,也不會使用到這個命令,更多的是使用git- clone(見2.7節)。可是,若是你想我的開發一個小模塊,並暫時用代碼管理工具管理起來(其實我就常這麼作,至少不少我的開發過程均可以保留下來, 以便備份和恢復),建立一個 Git庫是很容易和方便的。

對於酷訊來講,當一個代碼的Git庫建立後,會添加代碼文件到庫裏,並將這個庫放到公司一個專門用來進行代碼管理的服務器上,使你們能夠在之後clone(不明白?不要緊,繼續日後看就明白了)它。對於我的來講,你能夠隨便將這個庫放到哪裏,只要你能訪問的到就行。

建立一個Git庫是很容易和方便的,只要用命令 git-init 就能夠了。在Git1.4以前(包括git1.4)的版本,這個命令是git-init。

a) $ mkdir dir

b) $ cd dir

c) $ git-init

這樣,一個空的版本庫就建立好了,並在當前目錄中建立一個叫 .git 的子目錄。之後,因此的文件變化信息都會保存到這個目錄下,而不像CVS那樣,會在每一個目錄和子目錄下都建立一個討厭的CVS目錄。

在.git目錄下有一個config文件, 須要咱們添加一下我的信息後才能使用。不然咱們不能對其中添加和修改任何文件。

原始的config文件是這樣的,

[core]

repositoryformatversion = 0

filemode = true

bare = false

logallrefupdates = true

咱們須要加入

[user]

name = xxx

emai= xxx@kuxun.cn

如今已經建立好了一個 git 版本庫,可是它是空的,還不能作任何事情,下一步就是怎麼向版本庫中添加文件了。若是但願忽略某些文件,須要在git庫根目錄下添加. gitignore文件。

2.2 一條重要的命令 -- git-update-index

在介紹如何向git庫中添加文件前,不得不先介紹git- update-index命令。這條命令可能會使不少熟悉CVS的用戶疑惑,通常來講,咱們向一個源代碼管理庫提交代碼的更改,都會抽象爲如下的動做:更 改文件;向源碼管理系統標識變化;提交。好比從一個CVS庫裏刪除一個文件,須要先刪除文件,而後cvs delete; 最後cvs commit。

所以, git-update-index就是向源碼管理系統標識文件變化的一個抽象操做。說的簡要一些,git-update-index命令就是通知git庫 有文件的狀態發生了變化(新添、修改、刪除等待)。這條命令在早期的git版本中是很是經常使用的。在新的git版本(1.5版本及之後)已經被其它命令包裝 起來,而且不推薦使用了。

git-update-index最經常使用的方式有如下兩種,更多功能請man git-update-index。

方法一:git-update-index --add 文件名列表。 若是文件存在,則這條命令是向git庫標識該文件發生過變化(不管是否該文件確實被修改過),若是文件不存在,則這條命令是向git庫表示須要加入一個新文件。

方法二: git-update-index --force-remove 文件名列表。 這表示向git庫表示喲啊從庫中刪除文件。不管該文件是否已經被刪除,這條命令僅僅是通知git庫要從庫中刪除這些文件。這些文件都不會受影響。

所以,git-update-index僅僅是向git庫起到一個通知和標識的做用,並不會操做具體的文件。

2.3 向git庫中添加或刪除文件 – git-add、git-rm

其實,說使用git-add命令向git庫裏添加文件是不對的, 或者說至少是不全面的。git-add 命令的本質是命令"git-update-index --add」 的一個包裝。所以,git-add除了能夠添加文件,還能夠標識文件修改。在調用了git-add後,才能夠作commit操做。git-rm 也是同樣, 它是git-update-index --force-remove的一個包裝。

對於git-add來講, 若是在一個目錄下調用了git-add * ,則默認是遞歸將子目錄中全部文件都add到git庫中。對於git-rm來講,也是同樣。 這點和CVS有較大區別。

此外,咱們還能夠經過命令git-ls-files來查看當前的git庫中有那些文件。

2.4 查看版本庫狀態—git-status

經過該命令,咱們能夠查看版本庫的狀態。能夠得知那些文件發生了變化,那些文件尚未添加到git庫中等等。 建議每次commit前都要經過該命令確認庫狀態。以免誤操做。

其總,最多見的誤操做是, 修改了一個文件, 沒有調用git-add通知git庫該文件已經發生了變化就直接調用commit操做,從而致使該文件並無真正的提交。若是這時若是開發者覺得已經提交 了該文件,就繼續修改甚至刪除這個文件,那麼修改的內容就沒有經過版本管理起來。若是每次在提交前,使用git-status查看一下,就能夠發現這種錯 誤。所以,若是調用了git-status命令,必定要格外注意那些提示爲 「Changed but not updated:」的文件。這些文件都是與上次commit相比發生了變化,可是卻沒有經過git-add標識的文件。

2.5 向版本庫提交變化 – git-commit

直接調用git-commit命令,會提示填寫註釋。也能夠經過以下方式在命令行就填寫提交註釋:git-commit -m "Initial commit of gittutor reposistory"。 注意,和CVS不一樣,git的提交註釋必須不能爲空。不然就會提交失敗。

git-commit還有一個 –a的參數,能夠將那些沒有經過git-add標識的變化一併強行提交,可是不建議使用這種方式。

每一次提交,git就會爲全局代碼創建一個惟一的commit標識代碼,用戶能夠經過git-revert命令恢復到任意一次提交時的代碼。 這比CVS不一樣文件有不一樣的版本呢號管理可方便多了。(和SVN相似)

若是提交前,想看看具體那些文件發生變化,能夠經過git-diff來查看, 不過這個命令的輸出並不友好。所以建議用別的工具來實現該功能。在提交後,還能夠經過git-log命令來查看提交記錄。

2.6 分支管理 – git-branch

咱們迎來了git最強大,也是比CVS、SVN強大的多的功能 — 分支管理。

大概每一個程序員都會常常遇到這樣的狀況:

1. 須要馬上放下手頭的工做,去修改曾經一個版本的bug並上線,而後再繼續當的工做。

2. 本想向中心庫commit一個重要修改,可是因爲須要常常備份代碼,最終不得不頻繁的向中心庫commit。從而致使大量無用的commit信息被保留在中心庫中。

3. 將一次修改提交同事進行code review, 可是因爲同事code review比較慢, 獲得反饋時,本身的代碼已經發生了變化,從而卻是合併異常困難

這些場景,若是用CVS或者SVN來解決,雖然說不必定解決不了,但過程之繁瑣,之複雜,確定另全部人都有生不如死的感受吧!究其關鍵,就是CVS或者SNV的branch管理太複雜,基本不具可用性。

在 git 版本庫中建立分支的成本幾乎爲零,因此,沒必要吝嗇多建立幾個分支。當第一次執行git-init時,系統就會建立一個名爲」master」的分支。而其它分支則經過手工建立。下面列舉一些常見的分支策略,這些策略相信會對你的平常開發帶來很大的便利。

1.建立一個屬於本身的我的工做分支,以免對主分支 master 形成太多的干擾,也方便與他人交流協做。

2.當進行高風險的工做時,建立一個試驗性的分支,扔掉一個爛攤子總比收拾一個爛攤子好得多。

3.合併別人的工做的時候,最好是建立一個臨時的分支用來合併,合併完成後在「fatch」到本身的分支(合併和fatch後面有講述,不明白就繼續往下看好了)

2.6.1 查看分支 – git-branch

調用git-branch能夠查看程序中已經存在的分支和當前分支

2.6.2 建立分支 – git-branch 分支名

要建立一個分支,可使用以下方法:

1. git-branch 分支名稱

2. git-checout –b 分支名

使用第一種方法,雖然建立了分支,可是不會將當前工做分支切換到新建立的分支上,所以,還須要命令」git-checkout 分支名」 來切換, 而第二種方法不但建立了分支,還將當前工做分支切換到了該分支上。

另外,須要注意,分支名稱是有可能出現重名的狀況的, 好比說,我在master分支下建立了a和b兩個分支,而後切換到b分支,在b分支下又建立了a和c分支。 這種操做是能夠進行的。 此時的a分支和master下的a分支其實是兩個不一樣的分支。所以,在實際使用時,不建議這樣的操做,這樣會帶來命名上的疑惑。

2.6.3 刪除分支 – git-branch –D

git-branch –D 分支名能夠刪除分支,可是須要當心,刪除後,發生在該分支的全部變化都沒法恢復。

2.6.4 切換分支 – git-checkout 分支名

若是分支已經存在, 能夠經過 git-checkout 分支名 來切換工做分支到該分支名

2.6.5 查看分支歷史 –git-show-branch

調用該命令能夠查看分支歷史變化狀況。 如:

* [dev1] d2

! [master] m2

--

* [dev1] d2

* [dev1^] d1

* [dev1~2] d1

*+ [master] m2

在上述例子中, 「--」之上的兩行表示有兩個分支dev1和master,且dev分支上最後一次提交的日誌是「d2」,master分支上最後一次提交的日誌是」m2」。 「--」之下的幾行表示了分支演化的歷史,其中 dev1表示發生在dev分支上的最後一次提交,dev^表示發生在dev分支上的倒數第二次提交。dev1~2表示發生在dev分支上的倒數第三次提交。

2.6.6 合併分支 – git-merge

git-merge的用法爲:git-merge 「some memo」 合併的目標分支 合併的來源分支。如:

若是合併有衝突,git會由提示,當前,git-merge已經不多用了, 用git-pull來替代了。

用法爲:git-pull 合併的目標分支 合併的來源分支。 如git-pull . dev1

2.7 遠程獲取一個git庫 git-clone

在2.1節提到過,若是你不是一個代碼模塊的發起者,也不會使用到git-init命令,而是更多的是使用git-clone。經過這個命令,你能夠從遠端完整獲取一個git庫,並能夠經過一些命令和遠端的git交互。

基於git的代碼管理的組織結構,每每造成一個樹狀結構,開發者 通常從某個代碼模塊的管理者的git庫經過git-clone取得開發環境,在本地迭代開發後,再提交給該模塊的管理者,該模塊的管理者檢查這些提交併將 代碼合併到本身的庫中,並向更高一級的代碼管理者提交本身的模塊代碼。

對於酷訊來講,公司會有一箇中心的git庫, 你們在開發時,都是從中心庫git-clone獲取最新代碼。

git-clone的使用方法以下: git-clone [ssh://]username@ipaddr:path。 其中, 「ssh://」可選,也有別的獲取方式,如rsync。 Path是遠端git的根路徑,也叫repository。

經過git-clone獲取遠端git庫後,.git/config中的開發者信息不會被一塊兒clone過來。仍然須要爲.git/config文件添加開發者信息。此外,開發者還須要本身添加. gitignore文件

另外,經過git-clone獲取的遠端git庫,只包含了遠端git庫的當前工做分支。若是想獲取其它分支信息,須要使用」git-branch –r」 來查看, 若是須要將遠程的其它分支代碼也獲取過來,可使用命令」 git checkout -b 本地分支名遠程分支名」,其中,遠程分支名爲git-branch –r所列出的分支名, 通常是諸如「origin/分支名」的樣子。若是本地分支名已經存在,則不須要「-b」參數。

2.8 從遠程獲取一個git分支 – git-pull

與git-clone不一樣, git-pull能夠從任意一個git庫獲取某個分支的內容。用法以下:

git-pull username@ipaddr: 遠端repository名 遠端分支名:本地分支名。這條命令將從遠端git庫的遠端分支名獲取到本地git庫的一個本地分支中。其中,若是不寫本地分支名,則默認pull到本地當前分支。

須要注意的是,git-pull也能夠用來合併分支。 和git-merge的做用相同。 所以,若是你的本地分支已經有內容,則git-pull會合並這些文件,若是有衝突會報警。

2.9 將本地分支內容提交到遠端分支 – git-push

git-push和git-pull正好想反,是將本地某個分支的內容提交到遠端某個分支上。用法:

git-push username@ipaddr: 遠端repository名 本地分支名:遠端分支名。這條命令將本地git庫的一個本地分支push到遠端git庫的遠端分支名中。

須要格外注意的是,git-push好像不會自動合併文件。這點個人試驗代表是這樣,但我不能確認是不是我用錯了。所以,若是git-push時,發生了衝突,就會被後push的文件內容強行覆蓋,並且沒有什麼提示。 這在合做開發時是很危險的事情。

2.10 庫的逆轉與恢復 – git-reset

庫的逆轉與恢復除了用來進行一些廢棄的研發代碼的重置外,還有一 個重要的做用。好比咱們從遠程clone了一個代碼庫,在本地開發後,準備提交回遠程。可是本地代碼庫在開發時,有功能性的commit,也有出於備份目 的的commit等等。總之,commit的日誌中有大量無用log,咱們並不想把這些 log在提交回遠程時也提交到庫中。 所以,就要用到git-reset。

Git-reset的概念比較複雜。它的命令形式:git-reset [--mixed | --soft | --hard] [<commit-ish>]

命令的選項:

--mixed

這個是默認的選項。 如git-reset [--mixed] dev1^(dev1^的定義能夠參見2.6.5)。它的做用僅是重置分支狀態到dev1^, 可是卻不改變任何工做文件的內容。即,從dev1^到dev1的全部文件變化都保留了,可是dev1^到dev1之間的全部commit日誌都被清除了, 並且,發生變化的文件內容也沒有經過git-add標識,若是您要從新commit,還須要對變化的文件作一次git-add。這樣,commit後,就 獲得了一份很是乾淨的提交記錄。

--soft

至關於作了git-reset –mixed,後,又對變化的文件作了git-add。若是用了該選項, 就能夠直接commit了。

--hard

這個命令就會致使全部信息的回退, 包括文件內容。 通常只有在重置廢棄代碼時,才用它。 執行後,文件內容也沒法恢復回來了。

2.11 更多的操做

以前的10節只簡要介紹了git的基本命令,更多的細節能夠去linux下man git的文檔。

3. 基於git的合做開發

對於酷訊來講,當咱們採用了Git,如何進行合做開發呢? 具體步驟以下:

3.1 獲取最新代碼

酷訊會準備一箇中心git代碼庫。首先,咱們將整理好的代碼分模塊在git中心庫中創建git庫。並將文件add到中心庫中。 接下來,開發者經過git-clone將代碼從中心庫clone到本地開發環境。
對於較大的項目,咱們還建議每一個組選擇一個負責人,由這個負責人負責從中心庫獲取和更新最新的代碼,其它開發者從這個負責人的git代碼庫中clone代碼。此時,對開發者來講,這個負責人的git庫就是中心庫了。

3.2 和中心庫進行代碼合併

使用過CVS的人都知道, 在commit以前,都要作一次cvs update,以免和中心庫衝突。Git也是如此。

如今咱們已經通過了code review, 準備向中心庫提交變化了, 在開發的這段時間,也許中心庫發生了變化,所以,咱們須要在向中心庫提交前,再次將中心庫的master分支git-pull到本地的master分支 上。而且和dev分支作合併。最終,將合併的代碼放入master分支。

若是開發過程提交日誌過多,能夠考慮參照2.10節的介紹作一次git-reset。

此外,若是發現合併過程變化很是多, 出於代碼質量考慮,建議再作一次code review

3.3提交代碼到中心庫

此時,已經徹底準備好提交最終的代碼了。 經過git-push就能夠了。

3.4合做流程總結

你們能夠看到,使用git進行合做開發,這一過程和CVS有不少類似性,同時,加強了如下幾個環節:

1. 開發者在本地進行迭代開發,能夠常常的作commit操做且不會影響他人。 並且即便不在線也能夠進行開發。只須要最後向中心庫提交一次便可。

2. 你們都知道,若是CVS管理代碼,因爲咱們會經常作commit操做。可是在commit以前cvs update時常會遇到將中心庫上的其它最新代碼checkout下來的狀況,此時,一旦出現問題,就很難確認究竟是本身開發的bug仍是其它用戶的代碼帶來了影響。 而使用git則避免了用戶間的開發互相影響。

3. 更有利於在代碼提交前作code review。以往用cvs, 都是代碼提交後才作code view。若是發生問題, 也沒法避免服務器上有很差的代碼。 可是用git,真正向中心庫commit前,都是在本地開發,能夠方便的進行code review, 而後才提交到中心庫。更有利於代碼質量。並且,你們應該能夠感到,使用git的過程當中,更容易對代碼進行code review,由於影響因素更小。

4. 建立多分支,更容易在開發中進行多種工做,而使工做間不會互相影響。 好比user2對user1的代碼進行code review時,就能夠很是方便的保留當時的開發現場,並切換到user1的代碼分支,在code review完畢後,也能夠很是方便的切換會曾經被中斷的工做現場。

相關文章
相關標籤/搜索