Git學(xué)習(xí)筆記

Git教程

一、Git簡介

1.1. Git的誕生
1.2.集中式的vs分布式

二、安裝Git

三、創(chuàng)建版本庫

四、時(shí)光穿梭機(jī)

4.1版本回退
4.2工作區(qū)和暫存區(qū)
4.3管理修改
4.4撤銷修改
4.5刪除文件

五、遠(yuǎn)程倉庫

5.1添加遠(yuǎn)程倉庫
5.2從遠(yuǎn)程庫中克隆

六、分支管理

6.1創(chuàng)建與合并分支
6.2解決沖突
6.3分支管理策略
6.4Bug分支
6.5Feature分支
6.6多人協(xié)作

七、標(biāo)簽管理

7.1創(chuàng)建標(biāo)簽
7.2操作標(biāo)簽

八、使用GitHub

九、自定義Git

9.1忽略特殊定義符
9.2配置別名
9.3搭建Git服務(wù)器

十、總結(jié)

1、Git簡介

Git是什么?

Git是目前世界上最先進(jìn)的分布式版本控制系統(tǒng)(沒有之一)。

Git有什么特點(diǎn)?簡單來說就是:高端大氣上檔次!

1.1 Git的誕生

你也許會(huì)想,為什么Linus不把Linux代碼放到版本控制系統(tǒng)里呢?不是有CVS、SVN這些免費(fèi)的版本控制系統(tǒng)嗎?因?yàn)長inus堅(jiān)定地反對(duì)CVS和SVN,這些集中式的版本控制系統(tǒng)不但速度慢,而且必須聯(lián)網(wǎng)才能使用。有一些商用的版本控制系統(tǒng),雖然比CVS、SVN好用,但那是付費(fèi)的,和Linux的開源精神不符。

1.2 分布式 VS 集中式

  • 集中式
    SVN - CVS - ClearCase(IBM 收費(fèi)) - VSS(微軟)

  • 分布式
    git - BitKeeper(促使git誕生) - Mercurial - Bazaar

目前集中式常用的SVN, 分布式常用git

集中式

集中式版本控制系統(tǒng), 版本庫需要集中的放到一臺(tái)服務(wù)器上, 在工作時(shí), 用自己的電腦從中央服務(wù)器上將目前最新內(nèi)容下載到本地, 實(shí)現(xiàn)效果后再講內(nèi)容推送到中央服務(wù)器.

  • 缺點(diǎn)

1.中央服務(wù)器崩潰, 所有人都干不了活
2.網(wǎng)絡(luò)帶寬會(huì)影響文件下載和上傳速度

分布式

分布式版本控制系統(tǒng)壓根沒有”中央服務(wù)器”這個(gè)東西, 每個(gè)人的電腦都是一個(gè)完整的版本庫, 這樣工作的時(shí)候并不需要網(wǎng)絡(luò). 多人協(xié)作, 在合并作品的時(shí)候, 只需將自己的內(nèi)容傳給對(duì)方, 對(duì)方既可以看到你修改的內(nèi)容. 同時(shí), git提供強(qiáng)大的分支, 可以將項(xiàng)目拆分, 使項(xiàng)目更加安全.

注意

git雖然沒有”中央服務(wù)器”, 但常常找出一臺(tái)電腦來充當(dāng)”中央服務(wù)器”, 不過其作用是為了方便交換, 因?yàn)? 協(xié)作的兩個(gè)人不在同一個(gè)局域網(wǎng), 或者其中一人電腦未開啟等特殊情況.

  • 優(yōu)點(diǎn)

安全性極高, 即便自己的電腦壞了, 只需要從別人的電腦上重新clone一個(gè)版本庫即可
強(qiáng)大的分支, 可以將一個(gè)大項(xiàng)目拆分成若干小功能來實(shí)現(xiàn), 實(shí)現(xiàn)后再合并

安裝git(Linux)

1.在終端輸入 git 查看git信息(如果沒有安裝會(huì)有下方的友好提示)

$ git
The program 'git' is currently not installed. You can install it by typing:sudo apt-get install git

2.如果沒有安裝, 在終端輸入sudo apt-get install git 安裝

注意:

老一點(diǎn)的Debian或Ubuntu Linux,要把命令改為sudo apt-get install git-core,因?yàn)橐郧坝袀€(gè)軟件也叫GIT(GNU Interactive Tools),結(jié)果Git就只能叫g(shù)it-core了。由于Git名氣實(shí)在太大,后來就把GNU Interactive Tools改成gnuit,git-core正式改為git。

3、創(chuàng)建版本庫

版本庫又名倉庫,英文名repository,你可以簡單理解成一個(gè)目錄,這個(gè)目錄里面的所有文件都可以被Git管理起來,每個(gè)文件的修改、刪除,Git都能跟蹤,以便任何時(shí)刻都可以追蹤歷史,或者在將來某個(gè)時(shí)刻可以“還原”。

在一個(gè)有足夠權(quán)限的地方創(chuàng)建空文件夾

在終端使用命令:

$git init
git initInitialized empty Git repository in /Users/michael/learngit/.git/

這時(shí)git參考就建立好了, 而且是一個(gè)空倉庫, 此時(shí)文件夾下會(huì)多一個(gè).git隱藏文件, 它是來跟蹤倉庫變化的, 不要隨意改動(dòng)這個(gè)文件.
將內(nèi)容放到版本庫

1.git add fileName
2.git commit -m "info"

$ git add readme.md
$ git add git_study.md
$ git commit -m "add 2 files."

