分布式版本控制系统Git的安装与使用
作業(yè)要求
1.(本次作業(yè)要求來自:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE1/homework/2103
2.? 我的Github遠(yuǎn)程倉庫地址: https://github.com/llgeill/llg-centos-git--test
3.? 我的Github遠(yuǎn)程倉庫地址截圖
作業(yè)內(nèi)容
1.Git的由來
很多人都知道,Linus在1991年創(chuàng)建了開源的Linux,從此,Linux系統(tǒng)不斷發(fā)展,已經(jīng)成為最大的服務(wù)器系統(tǒng)軟件了。
Linus雖然創(chuàng)建了Linux,但Linux的壯大是靠全世界熱心的志愿者參與的,這么多人在世界各地為Linux編寫代碼,那Linux的代碼是如何管理的呢?
事實(shí)是,在2002年以前,世界各地的志愿者把源代碼文件通過diff的方式發(fā)給Linus,然后由Linus本人通過手工方式合并代碼!
你也許會(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的開源精神不符。
不過,到了2002年,Linux系統(tǒng)已經(jīng)發(fā)展了十年了,代碼庫之大讓Linus很難繼續(xù)通過手工方式管理了,社區(qū)的弟兄們也對(duì)這種方式表達(dá)了強(qiáng)烈不滿,于是Linus選擇了一個(gè)商業(yè)的版本控制系統(tǒng)BitKeeper,BitKeeper的東家BitMover公司出于人道主義精神,授權(quán)Linux社區(qū)免費(fèi)使用這個(gè)版本控制系統(tǒng)。
安定團(tuán)結(jié)的大好局面在2005年就被打破了,原因是Linux社區(qū)牛人聚集,不免沾染了一些梁山好漢的江湖習(xí)氣。開發(fā)Samba的Andrew試圖破解BitKeeper的協(xié)議(這么干的其實(shí)也不只他一個(gè)),被BitMover公司發(fā)現(xiàn)了(監(jiān)控工作做得不錯(cuò)!),于是BitMover公司怒了,要收回Linux社區(qū)的免費(fèi)使用權(quán)。
Linus可以向BitMover公司道個(gè)歉,保證以后嚴(yán)格管教弟兄們,嗯,這是不可能的。實(shí)際情況是這樣的:
Linus花了兩周時(shí)間自己用C寫了一個(gè)分布式版本控制系統(tǒng),這就是Git!一個(gè)月之內(nèi),Linux系統(tǒng)的源碼已經(jīng)由Git管理了!牛是怎么定義的呢?大家可以體會(huì)一下。
Git迅速成為最流行的分布式版本控制系統(tǒng),尤其是2008年,GitHub網(wǎng)站上線了,它為開源項(xiàng)目免費(fèi)提供Git存儲(chǔ),無數(shù)開源項(xiàng)目開始遷移至GitHub,包括jQuery,PHP,Ruby等等。
歷史就是這么偶然,如果不是當(dāng)年BitMover公司威脅Linux社區(qū),可能現(xiàn)在我們就沒有免費(fèi)而超級(jí)好用的Git了。
2.什么是Git
- 從定義上來說Git就是一個(gè)分布式版本控制系統(tǒng)
- 從作用上來說Git就是管理一些文本或者代碼的版本更新,例如內(nèi)容的改動(dòng)
- 從管理的對(duì)象來說,所有的版本控制都只能針對(duì)文本內(nèi)容,像word這樣的二進(jìn)制內(nèi)容,所謂版本,就是文件快照,不能比較差異,只能算帶備份的網(wǎng)盤
3.為什么git叫做分布式版本控制系統(tǒng)
如果要想了解分布式是什么意思,那么我們得先去了解它的對(duì)立面集中式
集中式版本控制系統(tǒng)
- 工具:CVS及SVN都是集中式的版本控制系統(tǒng)
- 內(nèi)容:集中式版本控制系統(tǒng)集中存放在中央服務(wù)器的,而干活的時(shí)候,用的都是自己的電腦,所以要先從中央服務(wù)器取得最新的版本,然后開始干活,干完活了,再把自己的活推送給中央服務(wù)器。中央服務(wù)器就好比是一個(gè)圖書館,你要改一本書,必須先從圖書館借出來,然后回到家自己改,改完了,再放回圖書館。
- 缺點(diǎn):集中式版本控制系統(tǒng)最大的毛病就是必須聯(lián)網(wǎng)才能工作,如果在局域網(wǎng)內(nèi)還好,帶寬夠大,速度夠快,可如果在互聯(lián)網(wǎng)上,遇到網(wǎng)速慢的話,可能提交一個(gè)10M的文件就需要5分鐘,這還不得把人給憋死啊。
?
分布式版本控制系統(tǒng)
工具:git
內(nèi)容:布式版本控制系統(tǒng)沒有“中央服務(wù)器”,每個(gè)人的電腦上都是一個(gè)完整的版本庫,這樣,你工作的時(shí)候,就不需要聯(lián)網(wǎng)了,因?yàn)榘姹編炀驮谀阕约旱碾娔X上。既然每個(gè)人電腦上都有一個(gè)完整的版本庫,那多個(gè)人如何協(xié)作呢?比方說你在自己電腦上改了文件A,你的同事也在他的電腦上改了文件A,這時(shí),你們倆之間只需把各自的修改推送給對(duì)方,就可以互相看到對(duì)方的修改了。
優(yōu)點(diǎn):和集中式版本控制系統(tǒng)相比,分布式版本控制系統(tǒng)的安全性要高很多,因?yàn)槊總€(gè)人電腦里都有完整的版本庫,某一個(gè)人的電腦壞掉了不要緊,隨便從其他人那里復(fù)制一個(gè)就可以了。而集中式版本控制系統(tǒng)的中央服務(wù)器要是出了問題,所有人都沒法干活了。在實(shí)際使用分布式版本控制系統(tǒng)的時(shí)候,其實(shí)很少在兩人之間的電腦上推送版本庫的修改,因?yàn)榭赡苣銈儌z不在一個(gè)局域網(wǎng)內(nèi),兩臺(tái)電腦互相訪問不了,也可能今天你的同事病了,他的電腦壓根沒有開機(jī)。因此,分布式版本控制系統(tǒng)通常也有一臺(tái)充當(dāng)“中央服務(wù)器”的電腦,但這個(gè)服務(wù)器的作用僅僅是用來方便“交換”大家的修改,沒有它大家也一樣干活,只是交換修改不方便而已。當(dāng)然,Git的優(yōu)勢不單是不必聯(lián)網(wǎng)這么簡單,后面我們還會(huì)看到Git極其強(qiáng)大的分支管理,把SVN等遠(yuǎn)遠(yuǎn)拋在了后面(svn其實(shí)也有分支功能,不過是在服務(wù)器上的分支)
?
集中式與分布式的差異性
4.開始安裝Git
Git安裝
可以直接從官網(wǎng)下載相應(yīng)操作系統(tǒng)的Git然后進(jìn)行安裝,當(dāng)然也可以使用命令行的方式
- 例如在使用Centos操作系統(tǒng)的時(shí)候,可以使用如下命令快速安裝
- yum install -y git
- 或著不想使用命令行方式就直接去官網(wǎng)下載壓縮包
Git bash配置
用戶名和郵箱地址的作用
修改用戶名和郵箱地址
- $?git?config?--global user.name "username"
- $?git?config?--global?user.email??"email"
查看用戶名和郵箱地址
- $?git?config?user.name
- $?git?config?user.email
5.開始使用Git(版本庫)
以下所有操作都在centos上操作完成
什么是版本庫
版本庫又名倉庫,英文名repository,你可以簡單理解成一個(gè)文件夾,這個(gè)文件夾里面的所有文件都可以被Git管理起來,每個(gè)文件的修改、刪除,Git都能跟蹤,以便任何時(shí)刻都可以追蹤歷史,或者在將來某個(gè)時(shí)刻可以“還原”。所以,創(chuàng)建一個(gè)版本庫非常簡單。
開始創(chuàng)建版本庫
首先,選擇一個(gè)合適的地方,創(chuàng)建一個(gè)空目錄
#創(chuàng)建一個(gè)文件件 [llg@localhost 桌面]$ mkdir llg-test-git #進(jìn)入文件夾目錄 [llg@localhost 桌面]$ cd llg-test-git/ #顯示當(dāng)前文件夾路徑 [llg@localhost llg-test-git]$ pwd接著,最重要的一步 通過git init?的命令將當(dāng)前文件夾變成一個(gè)版本庫
[llg@localhost llg-test-git]$ git init 初始化空的 Git 版本庫于 /home/llg/桌面/llg-test-git/.git/ [llg@localhost llg-test-git]$最后,通過ls -al 命令,發(fā)現(xiàn)多了個(gè)git文件夾。這個(gè)目錄是Git來跟蹤管理版本庫的,沒事千萬不要手動(dòng)修改這個(gè)目錄里面的文件,不然改亂了,就把Git倉庫給破壞了。
[llg@localhost llg-test-git]$ ls -al 總用量 4 drwxrwsr-x 3 llg llg 18 9月 14 19:48 . drwsrwsrwt. 13 llg llg 4096 9月 14 19:44 .. drwxrwsr-x 7 llg llg 119 9月 14 19:48 .git [llg@localhost llg-test-git]$?
開始添加文件到版本庫
首先需要注意的是版本管理的受眾范圍
- 首先這里再明確一下,所有的版本控制系統(tǒng),其實(shí)只能跟蹤文本文件的改動(dòng),比如TXT文件,網(wǎng)頁,所有的程序代碼等等,Git也不例外。版本控制系統(tǒng)可以告訴你每次的改動(dòng),比如在第5行加了一個(gè)單詞“Linux”,在第8行刪了一個(gè)單詞“Windows”。而圖片、視頻這些二進(jìn)制文件,雖然也能由版本控制系統(tǒng)管理,但沒法跟蹤文件的變化,只能把二進(jìn)制文件每次改動(dòng)串起來,也就是只知道圖片從100KB改成了120KB,但到底改了啥,版本控制系統(tǒng)不知道,也沒法知道。
- 不幸的是,Microsoft的Word格式是二進(jìn)制格式,因此,版本控制系統(tǒng)是沒法跟蹤Word文件的改動(dòng)的,前面我們舉的例子只是為了演示,如果要真正使用版本控制系統(tǒng),就要以純文本方式編寫文件。
- 因?yàn)槲谋臼怯芯幋a的,比如中文有常用的GBK編碼,日文有Shift_JIS編碼,如果沒有歷史遺留問題,強(qiáng)烈建議使用標(biāo)準(zhǔn)的UTF-8編碼,所有語言使用同一種編碼,既沒有沖突,又被所有平臺(tái)所支持。
- 使用Windows的童鞋要特別注意:千萬不要使用Windows自帶的記事本編輯任何文本文件。原因是Microsoft開發(fā)記事本的團(tuán)隊(duì)使用了一個(gè)非常弱智的行為來保存UTF-8編碼的文件,他們自作聰明地在每個(gè)文件開頭添加了0xefbbbf(十六進(jìn)制)的字符,你會(huì)遇到很多不可思議的問題,比如,網(wǎng)頁第一行可能會(huì)顯示一個(gè)“?”,明明正確的程序一編譯就報(bào)語法錯(cuò)誤,等等,都是由記事本的弱智行為帶來的。建議你下載Notepad++代替記事本,不但功能強(qiáng)大,而且免費(fèi)!記得把Notepad++的默認(rèn)編碼設(shè)置為UTF-8 without BOM即可:
首先,使用vi創(chuàng)建一個(gè)文件并且添加一些內(nèi)容。確保此文件必須在這個(gè)版本倉庫里面也就是我們惡毒llg-test-git文件夾,不然放在其他地方是不能被版本控制的。
[llg@localhost llg-test-git]$ vi llg.txt [llg@localhost llg-test-git]$接著,將文件顯示的通過git add命令添加到版本庫里面,不過在這之前我們使用git status 來查看一下還沒使用git add命令時(shí)候的狀態(tài)和使用git add之后的狀態(tài),比較一下不同。通過比較,我們發(fā)現(xiàn)了當(dāng)使用git add 命令的時(shí)候其實(shí)是建立起了文件跟蹤的功能,之后使用git status 就可以看到有一個(gè)新文件
[llg@localhost llg-test-git]$ git status # 位于分支 master # # 初始提交 # # 未跟蹤的文件: # (使用 "git add <file>..." 以包含要提交的內(nèi)容) # # llg.txt 提交為空,但是存在尚未跟蹤的文件(使用 "git add" 建立跟蹤) [llg@localhost llg-test-git]$ [llg@localhost llg-test-git]$ git add llg.txt [llg@localhost llg-test-git]$ git status # 位于分支 master # # 初始提交 # # 要提交的變更: # (使用 "git rm --cached <file>..." 撤出暫存區(qū)) # # 新文件: llg.txt # [llg@localhost llg-test-git]$?
最后,使用git commit -m告訴Git,把文件提交到倉庫。-m是提交的一些說明信息,必須要寫,可以方便自己和他人了解這次提交了什么東西。?
?
[llg@localhost llg-test-git]$ git commit -m "git練習(xí)測試" [master(根提交) abde635] git練習(xí)測試 1 file changed, 1 insertion(+) create mode 100644 llg.txt [llg@localhost llg-test-git]$?
疑問:為什么Git添加文件需要add,commit一共兩步呢?
因?yàn)閏ommit可以一次提交很多文件,所以你可以多次add不同的文件,比如下圖,可以跟蹤多個(gè)文件然后全部一次性提交到版本庫里面.
[llg@localhost llg-test-git]$ vi one.txt [llg@localhost llg-test-git]$ vi two.txt [llg@localhost llg-test-git]$ vi three.txt [llg@localhost llg-test-git]$ git add one.txt [llg@localhost llg-test-git]$ git add two.txt [llg@localhost llg-test-git]$ git add three.txt [llg@localhost llg-test-git]$ git commit -m "這次測試一次提交三個(gè)文件" [master 44449dc] 這次測試一次提交三個(gè)文件 3 files changed, 4 insertions(+) create mode 100644 one.txt create mode 100644 three.txt create mode 100644 two.txt [llg@localhost llg-test-git]$ [llg@localhost llg-test-git]$ git status # 位于分支 master 無文件要提交,干凈的工作區(qū) [llg@localhost llg-test-git]$?
6.Git版本回退
在學(xué)習(xí)版本回退之前我們線來了解下兩個(gè)常用的命令git status和git diff
git status
剛剛在創(chuàng)建版本庫的時(shí)候我們已經(jīng)使用了,用來查看git的狀態(tài),一般可以拿來查看我們做的某些操作之后的狀態(tài),例如修改文件,添加文件等等
例如我們修改一個(gè)文件然后使用git status查看,發(fā)現(xiàn)了提示llg.txt是修改過的文件
?
[llg@localhost llg-test-git]$ vi llg.txt [llg@localhost llg-test-git]$ git status # 位于分支 master # 尚未暫存以備提交的變更: # (使用 "git add <file>..." 更新要提交的內(nèi)容) # (使用 "git checkout -- <file>..." 丟棄工作區(qū)的改動(dòng)) # # 修改: llg.txt # 修改尚未加入提交(使用 "git add" 和/或 "git commit -a") [llg@localhost llg-test-git]$
?
?
git sdiff
由于文件修改過后,我們有時(shí)候可能想知道具體修改了什么內(nèi)容,位置在那里,區(qū)別是什么等等。,所以我們需要git sdiff命令來獲得這個(gè)修改前后的對(duì)照信息
[llg@localhost llg-test-git]$ git diff diff --git a/llg.txt b/llg.txt index f77faef..2f3d837 100644 --- a/llg.txt +++ b/llg.txt @@ -1 +1 @@ -my name is liliguang +My name is liliguang.I created three files a moment ago. [llg@localhost llg-test-git]$?
之后繼續(xù)測試,修改其他兩個(gè)文件內(nèi)容 [llg@localhost llg-test-git]$ vi one.txt [llg@localhost llg-test-git]$ vi two.txt [llg@localhost llg-test-git]$ git diff diff --git a/llg.txt b/llg.txt index f77faef..2f3d837 100644 --- a/llg.txt +++ b/llg.txt @@ -1 +1 @@ -my name is liliguang +My name is liliguang.I created three files a moment ago. diff --git a/one.txt b/one.txt index 25ab921..34144e1 100644 --- a/one.txt +++ b/one.txt @@ -1 +1,2 @@ this is one +llg diff --git a/two.txt b/two.txt index 42b3fbc..0f62931 100644 --- a/two.txt +++ b/two.txt @@ -1,2 +1,2 @@ this is two - +llg [llg@localhost llg-test-git]$?
[llg@localhost llg-test-git]$ vi two.txt [llg@localhost llg-test-git]$ git diff diff --git a/llg.txt b/llg.txt index f77faef..2f3d837 100644 --- a/llg.txt +++ b/llg.txt @@ -1 +1 @@ -my name is liliguang +My name is liliguang.I created three files a moment ago. diff --git a/one.txt b/one.txt index 25ab921..34144e1 100644 --- a/one.txt +++ b/one.txt @@ -1 +1,2 @@ this is one +llg diff --git a/two.txt b/two.txt index 42b3fbc..e730358 100644 --- a/two.txt +++ b/two.txt @@ -1,2 +1,6 @@ this is two - +llg +sss +aaa +bbb +wef [llg@localhost llg-test-git]$?
?
開始使用版本回退的前提
版本回退的意思就是回退到某一次commit那里,這優(yōu)點(diǎn)類似與打通關(guān)游戲,你可以在任意通過的關(guān)卡中來往穿梭
git log
首先,我們需要使用git log 命令來找出我們之前的commit信息。從下圖可以看到提交順序是按照最新日期排序的,最新的在最頂部,commit 后面的就是commit ID?了,后面的版本回退都靠它
?
[llg@localhost llg-test-git]$ git log commit 3956cc36e1017c14e79d9de0944bb9baa6d2ff51 Author: llg <903857227@qq.com> Date: Fri Sep 14 20:35:26 2018 +0800測試兩個(gè)文件提交留一個(gè)文件不提交commit 44449dc5261b8a66bac14ce302519f26895d0163 Author: llg <903857227@qq.com> Date: Fri Sep 14 20:11:22 2018 +0800這次測試一次提交三個(gè)文件commit abde635c93434ac4172caa4e0c6383e9dfc3d522 Author: llg <903857227@qq.com> Date: Fri Sep 14 20:07:31 2018 +0800git練習(xí)測試[llg@localhost llg-test-git]$?
如果嫌輸出信息太多,看得眼花繚亂的,可以試試加上--pretty=oneline參數(shù)?
?
[llg@localhost llg-test-git]$ git log --pretty=oneline 3956cc36e1017c14e79d9de0944bb9baa6d2ff51 測試兩個(gè)文件提交留一個(gè)文件不提交 44449dc5261b8a66bac14ce302519f26895d0163 這次測試一次提交三個(gè)文件 abde635c93434ac4172caa4e0c6383e9dfc3d522 git練習(xí)測試 [llg@localhost llg-test-git]$?
?
開始使用版本回退
首先,Git必須知道當(dāng)前版本是哪個(gè)版本,在Git中,用HEAD表示當(dāng)前版本,也就是最新的提交3956cc...(注意我的提交ID和你的肯定不一樣),上一個(gè)版本就是HEAD^,上上一個(gè)版本就是HEAD^^,當(dāng)然往上100個(gè)版本寫100個(gè)^比較容易數(shù)不過來,所以寫成HEAD~100。
git reset
我們要把當(dāng)前版本<測試兩個(gè)文件提交留一個(gè)文件不提交>回退到上一個(gè)版本<這次測試一次提交三個(gè)文件>,就可以使用git reset命令:
從下圖我們可以分析出,其實(shí)HEAD代表的是頭指針,畢竟這個(gè)git使用c語言寫的,我們對(duì)C應(yīng)該也是不陌生的,所以這是一個(gè)雙向鏈表,可以向前也可以向后,只要我們知道commit ID。
?
[llg@localhost llg-test-git]$ git reset --hard HEAD HEAD 現(xiàn)在位于 3956cc3 測試兩個(gè)文件提交留一個(gè)文件不提交 [llg@localhost llg-test-git]$ git reset --hard HEAD^ HEAD 現(xiàn)在位于 44449dc 這次測試一次提交三個(gè)文件 [llg@localhost llg-test-git]$ git reset --hard HEAD^ HEAD 現(xiàn)在位于 abde635 git練習(xí)測試 [llg@localhost llg-test-git]$?
?
當(dāng)我們跳的比較遠(yuǎn)的時(shí)候,也可以直接指定commit ID 來跳轉(zhuǎn)?
?
[llg@localhost llg-test-git]$ git reset --hard 3956cc3 HEAD 現(xiàn)在位于 3956cc3 測試兩個(gè)文件提交留一個(gè)文件不提交 [llg@localhost llg-test-git]$?
當(dāng)我們想要回到之前最新的版本的時(shí)候,我們會(huì)想到用git log,但是很不幸我們發(fā)現(xiàn)之前的版本信息都沒有了。所以我們還有一個(gè)命令用來找回之前的commit ID ,就是git reflog命令了。
?
[llg@localhost llg-test-git]$ git log commit abde635c93434ac4172caa4e0c6383e9dfc3d522 Author: llg <903857227@qq.com> Date: Fri Sep 14 20:07:31 2018 +0800 git練習(xí)測試 [llg@localhost llg-test-git]$?
?
?
?
git reflog
可以拿到所有的操作記錄
從下面我們可以找到帶有commit字樣的就是我們之前創(chuàng)建的版本,但是只提供了ID的七為數(shù),但是沒關(guān)系,git會(huì)自動(dòng)識(shí)別出來
?
[llg@localhost llg-test-git]$ git reflog abde635 HEAD@{0}: reset: moving to HEAD^ 44449dc HEAD@{1}: reset: moving to HEAD^ 3956cc3 HEAD@{2}: commit: 測試兩個(gè)文件提交留一個(gè)文件不提交 44449dc HEAD@{3}: commit: 這次測試一次提交三個(gè)文件 abde635 HEAD@{4}: commit (initial): git練習(xí)測試 [llg@localhost llg-test-git]$ git reset --hard 3956cc3 HEAD 現(xiàn)在位于 3956cc3 測試兩個(gè)文件提交留一個(gè)文件不提交 [llg@localhost llg-test-git]$?
?
?
?
?
7.git的工作區(qū)和暫存區(qū)
首先是官圖解釋,從下圖可以看出如果我們想直接提交文件到master分支上,那么直接使用 git commit -a即可
接著再看看其余大佬繪制的圖
版本庫(Repository)
工作區(qū)有一個(gè)隱藏目錄.git,這個(gè)不算工作區(qū),而是Git的版本庫。
Git的版本庫里存了很多東西,其中最重要的就是稱為stage(或者叫index)的暫存區(qū),還有Git為我們自動(dòng)創(chuàng)建的第一個(gè)分支master,以及指向master的一個(gè)指針叫HEAD。
?
假如我們?cè)赾ommit之后沒有任何操作,那么我們暫存區(qū)就是空的
當(dāng)我們添加了文件或者修改了文件,并且使用了add命令那么暫存區(qū)stage就又有了文件
?
當(dāng)我們使用commit提交之后,那么早存區(qū)又變成了空
?
關(guān)于git diff 與暫存區(qū)的關(guān)系
- git diff 比較的是工作區(qū)文件與暫存區(qū)文件的區(qū)別(上次git add 的內(nèi)容)
- git diff --cached 比較的是暫存區(qū)的文件與倉庫分支里(上次git commit 后的內(nèi)容)的區(qū)別
8.Git如何撤回修改的操作
場景1:當(dāng)你改亂了工作區(qū)某個(gè)文件的內(nèi)容,想直接丟棄工作區(qū)的修改時(shí),用命令git checkout -- file。
首先修改工作區(qū)的文件,不執(zhí)行add操作
檢查git狀態(tài),發(fā)現(xiàn)提示使用git checkout -- file 命令撤回操作 ,執(zhí)行之后發(fā)現(xiàn)已經(jīng)成功撤回
[llg@localhost llg-test-git]$ git status # 位于分支 master # 尚未暫存以備提交的變更: # (使用 "git add <file>..." 更新要提交的內(nèi)容) # (使用 "git checkout -- <file>..." 丟棄工作區(qū)的改動(dòng)) # # 修改: one.txt # 修改尚未加入提交(使用 "git add" 和/或 "git commit -a") [llg@localhost llg-test-git]$ [llg@localhost llg-test-git]$ git checkout -- one.txt [llg@localhost llg-test-git]$?
?
?
?
?
?
場景2:當(dāng)你不但改亂了工作區(qū)某個(gè)文件的內(nèi)容,還添加到了暫存區(qū)時(shí),想丟棄修改,分兩步,第一步用命令git reset HEAD <file>,就回到了場景1,第二步按場景1操作。
首先修改文件并且通過add放到暫存區(qū)?
?
[llg@localhost llg-test-git]$ git status # 位于分支 master # 要提交的變更: # (使用 "git reset HEAD <file>..." 撤出暫存區(qū)) # # 修改: one.txt # [llg@localhost llg-test-git]$?
?
?
?
根據(jù)提示使用git reset HEAD <file> 撤出暫存區(qū),執(zhí)行成功?
?
[llg@localhost llg-test-git]$ git status # 位于分支 master # 要提交的變更: # (使用 "git reset HEAD <file>..." 撤出暫存區(qū)) # # 修改: one.txt # [llg@localhost llg-test-git]$ git reset HEAD one.txt 重置后撤出暫存區(qū)的變更: M one.txt [llg@localhost llg-test-git]$ git status # 位于分支 master # 尚未暫存以備提交的變更: # (使用 "git add <file>..." 更新要提交的內(nèi)容) # (使用 "git checkout -- <file>..." 丟棄工作區(qū)的改動(dòng)) # # 修改: one.txt # 修改尚未加入提交(使用 "git add" 和/或 "git commit -a") [llg@localhost llg-test-git]$?
場景3:已經(jīng)提交了不合適的修改到版本庫時(shí),想要撤銷本次提交,參考版本回退一節(jié),不過前提是沒有推送到遠(yuǎn)程庫。
9.Git如何刪除文件
此處的刪除文件是指當(dāng)一個(gè)文件提交到版本庫后,也就是master分支。如果在工作區(qū)刪除這個(gè)文件,那么將會(huì)使工作區(qū)文件與版本庫文件不對(duì)應(yīng),在這里需要分清兩種使用情況。
工作區(qū)刪除了文件并且確實(shí)要從版本庫中也刪除該文件
那么就應(yīng)該使用git rm 命令
[llg@localhost llg-test-git]$ rm delete.txt [llg@localhost llg-test-git]$ git rm -- delete.txt rm 'delete.txt' [llg@localhost llg-test-git]$ git status # 位于分支 master # 要提交的變更: # (使用 "git reset HEAD <file>..." 撤出暫存區(qū)) # # 刪除: delete.txt # [llg@localhost llg-test-git]$?
?
?
當(dāng)然我們通過git status 命令可以看出這一操作只是保留在了暫存區(qū),所以我們還需要commit命令提交這一更改,其實(shí)可以把這一命令想象成修改的命令
?
[llg@localhost llg-test-git]$ git commit -m "正式從版本庫中刪除該文件" [master ad66495] 正式從版本庫中刪除該文件 1 file changed, 1 deletion(-) delete mode 100644 delete.txt [llg@localhost llg-test-git]$ git status # 位于分支 master 無文件要提交,干凈的工作區(qū) [llg@localhost llg-test-git]$?
?
工作區(qū)誤刪了某些文件,需要從版本庫中重新弄回來
根據(jù)git status 提示的方法,我們可以從版本庫中checkout中某些文件
[llg@localhost llg-test-git]$ git checkout -- delete.txt另外一個(gè)一個(gè)簡單的方法就是重新把版本庫更新回來,但是這個(gè)前提是你得保證只有這么一個(gè)刪除文件,如果有其他文件修改了并且未放到暫存區(qū),那么就非常可怕了。
?
[llg@localhost llg-test-git]$ git reset --hard HEAD^ HEAD 現(xiàn)在位于 eda17f9 這是一個(gè)將要被刪除的文件 [llg@localhost llg-test-git]$ ls -al 總用量 24 drwxrwsr-x 3 llg llg 98 9月 15 19:56 . drwsrwsrwt. 13 llg llg 4096 9月 14 19:44 .. -rw-rw-r-- 1 llg llg 34 9月 15 19:56 delete.txt drwxrwsr-x 8 llg llg 183 9月 15 19:56 .git -rw-rw-r-- 1 llg llg 57 9月 14 21:06 llg.txt -rw-rw-r-- 1 llg llg 16 9月 14 22:05 one.txt -rw-rw-r-- 1 llg llg 14 9月 14 21:06 three.txt -rw-rw-r-- 1 llg llg 13 9月 14 21:06 two.txt [llg@localhost llg-test-git]$?
10.初識(shí)遠(yuǎn)程倉庫
既然git的其中一個(gè)目的就是為了協(xié)作開發(fā),那么遠(yuǎn)程倉庫就是為了這一個(gè)目的的。通過將倉庫放在一個(gè)遠(yuǎn)程的服務(wù)器上,讓所有人都可以訪問這個(gè)倉庫,可以一起更新和提交。
實(shí)際情況往往是這樣,找一臺(tái)電腦充當(dāng)服務(wù)器的角色,每天24小時(shí)開機(jī),其他每個(gè)人都從這個(gè)“服務(wù)器”倉庫克隆一份到自己的電腦上,并且各自把各自的提交推送到服務(wù)器倉庫里,也從服務(wù)器倉庫中拉取別人的提交。
完全可以自己搭建一臺(tái)運(yùn)行Git的服務(wù)器,不過現(xiàn)階段,為了學(xué)Git先搭個(gè)服務(wù)器絕對(duì)是小題大作。好在這個(gè)世界上有個(gè)叫GitHub的神奇的網(wǎng)站,從名字就可以看出,這個(gè)網(wǎng)站就是提供Git倉庫托管服務(wù)的,所以,只要注冊(cè)一個(gè)GitHub賬號(hào),就可以免費(fèi)獲得Git遠(yuǎn)程倉庫。
在繼續(xù)閱讀后續(xù)內(nèi)容前,請(qǐng)自行注冊(cè)GitHub賬號(hào)。由于你的本地Git倉庫和GitHub倉庫之間的傳輸是通過SSH加密的,所以,需要一點(diǎn)設(shè)置:
第1步:創(chuàng)建SSH Key。在用戶主目錄下,看看有沒有.ssh目錄,如果有,再看看這個(gè)目錄下有沒有id_rsa和id_rsa.pub這兩個(gè)文件,如果已經(jīng)有了,可直接跳到下一步。如果沒有,打開Shell(Windows下打開Git Bash),創(chuàng)建SSH Key:
[llg@localhost ~]$ ssh-keygen -t rsa -C "903857227@qq.com"如果一切順利的話,可以在用戶主目錄里找到.ssh目錄,里面有id_rsa和id_rsa.pub兩個(gè)文件,這兩個(gè)就是SSH Key的秘鑰對(duì),id_rsa是私鑰,不能泄露出去,id_rsa.pub是公鑰,可以放心地告訴任何人。
第2步:登陸GitHub,打開“Account settings”,“SSH Keys”頁面:
然后,點(diǎn)“Add SSH Key”,填上任意Title,在Key文本框里粘貼id_rsa.pub文件的內(nèi)容:
[llg@localhost ~]$ cd .ssh/?
[llg@localhost .ssh]$ ls -al 總用量 16 drwsrwsrwt. 2 llg llg 57 9月 15 20:28 . drwsrwsrwt. 39 llg llg 4096 9月 15 19:59 .. -rw------- 1 llg llg 1679 9月 15 20:29 id_rsa -rw-r--r-- 1 llg llg 398 9月 15 20:29 id_rsa.pub -rw-r--r-- 1 llg llg 175 4月 27 20:05 known_hosts [llg@localhost .ssh]$ vi id_rsa.pub?
為什么GitHub需要SSH Key呢?因?yàn)镚itHub需要識(shí)別出你推送的提交確實(shí)是你推送的,而不是別人冒充的,而Git支持SSH協(xié)議,所以,GitHub只要知道了你的公鑰,就可以確認(rèn)只有你自己才能推送。
當(dāng)然,GitHub允許你添加多個(gè)Key。假定你有若干電腦,你一會(huì)兒在公司提交,一會(huì)兒在家里提交,只要把每臺(tái)電腦的Key都添加到GitHub,就可以在每臺(tái)電腦上往GitHub推送了。
最后友情提示,在GitHub上免費(fèi)托管的Git倉庫,任何人都可以看到喔(但只有你自己才能改)。所以,不要把敏感信息放進(jìn)去。
如果你不想讓別人看到Git庫,有兩個(gè)辦法,一個(gè)是交點(diǎn)保護(hù)費(fèi),讓GitHub把公開的倉庫變成私有的,這樣別人就看不見了(不可讀更不可寫)。另一個(gè)辦法是自己動(dòng)手,搭一個(gè)Git服務(wù)器,因?yàn)槭悄阕约旱腉it服務(wù)器,所以別人也是看不見的。這個(gè)方法我們后面會(huì)講到的,相當(dāng)簡單,公司內(nèi)部開發(fā)必備。
確保你擁有一個(gè)GitHub賬號(hào)后,我們就即將開始遠(yuǎn)程倉庫的學(xué)習(xí)。
11.從github上添加一個(gè)遠(yuǎn)程倉庫
首先我們github上登陸自己帳號(hào)后創(chuàng)建一個(gè)倉庫
接著我們可以看到創(chuàng)建完倉庫后給我們的提示
從本地的已有倉庫直接推送到遠(yuǎn)程倉庫上
根據(jù)上邊提示輸入命令
?
[llg@localhost llg-test-git]$ git remote add origin https://github.com/llgeill/llg-centos-git--test.git [llg@localhost llg-test-git]$ git push -u origin master Username for 'https://github.com': 903857227@qq.com Password for 'https://903857227@qq.com@github.com': Counting objects: 12, done. Delta compression using up to 4 threads. Compressing objects: 100% (6/6), done. Writing objects: 100% (12/12), 1.01 KiB | 0 bytes/s, done. Total 12 (delta 0), reused 0 (delta 0) remote: remote: Create a pull request for 'master' on GitHub by visiting: remote: https://github.com/llgeill/llg-centos-git--test/pull/new/master remote: To https://github.com/llgeill/llg-centos-git--test.git * [new branch] master -> master 分支 master 設(shè)置為跟蹤來自 origin 的遠(yuǎn)程分支 master。?
?
發(fā)現(xiàn)文件已經(jīng)推送完畢??
Git遠(yuǎn)程倉庫的優(yōu)點(diǎn)?
- 要關(guān)聯(lián)一個(gè)遠(yuǎn)程庫,使用命令git remote add origin git@server-name:path/repo-name.git;
- 關(guān)聯(lián)后,使用命令git push -u origin master第一次推送master分支的所有內(nèi)容;
- 此后,每次本地提交后,只要有必要,就可以使用命令git push origin master推送最新修改;
- 分布式版本系統(tǒng)的最大好處之一是在本地工作完全不需要考慮遠(yuǎn)程庫的存在,也就是有沒有聯(lián)網(wǎng)都可以正常工作,而SVN在沒有聯(lián)網(wǎng)的時(shí)候是拒絕干活的!當(dāng)有網(wǎng)絡(luò)的時(shí)候,再把本地提交推送一下就完成了同步,真是太方便了!
12.從遠(yuǎn)程倉庫克隆一個(gè)已有倉庫
首先我們從github上創(chuàng)建一個(gè)遠(yuǎn)程倉庫
首先在github上找到可以克隆的地址
下一步是用命令git clone克隆一個(gè)本地庫,我們可以發(fā)現(xiàn)項(xiàng)目已經(jīng)克隆下來
?
[llg@localhost 桌面]$ git clone git@github.com:llgeill/llg-centos-git-test-1.git 正克隆到 'llg-centos-git-test-1'... The authenticity of host 'github.com (192.30.253.112)' can't be established. RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8. RSA key fingerprint is MD5:16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'github.com,192.30.253.112' (RSA) to the list of known hosts. remote: Counting objects: 3, done. remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 接收對(duì)象中: 100% (3/3), done. [llg@localhost 桌面]$ ls -al 總用量 40 drwsrwsrwt. 14 llg llg 4096 9月 15 21:10 . drwsrwsrwt. 39 llg llg 4096 9月 15 20:39 .. drwxr-xr-x 11 llg llg 196 9月 2 17:11 1-Brixton版教程示例 drwxr-xr-x 34 llg llg 4096 9月 2 15:57 2-Dalston版教程示例 -rw-r--r-- 1 root root 12288 4月 23 20:58 .android-studio.desktop.swp drwxrwxr-x 10 llg llg 302 9月 13 22:23 dist -rwsrwsrwt 1 llg llg 1968 5月 2 08:27 .keystore drwxrwsr-x 5 llg llg 118 9月 14 08:38 llg drwxrwsr-x 3 llg llg 35 9月 15 21:10 llg-centos-git-test-1 drwxrwsr-x 3 llg llg 80 9月 15 20:01 llg-test-git drwxrwsr-x 5 llg llg 131 9月 7 20:13 llg-user-gateway drwxrwsr-x 6 llg llg 151 9月 14 08:51 llg-web-springboot-class drwxr-xr-x 39 llg llg 4096 9月 2 19:41 SpringCloudBook-master drwx------ 14 llg llg 315 9月 3 07:46 spring-cloud-llg drwxrwsr-x 5 llg llg 61 9月 5 18:53 untitled drwxr-xr-x 12 llg llg 4096 6月 29 2016 計(jì)算機(jī)組成原理201407?
測試從本地倉庫推送回遠(yuǎn)程倉庫
[llg@localhost llg-centos-git-test-1]$ vi llg.txt [llg@localhost llg-centos-git-test-1]$ git add llg.txt [llg@localhost llg-centos-git-test-1]$ git commit -m "測試" [master 4bdb6c4] 測試 1 file changed, 1 insertion(+) create mode 100644 llg.txt [llg@localhost llg-centos-git-test-1]$ git status # 位于分支 master # 您的分支領(lǐng)先 'origin/master' 共 1 個(gè)提交。 # (使用 "git push" 來發(fā)布您的本地提交) # 無文件要提交,干凈的工作區(qū) [llg@localhost llg-centos-git-test-1]$ git push -u origin masterWarning: Permanently added the RSA host key for IP address '192.30.253.113' to the list of known hosts. Counting objects: 4, done. Delta compression using up to 4 threads. Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 274 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To git@github.com:llgeill/llg-centos-git-test-1.git 07b4bcc..4bdb6c4 master -> master 分支 master 設(shè)置為跟蹤來自 origin 的遠(yuǎn)程分支 master。?
13.Git的分支管理
分支就是科幻電影里面的平行宇宙,當(dāng)你正在電腦前努力學(xué)習(xí)Git的時(shí)候,另一個(gè)你正在另一個(gè)平行宇宙里努力學(xué)習(xí)SVN。
如果兩個(gè)平行宇宙互不干擾,那對(duì)現(xiàn)在的你也沒啥影響。不過,在某個(gè)時(shí)間點(diǎn),兩個(gè)平行宇宙合并了,結(jié)果,你既學(xué)會(huì)了Git又學(xué)會(huì)了SVN!
分支在實(shí)際中有什么用呢?假設(shè)你準(zhǔn)備開發(fā)一個(gè)新功能,但是需要兩周才能完成,第一周你寫了50%的代碼,如果立刻提交,由于代碼還沒寫完,不完整的代碼庫會(huì)導(dǎo)致別人不能干活了。如果等代碼全部寫完再一次提交,又存在丟失每天進(jìn)度的巨大風(fēng)險(xiǎn)。
現(xiàn)在有了分支,就不用怕了。你創(chuàng)建了一個(gè)屬于你自己的分支,別人看不到,還繼續(xù)在原來的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到開發(fā)完畢后,再一次性合并到原來的分支上,這樣,既安全,又不影響別人工作。
其他版本控制系統(tǒng)如SVN等都有分支管理,但是用過之后你會(huì)發(fā)現(xiàn),這些版本控制系統(tǒng)創(chuàng)建和切換分支比蝸牛還慢,簡直讓人無法忍受,結(jié)果分支功能成了擺設(shè),大家都不去用。
但Git的分支是與眾不同的,無論創(chuàng)建、切換和刪除分支,Git在1秒鐘之內(nèi)就能完成!無論你的版本庫是1個(gè)文件還是1萬個(gè)文件。
14.創(chuàng)建與合并分支管理
在版本回退里,每次提交,Git都把它們串成一條時(shí)間線,這條時(shí)間線就是一個(gè)分支。截止到目前,只有一條時(shí)間線,在Git里,這個(gè)分支叫主分支,即master分支。HEAD嚴(yán)格來說不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是當(dāng)前分支。
原理解析
一開始的時(shí)候,master分支是一條線,Git用master指向最新的提交,再用HEAD指向master,就能確定當(dāng)前分支,以及當(dāng)前分支的提交點(diǎn):
?
創(chuàng)建新分支?
當(dāng)我們創(chuàng)建新的分支,例如dev時(shí),Git新建了一個(gè)指針叫dev,指向master相同的提交,再把HEAD指向dev,就表示當(dāng)前分支在dev上
git checkout命令加上-b參數(shù)表示創(chuàng)建分支并切換分支
?
[llg@localhost llg-test-git]$ git checkout -b dev 切換到一個(gè)新分支 'dev' [llg@localhost llg-test-git]$?
上面的命令等價(jià)與下面兩條命令的結(jié)合
?
[llg@localhost llg-test-git]$ git branch dev [llg@localhost llg-test-git]$ git checkout dev 切換到分支 'dev'?
我們可以使用git branch 查看當(dāng)前分支的情況?
?
[llg@localhost llg-test-git]$ git branch * dev master?
?你看,Git創(chuàng)建一個(gè)分支很快,因?yàn)槌嗽黾右粋€(gè)dev指針,改改HEAD的指向,工作區(qū)的文件都沒有任何變化!
新分支上提交版本庫
不過,從現(xiàn)在開始,對(duì)工作區(qū)的修改和提交就是針對(duì)dev分支了,比如新提交一次后,dev指針往前移動(dòng)一步,而master指針不變
?
[llg@localhost llg-test-git]$ vi one.txt [llg@localhost llg-test-git]$ git add one.txt [llg@localhost llg-test-git]$ git commit -m "在分支上提交版本信息" [dev 8c8117b] 在分支上提交版本信息 1 file changed, 2 insertions(+) [llg@localhost llg-test-git]$ git status # 位于分支 dev 無文件要提交,干凈的工作區(qū) [llg@localhost llg-test-git]$?
當(dāng)我們重新切換到master分支時(shí)候發(fā)現(xiàn)one.txt根本沒有變化,因?yàn)槲覀僣ommit的是dev分支
?
[llg@localhost llg-test-git]$ git checkout master 切換到分支 'master' [llg@localhost llg-test-git]$ vi one.txt [llg@localhost llg-test-git]$ git checkout dev 切換到分支 'dev' [llg@localhost llg-test-git]$ vi one.txt?
合并分支
假如我們?cè)赿ev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最簡單的方法,就是直接把master指向dev的當(dāng)前提交,就完成了合并?。注意下面的Fast-forwar 信息,Git告訴我們這次合并是“快進(jìn)模式”,也就是直接把master指向dev的當(dāng)前提交,所以合并速度非???。當(dāng)然,也不是每次合并都能Fast-forward,我們后面會(huì)講其他方式的合并。
?
[llg@localhost llg-test-git]$ git checkout master 切換到分支 'master' [llg@localhost llg-test-git]$ git merge dev 更新 3956cc3..8c8117b Fast-forward one.txt | 2 ++ 1 file changed, 2 insertions(+)?
刪除分支
合并完分支后,甚至可以刪除dev分支。刪除dev分支就是把dev指針給刪掉,刪掉后,我們就剩下了一條master分支
?
[llg@localhost llg-test-git]$ git branch dev * master [llg@localhost llg-test-git]$ vi one.txt [llg@localhost llg-test-git]$ git branch -d dev 已刪除分支 dev(曾為 8c8117b)。 [llg@localhost llg-test-git]$ git branch * master?
?小結(jié)
因?yàn)閯?chuàng)建、合并和刪除分支非???#xff0c;所以Git鼓勵(lì)你使用分支完成某個(gè)任務(wù),合并后再刪掉分支,這和直接在master分支上工作效果是一樣的,但過程更安全。
- 查看分支:git branch
- 創(chuàng)建分支:git branch <name>
- 切換分支:git checkout <name>
- 創(chuàng)建+切換分支:git checkout -b <name>
- 合并某分支到當(dāng)前分支:git merge <name>
- 刪除分支:git branch -d <name>
?
15.解決分支的沖突問題
首先創(chuàng)建一個(gè)分支并且提交了一次版本倉庫,主分支也提交了一次版本倉庫,如圖所示
這種情況下,Git無法執(zhí)行“快速合并”,只能試圖把各自的修改合并起來,但這種合并就可能會(huì)有沖突
?
[llg@localhost llg-test-git]$ git merge fantasy 自動(dòng)合并 dele 沖突(內(nèi)容):合并沖突于 dele 自動(dòng)合并失敗,修正沖突然后提交修正的結(jié)果。?
果然沖突了!Git告訴我們,readme.txt文件存在沖突,必須手動(dòng)解決沖突后再提交。git status也可以告訴我們沖突的文件
?
[llg@localhost llg-test-git]$ git status # 位于分支 master # 您的分支領(lǐng)先 'origin/master' 共 7 個(gè)提交。 # (使用 "git push" 來發(fā)布您的本地提交) # # 您有尚未合并的路徑。 # (解決沖突并運(yùn)行 "git commit") # # 未合并的路徑: # (使用 "git add <file>..." 標(biāo)記解決方案) # # 雙方修改: dele # 修改尚未加入提交(使用 "git add" 和/或 "git commit -a")?
手工修改沖突?
我們可以直接查看dele的內(nèi)容,Git用<<<<<<<,=======,>>>>>>>標(biāo)記出不同分支的內(nèi)容
我們手動(dòng)修改沖突位置,之后提交文件到暫存區(qū)并且commit
?
[llg@localhost llg-test-git]$ git add dele [llg@localhost llg-test-git]$ git commit -m "cscs" [master b1dd3cc] cscs?
現(xiàn)在,master分支和feature1分支變成了下圖所示
查看分支合并情況?
用帶參數(shù)的git log --graph?也可以看到分支的合并情況
?
* commit b1dd3cc1e90369e4fe2fc93f5a75b46a8918973f |\ Merge: 478f0bc 43149ab | | Author: llg <903857227@qq.com> | | Date: Sun Sep 16 15:10:03 2018 +0800 | | | | cscs | | | * commit 43149abf7f5724e74f64b394521778ceaded39b1 | | Author: llg <903857227@qq.com> | | Date: Sun Sep 16 15:01:24 2018 +0800 | | | | ccc | | * | commit 478f0bc2b144ac6fce457e05c9e596e314bd1f11 | | Author: llg <903857227@qq.com> | | Date: Sun Sep 16 15:02:12 2018 +0800 | | | | ss | | * | commit a22d668c065ad42c38232850fad8082250aa63a2 |\ \ Merge: 57e8b85 1575642 | |/ Author: llg <903857227@qq.com> | | Date: Sun Sep 16 14:55:13 2018 +0800 | | | | Merge branch 'fantasy' | | | | ceshi | |?
?
16.分支管理策略
通常,合并分支時(shí),如果可能,Git會(huì)用Fast forward模式,但這種模式下,刪除分支后,會(huì)丟掉分支信息。
如果要強(qiáng)制禁用Fast forward模式,Git就會(huì)在merge時(shí)生成一個(gè)新的commit,這樣,從分支歷史上就可以看出分支信息。
下面我們實(shí)戰(zhàn)一下--no-ff(禁用Fast forward)方式的git merge,一些前提條件略過??
?
[llg@localhost llg-test-git]$ git merge --no-ff -m "merge with no-ff" dev Merge made by the 'recursive' strategy. dele | 1 + 1 file changed, 1 insertion(+) 合并分支時(shí),加上--no-ff參數(shù)就可以用普通模式合并,合并后的歷史有分支,能看出來曾經(jīng)做過合并,而fast forward合并就看不出來曾經(jīng)做過合并。 [llg@localhost llg-test-git]$ git log --graph --pretty=oneline --abbrev-commit * 3a5456c merge with no-ff |\ | * b68ba37 add merge |/ * 0ed0fe3 測試 * b1dd3cc cscs |\ | * 43149ab ccc * | 478f0bc ss * | a22d668 Merge branch 'fantasy' |\ \ | |/ | * 1575642 xx * | 57e8b85 Merge branch 'fantasy' |\ \ | |/ | * 87bc5d7 ss * | 709521d 版本沖突 * | 8c8117b 在分支上提交版本信息 |/ * 3956cc3 測試兩個(gè)文件提交留一個(gè)文件不提交 * 44449dc 這次測試一次提交三個(gè)文件 * abde635 git練習(xí)測試?
我們來看看不適用no-ff下的策略,發(fā)現(xiàn)會(huì)直接合并,分支信息不能再找到
?
[llg@localhost llg-test-git]$ git log --graph --pretty=oneline --abbrev-commit * 8699b49 dele * 3a5456c merge with no-ff |\ | * b68ba37 add merge |/ * 0ed0fe3 測試 * b1dd3cc cscs |\ | * 43149ab ccc * | 478f0bc ss * | a22d668 Merge branch 'fantasy' |\ \ | |/ | * 1575642 xx * | 57e8b85 Merge branch 'fantasy' |\ \ | |/ | * 87bc5d7 ss * | 709521d 版本沖突 * | 8c8117b 在分支上提交版本信息 |/ * 3956cc3 測試兩個(gè)文件提交留一個(gè)文件不提交 * 44449dc 這次測試一次提交三個(gè)文件 * abde635 git練習(xí)測試? 可以看到,不使用Fast forward模式,merge后就像這樣。
?
分支策略
在實(shí)際開發(fā)中,我們應(yīng)該按照幾個(gè)基本原則進(jìn)行分支管理:
首先,master分支應(yīng)該是非常穩(wěn)定的,也就是僅用來發(fā)布新版本,平時(shí)不能在上面干活;
那在哪干活呢?干活都在dev分支上,也就是說,dev分支是不穩(wěn)定的,到某個(gè)時(shí)候,比如1.0版本發(fā)布時(shí),再把dev分支合并到master上,在master分支發(fā)布1.0版本;
你和你的小伙伴們每個(gè)人都在dev分支上干活,每個(gè)人都有自己的分支,時(shí)不時(shí)地往dev分支上合并就可以了。
所以,團(tuán)隊(duì)合作的分支看起來就像這樣:
?
17.解決Bug的臨時(shí)分支?
軟件開發(fā)中,bug就像家常便飯一樣。有了bug就需要修復(fù),在Git中,由于分支是如此的強(qiáng)大,所以,每個(gè)bug都可以通過一個(gè)新的臨時(shí)分支來修復(fù),修復(fù)后,合并分支,然后將臨時(shí)分支刪除。
當(dāng)你接到一個(gè)修復(fù)一個(gè)代號(hào)101的bug的任務(wù)時(shí),很自然地,你想創(chuàng)建一個(gè)分支issue-101來修復(fù)它,但是,等等,當(dāng)前正在dev上進(jìn)行的工作還沒有提交:
?
[llg@localhost llg-test-git]$ git status # 位于分支 master # 您的分支領(lǐng)先 'origin/master' 共 15 個(gè)提交。 # (使用 "git push" 來發(fā)布您的本地提交) # # 尚未暫存以備提交的變更: # (使用 "git add <file>..." 更新要提交的內(nèi)容) # (使用 "git checkout -- <file>..." 丟棄工作區(qū)的改動(dòng)) # # 修改: dele # 修改尚未加入提交(使用 "git add" 和/或 "git commit -a")?
?
并不是你不想提交,而是工作只進(jìn)行到一半,還沒法提交,預(yù)計(jì)完成還需1天時(shí)間。但是,必須在兩個(gè)小時(shí)內(nèi)修復(fù)該bug,怎么辦?
封鎖現(xiàn)場
幸好,Git還提供了一個(gè)stash功能,可以把當(dāng)前工作現(xiàn)場“儲(chǔ)藏”起來,等以后恢復(fù)現(xiàn)場后繼續(xù)工作,再通過git status 查看發(fā)現(xiàn)工作區(qū)已經(jīng)干凈。?
?
[llg@localhost llg-test-git]$ git stash Saved working directory and index state WIP on master: 7dec792 ss HEAD 現(xiàn)在位于 7dec792 ss [llg@localhost llg-test-git]$ git status # 位于分支 master # 您的分支領(lǐng)先 'origin/master' 共 15 個(gè)提交。 # (使用 "git push" 來發(fā)布您的本地提交) # 無文件要提交,干凈的工作區(qū) 首先確定要在哪個(gè)分支上修復(fù)bug,假定需要在master分支上修復(fù),就從master創(chuàng)建臨時(shí)分支?
?
[llg@localhost llg-test-git]$ git checkout -b issue-101 切換到一個(gè)新分支 'issue-101'?
現(xiàn)在修復(fù)bug,我們通過修改文件模擬這一個(gè)過程
?
[llg@localhost llg-test-git]$ vi delete.txt [llg@localhost llg-test-git]$ git add delete.txt [llg@localhost llg-test-git]$ git commit -m "ss" [issue-101 e0b9de9] ss 1 file changed, 1 insertion(+)?
修復(fù)完成后,切換到master分支,并完成合并,最后刪除issue-101分支
?
[llg@localhost llg-test-git]$ git checkout master 切換到分支 'master' 您的分支領(lǐng)先 'origin/master' 共 15 個(gè)提交。 (使用 "git push" 來發(fā)布您的本地提交) [llg@localhost llg-test-git]$ git merge --no-ff -m "merge bug fix 101" issue-101 Merge made by the 'recursive' strategy. delete.txt | 1 + 1 file changed, 1 insertion(+)?
還原現(xiàn)場?
太棒了,原計(jì)劃兩個(gè)小時(shí)的bug修復(fù)只花了5分鐘!
現(xiàn)在,是時(shí)候接著回到dev分支干活了,切換到dev分支然后用git stash list命令看看
?
[llg@localhost llg-test-git]$ git stash list stash@{0}: WIP on master: 7dec792 ss?
工作現(xiàn)場還在,Git把stash內(nèi)容存在某個(gè)地方了,但是需要恢復(fù)一下,有兩個(gè)辦法:
一是用git stash apply恢復(fù),但是恢復(fù)后,stash內(nèi)容并不刪除,你需要用git stash drop來刪除;
另一種方式是用git stash pop,恢復(fù)的同時(shí)把stash內(nèi)容也刪了:?
?
[llg@localhost llg-test-git]$ git stash pop # 位于分支 master # 您的分支領(lǐng)先 'origin/master' 共 17 個(gè)提交。 # (使用 "git push" 來發(fā)布您的本地提交) # # 尚未暫存以備提交的變更: # (使用 "git add <file>..." 更新要提交的內(nèi)容) # (使用 "git checkout -- <file>..." 丟棄工作區(qū)的改動(dòng)) # # 修改: dele # 修改尚未加入提交(使用 "git add" 和/或 "git commit -a") 丟棄了 refs/stash@{0} (fa2bbbe411ba20c94501e912ec120fa944c06b92) 再用git stash list查看,就看不到任何stash內(nèi)容了??
?
[llg@localhost llg-test-git]$ git stash list [llg@localhost llg-test-git]$?
小結(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)場
?
18.強(qiáng)制刪除分支
當(dāng)需要開發(fā)一個(gè)新功能的時(shí)候,最好創(chuàng)建一個(gè)新的分支進(jìn)行代碼編輯,但是因?yàn)橐恍┣闆r不需要這個(gè)分支了,但是這個(gè)分支從來沒有合并過,所以要使用 git branch -D?的方式強(qiáng)制刪除
?
[llg@localhost llg-test-git]$ vi feichuan.txt.swp [llg@localhost llg-test-git]$ git add feichuan.txt.swp [llg@localhost llg-test-git]$ git commit -m "ss" [feature-vulcan 4cd8736] ss 1 file changed, 1 insertion(+) create mode 100644 feichuan.txt.swp [llg@localhost llg-test-git]$ git checkout master M dele 切換到分支 'master' 您的分支領(lǐng)先 'origin/master' 共 17 個(gè)提交。 (使用 "git push" 來發(fā)布您的本地提交) [llg@localhost llg-test-git]$ git branch -D feature-vulcan 已刪除分支 feature-vulcan(曾為 4cd8736)。?
19.rebease整理分叉歷史
在上一節(jié)我們看到了,多人在同一個(gè)分支上協(xié)作時(shí),很容易出現(xiàn)沖突。即使沒有沖突,后push的童鞋不得不先pull,在本地合并,然后才能push成功。
每次合并再push后,分支變成了這樣
總之看上去很亂,有強(qiáng)迫癥的童鞋會(huì)問:為什么Git的提交歷史不能是一條干凈的直線?
其實(shí)是可以做到的!
Git有一種稱為rebase的操作,有人把它翻譯成“變基”。
先不要隨意展開想象。我們還是從實(shí)際問題出發(fā),看看怎么把分叉的提交變成直線。
在和遠(yuǎn)程分支同步后,我們對(duì)hello.py這個(gè)文件做了兩次提交。用git log命令看看:
?
$ git log --graph --pretty=oneline --abbrev-commit * 582d922 (HEAD -> master) add author * 8875536 add comment * d1be385 (origin/master) init hello * e5e69f1 Merge branch 'dev' |\ | * 57c53ab (origin/dev, dev) fix env conflict | |\ | | * 7a5e5dd add env | * | 7bd91f1 add new env ...?
注意到Git用(HEAD -> master)和(origin/master)標(biāo)識(shí)出當(dāng)前分支的HEAD和遠(yuǎn)程origin的位置分別是582d922 add author和d1be385 init hello,本地分支比遠(yuǎn)程分支快兩個(gè)提交。
現(xiàn)在我們嘗試推送本地分支:
?
$ git push origin master To github.com:michaelliao/learngit.git ! [rejected] master -> master (fetch first) error: failed to push some refs to 'git@github.com:michaelliao/learngit.git' hint: Updates were rejected because the remote contains work that you do hint: not have locally. This is usually caused by another repository pushing hint: to the same ref. You may want to first integrate the remote changes hint: (e.g., 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.?
很不幸,失敗了,這說明有人先于我們推送了遠(yuǎn)程分支。按照經(jīng)驗(yàn),先pull一下:?
?
$ git pull remote: Counting objects: 3, done. remote: Compressing objects: 100% (1/1), done. remote: Total 3 (delta 1), reused 3 (delta 1), pack-reused 0 Unpacking objects: 100% (3/3), done. From github.com:michaelliao/learngit d1be385..f005ed4 master -> origin/master * [new tag] v1.0 -> v1.0 Auto-merging hello.py Merge made by the 'recursive' strategy. hello.py | 1 + 1 file changed, 1 insertion(+)?
再用git status看看狀態(tài):
?
$ git status On branch master Your branch is ahead of 'origin/master' by 3 commits. (use "git push" to publish your local commits)nothing to commit, working tree clean?
加上剛才合并的提交,現(xiàn)在我們本地分支比遠(yuǎn)程分支超前3個(gè)提交。
用git log看看:
?
$ git log --graph --pretty=oneline --abbrev-commit * e0ea545 (HEAD -> master) Merge branch 'master' of github.com:michaelliao/learngit |\ | * f005ed4 (origin/master) set exit=1 * | 582d922 add author * | 8875536 add comment |/ * d1be385 init hello ...?
對(duì)強(qiáng)迫癥童鞋來說,現(xiàn)在事情有點(diǎn)不對(duì)頭,提交歷史分叉了。如果現(xiàn)在把本地分支push到遠(yuǎn)程,有沒有問題?
有!
什么問題?
不好看!
有沒有解決方法?
有!
這個(gè)時(shí)候,rebase就派上了用場。我們輸入命令git rebase試試:
?
$ git rebase First, rewinding head to replay your work on top of it... Applying: add comment Using index info to reconstruct a base tree... M hello.py Falling back to patching base and 3-way merge.. Auto-merging hello.py Applying: add author Using index info to reconstruct a base tree... M hello.py Falling back to patching base and 3-way merge... Auto-merging hello.py?
?
?
?
輸出了一大堆操作,到底是啥效果?再用git log看看:
?
?
$ git log --graph --pretty=oneline --abbrev-commit * 7e61ed4 (HEAD -> master) add author * 3611cfe add comment * f005ed4 (origin/master) set exit=1 * d1be385 init hello?
原本分叉的提交現(xiàn)在變成一條直線了!這種神奇的操作是怎么實(shí)現(xiàn)的?其實(shí)原理非常簡單。我們注意觀察,發(fā)現(xiàn)Git把我們本地的提交“挪動(dòng)”了位置,放到了f005ed4 (origin/master) set exit=1之后,這樣,整個(gè)提交歷史就成了一條直線。rebase操作前后,最終的提交內(nèi)容是一致的,但是,我們本地的commit修改內(nèi)容已經(jīng)變化了,它們的修改不再基于d1be385 init hello,而是基于f005ed4 (origin/master) set exit=1,但最后的提交7e61ed4內(nèi)容是一致的。
這就是rebase操作的特點(diǎn):把分叉的提交歷史“整理”成一條直線,看上去更直觀。缺點(diǎn)是本地的分叉提交已經(jīng)被修改過了。
最后,通過push操作把本地分支推送到遠(yuǎn)程:
?
Mac:~/learngit michael$ git push origin master Counting objects: 6, done. Delta compression using up to 4 threads. Compressing objects: 100% (5/5), done. Writing objects: 100% (6/6), 576 bytes | 576.00 KiB/s, done. Total 6 (delta 2), reused 0 (delta 0) remote: Resolving deltas: 100% (2/2), completed with 1 local object. To github.com:michaelliao/learngit.git f005ed4..7e61ed4 master -> master?
再用git log看看效果:
$ git log --graph --pretty=oneline --abbrev-commit * 7e61ed4 (HEAD -> master, origin/master) add author * 3611cfe add comment * f005ed4 set exit=1 * d1be385 init hello?
?
遠(yuǎn)程分支的提交歷史也是一條直線。
?
總結(jié)?
-
rebase操作可以把本地未push的分叉提交歷史整理成直線;
-
rebase的目的是使得我們?cè)诓榭礆v史提交的變化時(shí)更容易,因?yàn)榉植娴奶峤恍枰綄?duì)比。
20.什么是標(biāo)簽管理
發(fā)布一個(gè)版本時(shí),我們通常先在版本庫中打一個(gè)標(biāo)簽(tag),這樣,就唯一確定了打標(biāo)簽時(shí)刻的版本。將來無論什么時(shí)候,取某個(gè)標(biāo)簽的版本,就是把那個(gè)打標(biāo)簽的時(shí)刻的歷史版本取出來。所以,標(biāo)簽也是版本庫的一個(gè)快照。
Git的標(biāo)簽雖然是版本庫的快照,但其實(shí)它就是指向某個(gè)commit的指針(跟分支很像對(duì)不對(duì)?但是分支可以移動(dòng),標(biāo)簽不能移動(dòng)),所以,創(chuàng)建和刪除標(biāo)簽都是瞬間完成的。
Git有commit,為什么還要引入tag?
“請(qǐng)把上周一的那個(gè)版本打包發(fā)布,commit號(hào)是6a5819e...”
“一串亂七八糟的數(shù)字不好找!”
如果換一個(gè)辦法:
“請(qǐng)把上周一的那個(gè)版本打包發(fā)布,版本號(hào)是v1.2”
“好的,按照tag v1.2查找commit就行!”
所以,tag就是一個(gè)讓人容易記住的有意義的名字,它跟某個(gè)commit綁在一起。
21.創(chuàng)建Git倉庫版本標(biāo)簽
在Git中打標(biāo)簽非常簡單,首先,切換到需要打標(biāo)簽的分支上
?
[llg@localhost llg-test-git]$ git branch dev issue-101 * master [llg@localhost llg-test-git]$ git checkout dev 切換到分支 'dev'?
創(chuàng)建當(dāng)前版本標(biāo)簽
然后,敲命令git tag <name>就可以打一個(gè)新標(biāo)簽
[llg@localhost llg-test-git]$ git tag v1.0創(chuàng)建其他版本標(biāo)簽
默認(rèn)標(biāo)簽是打在最新提交的commit上的。有時(shí)候,如果忘了打標(biāo)簽,比如,現(xiàn)在已經(jīng)是周五了,但應(yīng)該在周一打的標(biāo)簽沒有打,怎么辦?
方法是找到歷史提交的commit id,然后打上就可以了:
?
[llg@localhost llg-test-git]$ git log --pretty=oneline --abbrev-commit 8699b49 dele 3a5456c merge with no-ff b68ba37 add merge 0ed0fe3 測試 b1dd3cc cscs 478f0bc ss 43149ab ccc a22d668 Merge branch 'fantasy' 1575642 xx 57e8b85 Merge branch 'fantasy' 709521d 版本沖突 87bc5d7 ss 8c8117b 在分支上提交版本信息 3956cc3 測試兩個(gè)文件提交留一個(gè)文件不提交 44449dc 這次測試一次提交三個(gè)文件 abde635 git練習(xí)測試 [llg@localhost llg-test-git]$ git tag v1.0 [llg@localhost llg-test-git]$ git tag v0.9 3a5456c [llg@localhost llg-test-git]$ git tag v0.9 v1.0?
查看所有標(biāo)簽?
?
[llg@localhost llg-test-git]$ git tag v0.8 v0.9 v1.0?
查看標(biāo)簽詳細(xì)信息
注意,標(biāo)簽不是按時(shí)間順序列出,而是按字母排序的??梢杂胓it show <tagname>查看標(biāo)簽信息
[llg@localhost llg-test-git]$ git show v0.9 commit 3a5456c07d50d99437d01fbf538a41a4556d7504 Merge: 0ed0fe3 b68ba37 Author: llg <903857227@qq.com> Date: Sun Sep 16 16:04:56 2018 +0800merge with no-ff創(chuàng)建帶說明文字的標(biāo)簽
還可以創(chuàng)建帶有說明的標(biāo)簽,用-a指定標(biāo)簽名,-m指定說明文字
?
[llg@localhost llg-test-git]$ git tag -a v0.8 -m "version 0.8 released" b68ba37 [llg@localhost llg-test-git]$ git show v0.8 tag v0.8 Tagger: llg <903857227@qq.com> Date: Mon Sep 17 09:31:27 2018 +0800version 0.8 releasedcommit b68ba371b04d5b7b6305454c160d7ef88178ea2d Author: llg <903857227@qq.com> Date: Sun Sep 16 16:04:19 2018 +0800add mergediff --git a/dele b/dele index 20c0828..a36d773 100644 --- a/dele +++ b/dele @@ -10,3 +10,4 @@ sad end1111111111111111111111 +2222222222222222222222?
22.操作標(biāo)簽
刪除標(biāo)簽
如果標(biāo)簽打錯(cuò)了,也可以刪除
?
[llg@localhost llg-test-git]$ git tag -d v0.8 已刪除 tag 'v0.8'(曾為 658e2ab)?
推送某個(gè)標(biāo)簽到遠(yuǎn)程倉庫?
因?yàn)閯?chuàng)建的標(biāo)簽都只存儲(chǔ)在本地,不會(huì)自動(dòng)推送到遠(yuǎn)程。所以,打錯(cuò)的標(biāo)簽可以在本地安全刪除。
如果要推送某個(gè)標(biāo)簽到遠(yuǎn)程,使用命令git push origin <tagname>
?
[llg@localhost llg-test-git]$ git push origin v1.0 Username for 'https://github.com': 903857227@qq.com Password for 'https://903857227@qq.com@github.com': Total 0 (delta 0), reused 0 (delta 0) To https://github.com/llgeill/llg-centos-git--test.git * [new tag] v1.0 -> v1.0?
?推送所有標(biāo)簽到遠(yuǎn)程倉庫?
或者,一次性推送全部尚未推送到遠(yuǎn)程的本地標(biāo)簽:
?
[llg@localhost llg-test-git]$ git push origin --tag Username for 'https://github.com': 903857227@qq.com Password for 'https://903857227@qq.com@github.com': Total 0 (delta 0), reused 0 (delta 0) To https://github.com/llgeill/llg-centos-git--test.git * [new tag] v0.9 -> v0.9?
刪除遠(yuǎn)程標(biāo)簽
首先在本地刪除標(biāo)簽
?
[llg@localhost llg-test-git]$ git tag -d v0.8 已刪除 tag 'v0.9'(曾為 3a5456c)?
然后,從遠(yuǎn)程刪除。刪除命令是?git push origin :refs/tags/xxx
?
[llg@localhost llg-test-git]$ git push origin :refs/tags/v0.8 Username for 'https://github.com': 903857227@qq.com Password for 'https://903857227@qq.com@github.com': To https://github.com/llgeill/llg-centos-git--test.git - [deleted] v0.8?
最后去官網(wǎng)github上查看tag是否被刪除,發(fā)現(xiàn)確實(shí)被刪除了
?
23.如何使用Github
我們一直用GitHub作為免費(fèi)的遠(yuǎn)程倉庫,如果是個(gè)人的開源項(xiàng)目,放到GitHub上是完全沒有問題的。其實(shí)GitHub還是一個(gè)開源協(xié)作社區(qū),通過GitHub,既可以讓別人參與你的開源項(xiàng)目,也可以參與別人的開源項(xiàng)目。
在GitHub出現(xiàn)以前,開源項(xiàng)目開源容易,但讓廣大人民群眾參與進(jìn)來比較困難,因?yàn)橐獏⑴c,就要提交代碼,而給每個(gè)想提交代碼的群眾都開一個(gè)賬號(hào)那是不現(xiàn)實(shí)的,因此,群眾也僅限于報(bào)個(gè)bug,即使能改掉bug,也只能把diff文件用郵件發(fā)過去,很不方便。
但是在GitHub上,利用Git極其強(qiáng)大的克隆和分支功能,廣大人民群眾真正可以第一次自由參與各種開源項(xiàng)目了。
參與別人的開源項(xiàng)目?
如何參與一個(gè)開源項(xiàng)目呢?比如人氣極高的bootstrap項(xiàng)目,這是一個(gè)非常強(qiáng)大的CSS框架,你可以訪問它的項(xiàng)目主頁https://github.com/twbs/bootstrap,點(diǎn)“Fork”就在自己的賬號(hào)下克隆了一個(gè)bootstrap倉庫,然后,從自己的賬號(hào)下clone:
??
?
[llg@localhost 桌面]$ git clone git@github.com:llgeill/bootstrap.git 正克隆到 'bootstrap'... remote: Counting objects: 126027, done. remote: Compressing objects: 100% (40/40), done. remote: Total 126027 (delta 44), reused 45 (delta 35), pack-reused 125952 接收對(duì)象中: 100% (126027/126027), 123.12 MiB | 4.97 MiB/s, done. 處理 delta 中: 100% (83420/83420), done.?
一定要從自己的賬號(hào)下clone倉庫,這樣你才能推送修改。如果從bootstrap的作者的倉庫地址git@github.com:twbs/bootstrap.git克隆,因?yàn)闆]有權(quán)限,你將不能推送修改。
Bootstrap的官方倉庫twbs/bootstrap、你在GitHub上克隆的倉庫my/bootstrap,以及你自己克隆到本地電腦的倉庫,他們的關(guān)系就像下圖顯示的那樣:
如果你想修復(fù)bootstrap的一個(gè)bug,或者新增一個(gè)功能,立刻就可以開始干活,干完后,往自己的倉庫推送。
如果你希望bootstrap的官方庫能接受你的修改,你就可以在GitHub上發(fā)起一個(gè)pull request。當(dāng)然,對(duì)方是否接受你的pull request就不一定了。
?
23.如何使用碼云
使用GitHub時(shí),國內(nèi)的用戶經(jīng)常遇到的問題是訪問速度太慢,有時(shí)候還會(huì)出現(xiàn)無法連接的情況(原因你懂的)。
如果我們希望體驗(yàn)Git飛一般的速度,可以使用國內(nèi)的Git托管服務(wù)——碼云(gitee.com)。
和GitHub相比,碼云也提供免費(fèi)的Git倉庫。此外,還集成了代碼質(zhì)量檢測、項(xiàng)目演示等功能。對(duì)于團(tuán)隊(duì)協(xié)作開發(fā),碼云還提供了項(xiàng)目管理、代碼托管、文檔管理的服務(wù),5人以下小團(tuán)隊(duì)免費(fèi)。
?碼云的免費(fèi)版本也提供私有庫功能,只是有5人的成員上限。
使用碼云和使用GitHub類似,我們?cè)诖a云上注冊(cè)賬號(hào)并登錄后,需要先上傳自己的SSH公鑰。選擇右上角用戶頭像 -> 菜單“修改資料”,然后選擇“SSH公鑰”,填寫一個(gè)便于識(shí)別的標(biāo)題,然后把用戶主目錄下的.ssh/id_rsa.pub文件的內(nèi)容粘貼進(jìn)去:
?
已有本地倉庫關(guān)聯(lián)遠(yuǎn)程倉庫?
如果我們已經(jīng)有了一個(gè)本地的git倉庫(例如,一個(gè)名為learngit的本地庫),如何把它關(guān)聯(lián)到碼云的遠(yuǎn)程庫上呢?
首先,我們?cè)诖a云上創(chuàng)建一個(gè)新的項(xiàng)目,選擇右上角用戶頭像 -> 菜單“控制面板”,然后點(diǎn)擊“創(chuàng)建項(xiàng)目”:
創(chuàng)建遠(yuǎn)程倉庫
關(guān)聯(lián)遠(yuǎn)程倉庫
由于剛才已經(jīng)關(guān)聯(lián)了github,如果用同一個(gè)tag orgin的話將會(huì)關(guān)聯(lián)失敗,所以我用了orgins 關(guān)聯(lián)碼云
?
[llg@localhost llg-test-git]$ git remote add origin git@gitee.com:eill/llg-test-git.git fatal: 遠(yuǎn)程 origin 已經(jīng)存在。 [llg@localhost llg-test-git]$ git push -u origin master Username for 'https://github.com': 903857227@qq .com Password for 'https://903857227@qq.com@github.com': 分支 master 設(shè)置為跟蹤來自 origin 的遠(yuǎn)程分支 master。 Everything up-to-date這樣一來,我們的本地庫就可以同時(shí)與多個(gè)遠(yuǎn)程庫互相同步:
刪除關(guān)聯(lián)
[llg@localhost llg-test-git]$ git remote rm origin [llg@localhost llg-test-git]$ git remote -v origins git@gitee.com:eill/centos-git-gitee-test.git (fetch) origins git@gitee.com:eill/centos-git-gitee-test.git (push)碼云也同樣提供了Pull request功能,可以讓其他小伙伴參與到開源項(xiàng)目中來。你可以通過Fork我的倉庫:https://gitee.com/liaoxuefeng/learngit,創(chuàng)建一個(gè)your-gitee-id.txt的文本文件, 寫點(diǎn)自己學(xué)習(xí)Git的心得,然后推送一個(gè)pull request給我,這個(gè)倉庫會(huì)在碼云和GitHub做雙向同步。
24.自定義Git配置
在安裝Git一節(jié)中,我們已經(jīng)配置了user.name和user.email,實(shí)際上,Git還有很多可配置項(xiàng)。
開啟命令行顏色
比如,讓Git顯示顏色,會(huì)讓命令輸出看起來更醒目
[忽略特殊文件
有些時(shí)候,你必須把某些文件放到Git工作目錄中,但又不能提交它們,比如保存了數(shù)據(jù)庫密碼的配置文件啦,等等,每次git status都會(huì)顯示Untracked files ...,有強(qiáng)迫癥的童鞋心里肯定不爽。
好在Git考慮到了大家的感受,這個(gè)問題解決起來也很簡單,在Git工作區(qū)的根目錄下創(chuàng)建一個(gè)特殊的.gitignore文件,然后把要忽略的文件名填進(jìn)去,Git就會(huì)自動(dòng)忽略這些文件。
不需要從頭寫.gitignore文件,GitHub已經(jīng)為我們準(zhǔn)備了各種配置文件,只需要組合一下就可以使用了。所有配置文件可以直接在線瀏覽:https://github.com/github/gitignore
忽略文件的原則是:
舉個(gè)例子:
假設(shè)你在Windows下進(jìn)行Python開發(fā),Windows會(huì)自動(dòng)在有圖片的目錄下生成隱藏的縮略圖文件,如果有自定義目錄,目錄下就會(huì)有Desktop.ini文件,因此你需要忽略Windows自動(dòng)生成的垃圾文件:
# Windows: Thumbs.db ehthumbs.db Desktop.ini然后,繼續(xù)忽略Python編譯產(chǎn)生的.pyc、.pyo、dist等文件或目錄:
# Python: *.py[cod] *.so *.egg *.egg-info dist build加上你自己定義的文件,最終得到一個(gè)完整的.gitignore文件,內(nèi)容如下:
# Windows: Thumbs.db ehthumbs.db Desktop.ini# Python: *.py[cod] *.so *.egg *.egg-info dist build# My configurations: db.ini deploy_key_rsa最后一步就是把.gitignore也提交到Git,就完成了!當(dāng)然檢驗(yàn).gitignore的標(biāo)準(zhǔn)是git status命令是不是說working directory clean。
使用Windows的童鞋注意了,如果你在資源管理器里新建一個(gè).gitignore文件,它會(huì)非常弱智地提示你必須輸入文件名,但是在文本編輯器里“保存”或者“另存為”就可以把文件保存為.gitignore了。
有些時(shí)候,你想添加一個(gè)文件到Git,但發(fā)現(xiàn)添加不了,原因是這個(gè)文件被.gitignore忽略了:
$ git add App.class The following paths are ignored by one of your .gitignore files: App.class Use -f if you really want to add them.如果你確實(shí)想添加該文件,可以用-f強(qiáng)制添加到Git:
$ git add -f App.class或者你發(fā)現(xiàn),可能是.gitignore寫得有問題,需要找出來到底哪個(gè)規(guī)則寫錯(cuò)了,可以用git check-ignore命令檢查:
$ git check-ignore -v App.class .gitignore:3:*.class App.classGit會(huì)告訴我們,.gitignore的第3行規(guī)則忽略了該文件,于是我們就可以知道應(yīng)該修訂哪個(gè)規(guī)則。
小結(jié)
-
忽略某些文件時(shí),需要編寫.gitignore;
-
.gitignore文件本身要放到版本庫里,并且可以對(duì).gitignore做版本管理!
配置別名
有沒有經(jīng)常敲錯(cuò)命令?比如git status?status這個(gè)單詞真心不好記。
如果敲git st就表示git status那就簡單多了,當(dāng)然這種偷懶的辦法我們是極力贊成的。
我們只需要敲一行命令,告訴Git,以后st就表示status(這個(gè)功能在linux上也有)
[llg@localhost llg-test-git]$ git config --global alias.st status [llg@localhost llg-test-git]$ git st # 位于分支 dev # 尚未暫存以備提交的變更: # (使用 "git add <file>..." 更新要提交的內(nèi)容) # (使用 "git checkout -- <file>..." 丟棄工作區(qū)的改動(dòng)) # # 修改: dele # 修改尚未加入提交(使用 "git add" 和/或 "git commit -a")配置文件
配置Git的時(shí)候,加上--global是針對(duì)當(dāng)前用戶起作用的,如果不加,那只針對(duì)當(dāng)前的倉庫起作用。
配置文件放哪了?每個(gè)倉庫的Git配置文件都放在.git/config文件中:
$ cat .git/config [core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true precomposeunicode = true [remote "origin"] url = git@github.com:michaelliao/learngit.git fetch = +refs/heads/*:refs/remotes/origin/* [branch "master"] remote = origin merge = refs/heads/master [alias] last = log -1別名就在[alias]后面,要?jiǎng)h除別名,直接把對(duì)應(yīng)的行刪掉即可。
而當(dāng)前用戶的Git配置文件放在用戶主目錄下的一個(gè)隱藏文件.gitconfig中:?
$ cat .gitconfig [alias] co = checkout ci = commit br = branch st = status [user] name = Your Name email = your@email.com 配置別名也可以直接修改這個(gè)文件,如果改錯(cuò)了,可以刪掉文件重新通過命令配置。小結(jié)
給Git配置好別名,就可以輸入命令時(shí)偷個(gè)懶。我們鼓勵(lì)偷懶。
25.搭建Git服務(wù)器
在遠(yuǎn)程倉庫一節(jié)中,我們講了遠(yuǎn)程倉庫實(shí)際上和本地倉庫沒啥不同,純粹為了7x24小時(shí)開機(jī)并交換大家的修改。
GitHub就是一個(gè)免費(fèi)托管開源代碼的遠(yuǎn)程倉庫。但是對(duì)于某些視源代碼如生命的商業(yè)公司來說,既不想公開源代碼,又舍不得給GitHub交保護(hù)費(fèi),那就只能自己搭建一臺(tái)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),下面,正式開始安裝。(在這里我使用的是Centos)
第一步,安裝git
[llg@localhost llg-test-git]$ sudo yum install git第二步,創(chuàng)建一個(gè)git用戶,用來運(yùn)行g(shù)it服務(wù)
[llg@localhost llg-test-git]$ sudo adduser git第三步,創(chuàng)建證書登錄:
收集所有需要登錄的用戶的公鑰,就是他們自己的id_rsa.pub文件,把所有公鑰導(dǎo)入到/home/git/.ssh/authorized_keys文件里,一行一個(gè)。
第四步,初始化Git倉庫:
先選定一個(gè)目錄作為Git倉庫,假定是/srv/sample.git,在/srv目錄下輸入命令:
[llg@localhost llg-test-git]$ sudo git init --bare sample.git 初始化空的 Git 版本庫于 /home/llg/桌面/llg-test-git/sample.git/Git就會(huì)創(chuàng)建一個(gè)裸倉庫,裸倉庫沒有工作區(qū),因?yàn)榉?wù)器上的Git倉庫純粹是為了共享,所以不讓用戶直接登錄到服務(wù)器上去改工作區(qū),并且服務(wù)器上的Git倉庫通常都以.git結(jié)尾。然后,把owner改為git(用戶權(quán)限)
[llg@localhost llg-test-git]$ sudo chown -R git:git sample.git第五步,禁用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)退出。
第六步,克隆遠(yuǎn)程倉庫:
現(xiàn)在,可以通過git clone命令克隆遠(yuǎn)程倉庫了,在各自的電腦上運(yùn)行:
[llg@localhost llg-test-git]$ git clone git@127.0.0.1:/llg-test-git/sample.git/剩下的推送就簡單了。
管理公鑰
如果團(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è)工具。
這里我們也不介紹Gitolite了,不要把有限的生命浪費(fèi)到權(quán)限斗爭中。
小結(jié)
-
搭建Git服務(wù)器非常簡單,通常10分鐘即可完成;
-
要方便管理公鑰,用Gitosis;
-
要像SVN那樣變態(tài)地控制權(quán)限,用Gitolite。
26.總結(jié)
經(jīng)過兩天的學(xué)習(xí),站在巨人的肩膀上,我把命令都執(zhí)行了一遍,大概有了個(gè)印象。
Git雖然極其強(qiáng)大,命令繁多,但常用的就那么十來個(gè),掌握好這十幾個(gè)常用命令,你已經(jīng)可以得心應(yīng)手地使用Git了。
友情附贈(zèng)國外網(wǎng)友制作的Git Cheat Sheet,建議打印出來備用:
Git Cheat Sheet
Git的官方網(wǎng)站:http://git-scm.com
?
?
?
?
?
?
作者:廖雪峰
鏈接:https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000
來源:廖雪峰的官方網(wǎng)站
?
轉(zhuǎn)載于:https://www.cnblogs.com/liliguang/p/9661646.html
總結(jié)
以上是生活随笔為你收集整理的分布式版本控制系统Git的安装与使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: rhel7+apache+c cgi+动
- 下一篇: Git for Windows之推送本地