說明:

git add 告訴 git 我要加入某個(gè)文件, git commit告訴 git 內(nèi)容可以放入版本庫了, git commit后的 -m ‘xxx’ 參數(shù)的意思是這次提交做了哪些改動(dòng), 強(qiáng)烈建議寫上, 因?yàn)橛貌涣硕嗑媚憔蜁?huì)忘了曾經(jīng)做了什么. 因?yàn)?code>git commit 一次可以提交多個(gè)文件, 所以可以先通過add多個(gè)文件, 然后commit一次提交.

4、時(shí)光機(jī)穿梭

  • 在終端使用命令git status查看那些文件被改動(dòng), 以及那些文件將要被commit提交

  • 在終端使用命令git diff查看文件被改動(dòng)了什么

4.1版本回退

如果在修改文件過程中出現(xiàn)了什么錯(cuò)誤, 需要回退到就版本, 怎么辦呢?

在終端使用命令git log查看提交歷史

commit f384b35e6c614ac5444efd0167e29fee66c9c37d
Merge: c65e7a0 2a0f55c
Author: caoyuan <2675142924@qq.com>
Date:   Wed Sep 21 15:46:03 2016 +0800

    merge with no-ff

commit 2a0f55c64f68abb7cb69547063330821a3a0df39
Author: caoyuan <2675142924@qq.com>
Date:   Wed Sep 21 15:35:31 2016 +0800

    add merge

commit c65e7a0f684587adce36c2f972de7fb4ce53cd69
Merge: 28d8785 71dbe9d
Author: caoyuan <2675142924@qq.com>
Date:   Wed Sep 21 14:58:04 2016 +0800

如果覺得內(nèi)容太多, 可以使用命令git log --graph --pretty=oneline --abbrev-commit 查看

yuan@yuan:~/learngit$ git log --pretty=oneline --abbrev-commit
f384b35 merge with no-ff
2a0f55c add merge
c65e7a0 conflict fixed
28d8785 & simple
71dbe9d AND simple
fc62eb2 brach test
4c51d94 remove test.txt
1ee3747 add test.text
5895409 add cao
9a97047 git track changes
440c6b3 understand how stage works
5396aed append GPL
21c867f add 3 file
9c6ce9f add 1 file

說明:
前面的一大串?dāng)?shù)字是commit id, 和SVN不一樣,Git的commit id不是1,2,3……遞增的數(shù)字,而是一個(gè)SHA1計(jì)算出來的一個(gè)非常大的數(shù)字,用十六進(jìn)制表示.

上一個(gè)版本就是HEAD,上上一個(gè)版本就是HEAD,當(dāng)然往上100個(gè)版本寫100個(gè)比較容易數(shù)不過來,所以寫成HEAD~100。

yuan@yuan:~/learngit$ git reset --hard HEAD^
HEAD is now at c65e7a0 conflict fixed

注意:
要重返未來,用git reflog查看命令歷史,以便確定要回到未來的哪個(gè)版本。

4.2工作區(qū)和暫存區(qū)

Git和其他版本控制系統(tǒng)如SVN的一個(gè)不同之處就是有暫存區(qū)的概念。

  • 工作區(qū)

工作區(qū)可以簡單的理解為是git倉庫目錄下內(nèi)容.

  • 暫存區(qū)

回顧一下, 在將內(nèi)容提交到倉庫時(shí)候, 需要先使用git add一下, 此時(shí)這個(gè)add其實(shí)是吧內(nèi)容提交到stage暫存區(qū), 在執(zhí)行commit的使用才會(huì)將stage暫存區(qū)中的內(nèi)容提交到工作區(qū).

git add命令將文件提交到緩存區(qū)

20160921133228815.jpg

Git和其他版本控制系統(tǒng)如SVN的一個(gè)不同之處就是有暫存區(qū)的概念。

先來看名詞解釋。

工作區(qū)(Working Directory)

就是你在電腦里能看到的目錄,比如我的learngit文件夾就是一個(gè)工作區(qū):

working-dir

版本庫(Repository)

工作區(qū)有一個(gè)隱藏目錄.git,這個(gè)不算工作區(qū),而是Git的版本庫。

Git的版本庫里存了很多東西,其中最重要的就是稱為stage(或者叫index)的暫存區(qū),還有Git為我們自動(dòng)創(chuàng)建的第一個(gè)分支master,以及指向master的一個(gè)指針叫HEAD。

git-repo

分支和HEAD的概念我們以后再講。

前面講了我們把文件往Git版本庫里添加的時(shí)候,是分兩步執(zhí)行的:**

第一步:是用git add把文件添加進(jìn)去,實(shí)際上就是把文件修改添加到暫存區(qū);

第二步:是用git commit提交更改,實(shí)際上就是把暫存區(qū)的所有內(nèi)容提交到當(dāng)前分支。

因?yàn)槲覀儎?chuàng)建Git版本庫時(shí),Git自動(dòng)為我們創(chuàng)建了唯一一個(gè)master分支,所以,現(xiàn)在,git commit就是往master分支上提交更改。

你可以簡單理解為,需要提交的文件修改通通放到暫存區(qū),然后,一次性提交暫存區(qū)的所有修改。

俗話說,實(shí)踐出真知?,F(xiàn)在,我們再練習(xí)一遍,先對(duì)readme.txt做個(gè)修改,比如加上一行內(nèi)容:

Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.

然后,在工作區(qū)新增一個(gè)LICENSE文本文件(內(nèi)容隨便寫)。

先用git status查看一下狀態(tài):

$ git status
On branch master
Changes not staged for commit:
 (use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

   modified:   readme.txt

 Untracked files:
   (use "git add <file>..." to include in what will be committed)

   LICENSE
no changes added to commit (use "git add" and/or "git commit -a")

Git非常清楚地告訴我們,readme.txt被修改了,而LICENSE還從來沒有被添加過,所以它的狀態(tài)是Untracked。

現(xiàn)在,使用兩次命令git add,把readme.txt和LICENSE都添加后,用git status再查看一下:

$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

 new file:   LICENSE
 modified:   readme.txt

現(xiàn)在,暫存區(qū)的狀態(tài)就變成這樣了:

git-stage

所以,git add命令實(shí)際上就是把要提交的所有修改放到暫存區(qū)(Stage),然后,執(zhí)行g(shù)it commit就可以一次性把暫存區(qū)的所有修改提交到分支。

$ git commit -m "understand how stage works"
[master 27c9860] understand how stage works
 2 files changed, 675 insertions(+)
 create mode 100644 LICENSE

一旦提交后,如果你又沒有對(duì)工作區(qū)做任何修改,那么工作區(qū)就是“干凈”的:

$ git status
# On branch master
nothing to commit (working directory clean)

現(xiàn)在版本庫變成了這樣,暫存區(qū)就沒有任何內(nèi)容了:

git-stage-after-commit

小結(jié)

暫存區(qū)是Git非常重要的概念,弄明白了暫存區(qū),就弄明白了Git的很多操作到底干了什么。

沒弄明白暫存區(qū)是怎么回事的童鞋,請(qǐng)向上滾動(dòng)頁面,再看一次。

4.3 git撤銷修改

如果在reqdme.txt中多加了一行,在提交前,我們要撤銷修改

刪除添加的行,返回到上一個(gè)歷史版本。

例1:

  yuan@yuan:~/learngit$ git status
    On branch master
    Changes not staged for commit:
    (use "git add <file>..." to update what will be committed)
    (use "git checkout -- <file>..." to discard changes in working directory)
    modified:   readme.txt
    no changes added to commit (use "git add" and/or "git commit -a")

執(zhí)行git status后git會(huì)提醒git checkout -- file

git checkout -- file 可以丟棄工作區(qū)的修改

文件在工作區(qū)的修改全部撤銷

修改后還沒被放到暫存區(qū)

撤銷修改就回到和版本庫一模一樣狀態(tài)

修改后已經(jīng)添加到暫存區(qū)

又作了修改,現(xiàn)在,撤銷修改就回到添加到暫存區(qū)后的狀態(tài)

git commit  
git add
git checkout -- file 

命令中的 --的作用

沒用-- 就變成切換到另一分支命令

git checkout命令

在commit之前發(fā)現(xiàn)這個(gè)問題,git status 修改只是添加到了暫存區(qū),還沒有提交:

```
yuan@yuan:~/learngit$ vim readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes.
dddd cao yuan
i love you
```

通過git diff可以看到里面添加了一個(gè) I love you的內(nèi)容

    yuan@yuan:~/learngit$ git diff
    diff --git a/readme.txt b/readme.txt
    index 5d1ed32..fcb9573 100644
    --- a/readme.txt
    +++ b/readme.txt
    @@ -3,3 +3,4 @@ Git is free software distributed under the GPL.
     Git has a mutable index called stage.
     Git tracks changes.
     dddd cao yuan
    +i love you^M   //此行是添加的內(nèi)容,可以看到前面有一個(gè)+號(hào)

2、我們現(xiàn)在把readme.txt添加到暫存區(qū)

    yuan@yuan:~/learngit$ git add readme.txt  //把readme.txt添加到暫存區(qū)
    yuan@yuan:~/learngit$ git status              //查看狀態(tài)
    On branch master
    Changes to be committed: 
    (use "git reset HEAD <file>..." to unstage) //提示撤銷暫存區(qū)修改
    modified:   readme.txt                     //提示修改reqdme.txt

    yuan@yuan:~/learngit$ git reset HEAD readme.txt //撤銷暫存區(qū)修改,重新放回工作區(qū)
    Unstaged changes after reset:
    M   readme.txt

查看狀態(tài),當(dāng)前已前暫存區(qū)回到的工作區(qū)

 yuan@yuan:~/learngit$ git status     //查看狀態(tài) 
    On branch master  
    Changes not staged for commit:
    (use "git add <file>..." to update what will be committed)
    (use "git checkout -- <file>..." to discard changes in working directory)
    modified:   readme.txt
    no changes added to commit (use "git add" and/or "git commit -a") //

再從工作區(qū)撤銷命令,看到結(jié)果中沒有i love you字母了

    yuan@yuan:~/learngit$ git checkout -- readme.txt   //撤銷工作區(qū)修改
    yuan@yuan:~/learngit$ cat readme.txt               //查看readme.txt
    Git is a distributed version control system.
    Git is free software distributed under the GPL.
    Git has a mutable index called stage.
    Git tracks changes.
    cao                                           

3、如果從暫存區(qū)提交到了版本庫,只能用前面講到的版本回退操作

前提是沒有把本地版本庫推送到遠(yuǎn)程,否則無法撤銷。

總結(jié):

1、修改內(nèi)容有誤時(shí)了,但沒有提交到暫存區(qū) 直接使用 git checkout -- file

2、修改某文件內(nèi)容有誤后,提交到暫存區(qū)想撤銷修改分如下2步

  • 第一步: 先讓文件回到工作區(qū) git rest HEAD file

  • 第二步:從工作區(qū)撤銷修改 git checkout -- file

3、已經(jīng)提交了修改內(nèi)容到版本庫時(shí),想要撤銷本次提交只能用版本回退,前提沒有推送到遠(yuǎn)程庫

4.4 刪除文件

1、添加一個(gè)test.txt新文件

```
yuan@yuan:~/learngit$ vim test.txt
yuan@yuan:~/learngit$ ls      //ls查看到當(dāng)前目錄下多了一個(gè)test.txt文件
LICENSE.txt  readme.txt  test.txt
```

2、把test文件提交到暫存區(qū)

```
yuan@yuan:~/learngit$ git add test.txt               //把test添加到暫存區(qū)
yuan@yuan:~/learngit$ git commit -m "add test.text"  //把test添加到本地庫
[master 1ee3747] add test.text
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 test.txt
```

3、刪除test.txt文件

yuan@yuan:~/learngit$ rm test.txt

刪除后Git知道你刪除了文件,因此,工作區(qū)和版本庫就不一致了

4、git status查看狀態(tài)

    yuan@yuan:~/learngit$ git status
    On branch master
    Changes not staged for commit:
    (use "git add/rm <file>..." to update what will be committed)
    (use "git checkout -- <file>..." to discard changes in working directory)
    deleted:    test.txt                        //提示文件被刪除
    no changes added to commit (use "git add" and/or "git commit -a")

5、是否確認(rèn)刪除文件

如果刪除文件執(zhí)行g(shù)it rm test.txt 刪掉,并且git commit

    yuan@yuan:~/learngit$ git rm test.txt
   rm 'test.txt'
   yuan@yuan:~/learngit$ git commit -m "remove test.txt"
   [master 4c51d94] remove test.txt
    1 file changed, 0 insertions(+), 0 deletions(-)
    delete mode 100644 test.txt

如果不小心刪錯(cuò)了用git checkout -- test.txt 就可以找回來

git checkout用版本庫里的版本替換工作區(qū)的版本,無論工作區(qū)是修改還是刪除,都可以“一鍵還原”。

總結(jié):

1、執(zhí)行g(shù)it rm file 刪除文件

2、只要提交到版本庫不用提心誤刪除,但只能恢復(fù)最版本。

5、遠(yuǎn)程倉庫

1、時(shí)光穿梭可恢復(fù)歷史版本

2、git分布式版本控制系統(tǒng)

同一個(gè)Git倉庫,可以分布到不同的機(jī)器上。

從版本庫機(jī)器上克隆原始版本庫,每臺(tái)機(jī)器都一樣

3、通過一臺(tái)電腦玩遠(yuǎn)程庫

一臺(tái)電腦上可以克隆多個(gè)版本庫,只要不在同一個(gè)目錄下

4、多臺(tái)電腦玩遠(yuǎn)程庫

一臺(tái)電腦當(dāng)服務(wù)器用,其它的電腦從服務(wù)器中克隆一份到電腦上,并把各自的提交到服務(wù)器倉庫,也

可從服務(wù)器拉取最新版本

5、GitHub網(wǎng)站提供版本托管服務(wù)

只要注冊一個(gè)GitHub帳號(hào),就可免費(fèi)獲得Git遠(yuǎn)程倉庫,GitHub通過SSH加密傳輸

第一步:創(chuàng)建SSH Key

查看用戶主目錄下是否有.ssh目錄,有再看看有沒有id_rsaid_rsa.pub這兩個(gè)文件如果有跳過

沒有就創(chuàng)建SSH Key,執(zhí)行完.ssh目錄下生成 id_rsa和id_rsa.pub兩個(gè)密鑰文件,

id_rsa私鑰,不可泄露,id_rsa.pub是公鑰可以告訴別人

ssh-keygen -t rsa -C "2675142924@qq.com"  //更換自己的郵件地址

第2步:登陸GitHub,打開“Account settings”,“SSH Keys”頁面:

然后,點(diǎn)“Add SSH Key”,填上任意Title,在Key文本框里粘貼id_rsa.pub文件的內(nèi)容:
點(diǎn)“Add Key”,你就應(yīng)該看到已經(jīng)添加的Key:

總結(jié):

1、Github 有公鑰就可以確認(rèn)只有你自己推送

2、允許添加多個(gè)key,多臺(tái)電腦,只要把每臺(tái)要訪問的電腦都加到GitHub中,就可以每臺(tái)推送到Github中

3、GitHub免費(fèi)托管的Git倉庫,任何人都可以看到,但只有自己可以修改,所以重要信息不能放進(jìn)去

4、如果不想讓別人看到放在GitHub中第一交點(diǎn)錢,把公開的變成私有的,別人就看不見了,再一個(gè)就是自己

搭建一個(gè)Git服務(wù)器,自己的服務(wù)器別人就看不到

5.1添加遠(yuǎn)程庫

1、創(chuàng)建本地Git倉庫,GitHub創(chuàng)建一個(gè)Git倉庫

2、讓本地倉庫與遠(yuǎn)程倉庫進(jìn)行遠(yuǎn)程同步,可以作為備份

3、登錄GitHub右上角Create a new repo創(chuàng)建一個(gè)新庫

Respository name 填learngit 點(diǎn)擊Create repository

4、本地庫與遠(yuǎn)程庫關(guān)聯(lián)

yuan@yuan:~/learngit$ git remote add origin 2675142924@qq.com:michaelliao/learngit.git

5、本地所有內(nèi)容添加到遠(yuǎn)程庫上

yuan@yuan:~/learngit$ git push -u origin master

用git push命令,實(shí)際上是把當(dāng)前分支master推送到遠(yuǎn)程

第一次推送master加上-u參數(shù)

本地master分支內(nèi)容添加到遠(yuǎn)程新的master分支內(nèi)容
還會(huì)把本地的master分支與遠(yuǎn)程master分支關(guān)聯(lián)起來,方便以后推送

以后推送就可以通過以下命令

    git push origin master

第一次使用Git的clone或者push命令連接GitHub時(shí)會(huì)有警告

The authenticity of host 'github.com (xx.xx.xx.xx)' can't be established.
RSA key fingerprint is xx.xx.xx.xx.xx.
Are you sure you want to continue connecting (yes/no)?

提示確認(rèn)GitHub的Key的指紋信服務(wù)息是否真的來自GitHub服務(wù)器,輸入Yes即可

Warning: Permanently added 'github.com' (RSA) to the list of known hosts.

警告出現(xiàn)一次,后面的操作就不會(huì)有任何警告了

總結(jié):

1、關(guān)聯(lián)遠(yuǎn)程庫使用命令

git remote add origin 2675142924@qq.com:path/repo-name.git

2、第一次推送分支所有內(nèi)容:git push -u origin master

3、以后每次提次只需輸入命令:git push origin master 推送最新修改

6.3分支管理策略

合并分支時(shí),Git會(huì)用Fast forwards模式,這種模式,刪除分支后會(huì)丟掉信息

強(qiáng)制禁用Fast forward模式,Git就會(huì)在merge時(shí)生成一個(gè)新的commit,這樣,從分支歷史上就可以看出分支信息

--no--ff方式的git merge

1、創(chuàng)建并切換dev分支:

yuan@yuan:~/learngit$ git checkout -b dev
Switched to a new branch 'dev'

2、修改readme.txt,提交一個(gè)新的add commit

yuan@yuan:~/learngit$ git add readme.txt
yuan@yuan:~/learngit$ git commit -m "add merge"
[dev 2a0f55c] add merge
 1 file changed, 1 insertion(+), 5 deletions(-)

3、切換回master分支

yuan@yuan:~/learngit$ git branch
* dev
  master
yuan@yuan:~/learngit$ git checkout master
Switched to branch 'master'
yuan@yuan:~/learngit$ git branch
  dev
* master

4、合并dev分支,請(qǐng)注意--no-ff參數(shù),表示禁用Fast forward:

yuan@yuan:~/learngit$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
 readme.txt | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

因?yàn)楸敬魏喜⒁獎(jiǎng)?chuàng)建一個(gè)新的commit,所以加上-m參數(shù),把commit描述寫進(jìn)去。

5、查看分支歷史git log:

yuan@yuan:~/learngit$ git log --graph --pretty=oneline --abbrev-commit  //查看分支

*   f384b35 merge with no-ff
|\  
| * 2a0f55c add merge
|/  
*   c65e7a0 conflict fixed
|\  
| * 71dbe9d AND simple
* | 28d8785 & simple
|/  
* fc62eb2 brach test
* 4c51d94 remove test.txt
……

可以看到,不使用Fast forward模式,merge后就像這樣:

6、分支策略

管理分支原則

master分支非常穩(wěn)定,僅用來發(fā)布新版本,平時(shí)不在上面干活

干活一般都在dev分支上,dev分支是不穩(wěn)定的,到某個(gè)時(shí)候,比如1.0版本發(fā)布,再把dev分支合并到master上,在master分支發(fā)布1.0版本

每個(gè)人都在dev分支上干活,每個(gè)人都可以有自己的分支,時(shí)不時(shí)地往dev分支上合并就可以了

團(tuán)隊(duì)合作的支支看起來就像這樣

總結(jié)

1、合并分支時(shí),加上--no-ff參數(shù)就可以用普通模式合并

2、合并后的歷史有分支,能看出來曾經(jīng)做過合并

3、fast forward合并就看不出來曾經(jīng)做過合并。

6.3Bug分支

開發(fā)中Bug修復(fù)辦法

yuan@yuan:~/learngit$ git status
On branch master
nothing to commit, working directory clean

在Git中分支功能比較強(qiáng)大,每個(gè)bug都可以通過一個(gè)新的臨時(shí)分支來修復(fù),修復(fù)后,合并分支,然后將臨時(shí)分支刪除。

并不是你不想提交,而是工作只進(jìn)行到一半,還沒法提交,預(yù)計(jì)完成還需1天時(shí)間。但是,必須在兩個(gè)小時(shí)內(nèi)修復(fù)該bug,怎么辦?

幸好,Git還提供了一個(gè)stash功能,可以把當(dāng)前工作現(xiàn)場“儲(chǔ)藏”起來,等以后恢復(fù)現(xiàn)場后繼續(xù)工作:

yuan@yuan:~/learngit$ git stash
Saved working directory and index state WIP on dev: f384b35 merge with no-ff
HEAD is now at f384b35 merge with no-ff

現(xiàn)在,用git status查看工作區(qū),就是干凈的(除非有沒有被Git管理的文件),因此可以放心地創(chuàng)建分支來修復(fù)bug。

首先確定要在哪個(gè)分支上修復(fù)bug,假定需要在master分支上修復(fù),就從master創(chuàng)建臨時(shí)分支:

$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 6 commits.
$ git checkout -b issue-101
Switched to a new branch 'issue-101'

現(xiàn)在修復(fù)bug,需要把“Git is free software ...”改為“Git is a free software ...”,然后提交:

yuan@yuan:~/learngit$ git commit -m "fix bug 101"
On branch master
nothing to commit, working directory clean

yuan@yuan:~/learngit$ git commit -m "fix bug 101"
[master 32614a1] fix bug 101
 1 file changed, 1 insertion(+), 1 deletion(-)

修復(fù)完成后,切換到master分支,并完成合并,最后刪除issue-101分支:

$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 2 commits.
$ git merge --no-ff -m "merged bug fix 101" issue-101
Merge made by the 'recursive' strategy.
 readme.txt |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git branch -d issue-101
Deleted branch issue-101 (was cc17032).

太棒了,原計(jì)劃兩個(gè)小時(shí)的bug修復(fù)只花了5分鐘!現(xiàn)在,是時(shí)候接著回到dev分支干活了!

$ git checkout dev
Switched to branch 'dev'
$ git status
# On branch dev
nothing to commit (working directory clean)

工作現(xiàn)場還在,Git把stash內(nèi)容存在某個(gè)地方了,但是需要恢復(fù)一下,有兩個(gè)辦法:

1、是用git stash apply恢復(fù),但是恢復(fù)后,stash內(nèi)容并不刪除,你需要用git stash drop來刪除;

2、另一種方式是用git stash pop,恢復(fù)的同時(shí)把stash內(nèi)容也刪了:

yuan@yuan:~/learngit$ git stash pop
On branch issue-101
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (a3c15cae9ce0df80247abf06a3462f3d7a44a1d0)

3、再用git stash list查看,就看不到任何stash內(nèi)容了

yuan@yuan:~/learngit$ git stash list

4、你可以多次stash,恢復(fù)的時(shí)候,先用git stash list查看,然后恢復(fù)指定的stash,用命令:

git stash apply stash@{0}

總結(jié)

修復(fù)bug時(shí),我們會(huì)通過創(chuàng)建新的bug分支進(jìn)行修復(fù),然后合并,最后刪除;

當(dāng)手頭工作沒有完成時(shí),先把工作現(xiàn)場git stash一下,然后去修復(fù)bug,修復(fù)后,再git stash pop,回到工作現(xiàn)場。

6.4Feature分支

軟件開發(fā)中,總要不斷添加進(jìn)來,添加新功能時(shí)。

你肯定不希望因?yàn)橐恍?shí)驗(yàn)性質(zhì)的代碼,把主分支搞亂了,所以,每添加一個(gè)新功能,最好新建一個(gè)feature分支,在上面開發(fā),完成后,合并,最后,刪除該feature分支。

yuan@yuan:~/learngit$ git checkout -b feature-vulcan
M   readme.txt
Switched to a new branch 'feature-vulcan'

5分鐘后,開發(fā)完畢:

yuan@yuan:~/learngit$ git add vulcan.py
yuan@yuan:~/learngit$ git commit -m "add feature vulcan"
[feature-vulcan afb809a] add feature vulcan
 1 file changed, 1 insertion(+)
 create mode 100644 vulcan.py

切回dev

準(zhǔn)備合并:

yuan@yuan:~/learngit$ git checkout dev

feature分支和bug分支合并,然后刪除。

但是,
就在此時(shí),接到上級(jí)命令,因經(jīng)費(fèi)不足,新功能必須取消!
雖然白干了,但是這個(gè)分支還是必須就地銷毀:

yuan@yuan:~/learngit$ git branch -d feature-vulcan
error: The branch 'feature-vulcan' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature-vulcan'.

銷毀失敗。Git友情提醒,feature-vulcan
分支還沒有被合并,如果刪除,將丟失掉修改,如果要強(qiáng)行刪除,需要使用命令git branch -D feature-vulcan
。
現(xiàn)在我們強(qiáng)行刪除:

yuan@yuan:~/learngit$ git branch -d feature-vulcan
error: The branch 'feature-vulcan' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature-vulcan'.

終于刪除成功!

6.5多人協(xié)作

多人協(xié)作, 往往要用到遠(yuǎn)程倉庫, 那么要如何解決與遠(yuǎn)程倉庫之間的同步以及和伙伴代碼合并的問題呢?
和遠(yuǎn)程倉庫同步

當(dāng)你從遠(yuǎn)程倉庫克隆時(shí),實(shí)際上Git自動(dòng)把本地的master分支和遠(yuǎn)程的master分支對(duì)應(yīng)起來了,并且,遠(yuǎn)程倉庫的默認(rèn)名稱是origin。

可是使用git remote查看遠(yuǎn)程倉庫的信息

$ git remote
origin

或者,使用git remote -v查看詳細(xì)的信息

$ git remote -v
origin git@github.com:michaelliao/learngit.git (fetch)
origin git@github.com:michaelliao/learngit.git (push)

上面顯示了可以抓取和推送的origin的地址。如果沒有推送權(quán)限,就看不到push的地址。

推送分支

推送分支,就是把該分支上的所有本地提交推送到遠(yuǎn)程庫。推送時(shí),要指定本地分支,這樣,Git就會(huì)把該分支推送到遠(yuǎn)程庫對(duì)應(yīng)的遠(yuǎn)程分支上, 比如下面這句就是吧本地的master分支推送到遠(yuǎn)程的master分支上:

$ git push origin master

但是并不是所有分支都需要推送, 像一些大家都需要用到的諸如: master(主分支), dev(開發(fā)分支)等這些需要推送, 像一些只是自己完成任務(wù)的獨(dú)立分支, 類似:bug(修改bug的分支)就不用推送, 除非你的老板想知道你都修改了哪些bug.

抓取分支

多人協(xié)作時(shí),大家都會(huì)往master和dev分支上推送各自的修改。

當(dāng)你的協(xié)作伙伴從遠(yuǎn)程clone時(shí), 他只能看到master分支, 如果想看到dev等其他分支, ,就必須創(chuàng)建遠(yuǎn)程origin的dev分支到本地,可以使用這個(gè)命令創(chuàng)建本地dev分支:

$ git checkout -b dev origin/dev

此后, 你的伙伴就可以在分支上做修改了, 并且會(huì)提交修改, 如果他提交后(此時(shí)有個(gè)問題: 你手里的版本已經(jīng)不是最新版本了), 你同樣做好了修改需要提交, 這時(shí)當(dāng)你pull時(shí), 你會(huì)發(fā)現(xiàn)報(bào)錯(cuò), 因?yàn)槟愫湍愕幕锇榭赡苄薷牧送瑯拥奈募? 這就和前面分支合并一樣, 出現(xiàn)了沖突. 解決辦法也很簡單,Git已經(jīng)提示我們,就是先用git pull把最新的提交從origin/dev抓下來,然后,在本地合并,解決沖突,再推送(這時(shí)可能會(huì)git pull失敗,原因是沒有指定本地dev分支與遠(yuǎn)程origin/dev分支的鏈接,根據(jù)提示,設(shè)置dev和origin/dev的鏈接).

創(chuàng)建分支鏈接

$ git branch --set-upstream dev origin/dev

然后pull到本地

$ git pull

這時(shí), 在本地對(duì)伙伴修改的內(nèi)容和自己修改的內(nèi)容進(jìn)行合并, 會(huì)有合并沖突, 需要手動(dòng)解決, 解決后在推送.

注意:

多人協(xié)作的工作模式通常是這樣:

1、可以試圖用git push origin branch-name推送自己的修改;
2、如果推送失敗,則因?yàn)檫h(yuǎn)程分支比你的本地更新,需要先用git pull試圖合并;
3、如果合并有沖突,則解決沖突,并在本地提交;
4、沒有沖突或者解決掉沖突后,再用git push origin branch-name推送就能成功!
5、如果git pull提示“no tracking information”,則說明本地分支和遠(yuǎn)程分支的鏈接關(guān)系沒有創(chuàng)建,用命令git branch –set-upstream branch-name origin/branch-name。

說明:

  • 查看遠(yuǎn)程庫信息,使用git remote -v;
  • 本地新建的分支如果不推送到遠(yuǎn)程,對(duì)其他人就是不可見的;
  • 從本地推送分支,使用git push origin branch-name,如果推送失敗,先用git pull抓取遠(yuǎn)程的新提交;
  • 在本地創(chuàng)建和遠(yuǎn)程分支對(duì)應(yīng)的分支,使用git checkout -b branch-name origin/branch-name,本地和遠(yuǎn)程分支的名稱最好一致;
  • 建立本地分支和遠(yuǎn)程分支的關(guān)聯(lián),使用git branch –set-upstream branch-name origin/branch-name;
  • 從遠(yuǎn)程抓取分支,使用git pull,如果有沖突,要先處理沖突。

7、標(biāo)簽管理

標(biāo)簽(tag), 一個(gè)簡單的理解就是它記錄了一次commit id, tag一般建立在主分支上, 方便用于版本發(fā)布. 標(biāo)簽和分支類似, 一個(gè)指針指向某次提交, 只不過分支可以繼續(xù)先前移動(dòng), 而標(biāo)簽不可移動(dòng).

7.1創(chuàng)建標(biāo)簽

在創(chuàng)建標(biāo)簽前需要先切換到需要打標(biāo)簽的分支上, 然后使用命令 git tag v1.0 來創(chuàng)建標(biāo)簽. 默認(rèn)標(biāo)簽是打在HEAD指向的地方(即最新提交), 如果想把標(biāo)簽創(chuàng)建在先前的提交上, 需要先知道commit id(用命令git log –pretty oneline –abbrev-commit), 然后用命令 git tag v0.9 6224937 在對(duì)應(yīng)的提交上打上標(biāo)簽, 可以使用 git tag 查看所有標(biāo)簽, 使用命令 git show v0.9 來查看標(biāo)簽詳細(xì)信息.

還可以創(chuàng)建帶有說明的標(biāo)簽,用-a指定標(biāo)簽名,-m指定說明文字:

$ git tag -a v0.1 -m "version 0.1 released" 3628164

還可以通過-s用私鑰簽名一個(gè)標(biāo)簽:

$ git tag -s v0.2 -m "signed version 0.2 released" fec145a

注意:

簽名采用PGP簽名,因此,必須首先安裝gpg(GnuPG),如果沒有找到gpg,或者沒有g(shù)pg密鑰對(duì),就會(huì)報(bào)錯(cuò)

7.2操作標(biāo)簽

如果標(biāo)簽打錯(cuò)了,也可以刪除:

$ git tag -d v0.1

如果要推送某個(gè)標(biāo)簽到遠(yuǎn)程,使用命令git push origin

$ git push origin v1.0

或者,一次性推送全部尚未推送到遠(yuǎn)程的本地標(biāo)簽:

$ git push origin --tags

如果標(biāo)簽已經(jīng)推送到遠(yuǎn)程,要?jiǎng)h除遠(yuǎn)程標(biāo)簽就麻煩一點(diǎn),先從本地刪除:

$ git tag -d v0.9

然后,從遠(yuǎn)程刪除。刪除命令也是push,但是格式如下:

$ git push origin :refs/tags/v0.9

8、使用GitHub

  • 在GitHub上,可以任意Fork開源倉庫;
  • 自己擁有Fork后的倉庫的讀寫權(quán)限;
  • 可以推送pull request給官方倉庫來貢獻(xiàn)代碼。

9、自定義Git

  • 讓Git顯示顏色,會(huì)讓命令輸出看起來更醒目:
$ git config --global color.ui true

8.1忽略特殊文件

在工作目錄下創(chuàng)建.gitignore文件, 在這個(gè)文件中填寫需要忽略的文件內(nèi)容, 然后git add進(jìn)去. 此后這個(gè).gitignore就開始起作用了.

忽略文件的原則是:

  1. 忽略操作系統(tǒng)自動(dòng)生成的文件,比如縮略圖等;

  2. 忽略編譯生成的中間文件、可執(zhí)行文件等,也就是如果一個(gè)文件是通過另一個(gè)文件自動(dòng)生成的,那自動(dòng)生成的文件就沒必要放進(jìn)版本庫,比如Java編譯產(chǎn)生的.class文件;

  3. 忽略你自己的帶有敏感信息的配置文件,比如存放口令的配置文件。

如果有些時(shí)候,你想添加一個(gè)文件到Git,但發(fā)現(xiàn)添加不了,原因是這個(gè)文件被.gitignore忽略了.

如果你確實(shí)想添加該文件,可以用-f強(qiáng)制添加到Git:

$ git add -f App.class

8.2配置別名

通過以下命令將status 縮寫成st

$ git config --global alias.st status

8.3搭建Git服務(wù)器

搭建Git服務(wù)器需要準(zhǔn)備一臺(tái)運(yùn)行Linux的機(jī)器,強(qiáng)烈推薦用Ubuntu或Debian,這樣,通過幾條簡單的apt命令就可以完成安裝。

假設(shè)你已經(jīng)有sudo權(quán)限的用戶賬號(hào),下面,正式開始安裝。

1、安裝git

yuan@yuan:~$ sudo apt-get install git

2、創(chuàng)建一個(gè)git用戶,用來運(yùn)行g(shù)it服務(wù)

$ sudo adduser git

3、創(chuàng)建證書登錄

收集所有需要登錄的用戶的公鑰,就是他們自己的id_rsa.pub文件,把所有公鑰導(dǎo)入到/home/git/.ssh/authorized_keys文件里,一行一個(gè)。

4、初始化Git倉庫:

先選定一個(gè)目錄作為Git倉庫,假定是/srv/sample.git,在/srv目錄下輸入命令:

$ sudo git init --bare sample.git

Git就會(huì)創(chuàng)建一個(gè)裸倉庫,裸倉庫沒有工作區(qū),因?yàn)榉?wù)器上的Git倉庫純粹是為了共享,所以不讓用戶直接登錄到服務(wù)器上去改工作區(qū),并且服務(wù)器上的Git倉庫通常都以.git結(jié)尾。然后,把owner改為git:

$ sudo chown -R git:git sample.git

5、禁用shell登錄:

出于安全考慮,第二步創(chuàng)建的git用戶不允許登錄shell,這可以通過編輯/etc/passwd文件完成。找到類似下面的一行:

git:x:1001:1001:,,,:/home/git:/bin/bash

改為:

git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell

這樣,git用戶可以正常通過ssh使用git,但無法登錄shell,因?yàn)槲覀優(yōu)間it用戶指定的git-shell每次一登錄就自動(dòng)退出。

6、克隆遠(yuǎn)程倉庫:

現(xiàn)在,可以通過git clone命令克隆遠(yuǎn)程倉庫了,在各自的電腦上運(yùn)行:

$ git clone git@server:/srv/sample.git
Cloning into 'sample'...
warning: You appear to have cloned an empty repository.

剩下的推送就簡單了。

管理公鑰

如果團(tuán)隊(duì)很小,把每個(gè)人的公鑰收集起來放到服務(wù)器的/home/git/.ssh/authorized_keys文件里就是可行的。如果團(tuán)隊(duì)有幾百號(hào)人,就沒法這么玩了,這時(shí),可以用Gitosis來管理公鑰。

這里我們不介紹怎么玩Gitosis了,幾百號(hào)人的團(tuán)隊(duì)基本都在500強(qiáng)了,相信找個(gè)高水平的Linux管理員問題不大。

管理權(quán)限

有很多不但視源代碼如生命,而且視員工為竊賊的公司,會(huì)在版本控制系統(tǒng)里設(shè)置一套完善的權(quán)限控制,每個(gè)人是否有讀寫權(quán)限會(huì)精確到每個(gè)分支甚至每個(gè)目錄下。因?yàn)镚it是為Linux源代碼托管而開發(fā)的,所以Git也繼承了開源社區(qū)的精神,不支持權(quán)限控制。不過,因?yàn)镚it支持鉤子(hook),所以,可以在服務(wù)器端編寫一系列腳本來控制提交等操作,達(dá)到權(quán)限控制的目的。Gitolite就是這個(gè)工具。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容