1.(本次做業要求來自:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE1/homework/2103java
2. 個人Github遠程倉庫地址: https://github.com/llgeill/llg-centos-git--testlinux
3. 個人Github遠程倉庫地址截圖android
不少人都知道,Linus在1991年建立了開源的Linux,今後,Linux系統不斷髮展,已經成爲最大的服務器系統軟件了。git
Linus雖然建立了Linux,但Linux的壯大是靠全世界熱心的志願者參與的,這麼多人在世界各地爲Linux編寫代碼,那Linux的代碼是如何管理的呢?github
事實是,在2002年之前,世界各地的志願者把源代碼文件經過diff的方式發給Linus,而後由Linus本人經過手工方式合併代碼!web
你也許會想,爲何Linus不把Linux代碼放到版本控制系統裏呢?不是有CVS、SVN這些免費的版本控制系統嗎?由於Linus堅決地反對CVS和SVN,這些集中式的版本控制系統不但速度慢,並且必須聯網才能使用。有一些商用的版本控制系統,雖然比CVS、SVN好用,但那是付費的,和Linux的開源精神不符。spring
不過,到了2002年,Linux系統已經發展了十年了,代碼庫之大讓Linus很難繼續經過手工方式管理了,社區的弟兄們也對這種方式表達了強烈不滿,因而Linus選擇了一個商業的版本控制系統BitKeeper,BitKeeper的東家BitMover公司出於人道主義精神,受權Linux社區無償使用這個版本控制系統。shell
安定團結的大好局面在2005年就被打破了,緣由是Linux社區牛人彙集,難免沾染了一些梁山好漢的江湖習氣。開發Samba的Andrew試圖破解BitKeeper的協議(這麼幹的其實也不僅他一個),被BitMover公司發現了(監控工做作得不錯!),因而BitMover公司怒了,要收回Linux社區的無償使用權。數據庫
Linus能夠向BitMover公司道個歉,保證之後嚴格管教弟兄們,嗯,這是不可能的。實際狀況是這樣的:bootstrap
Linus花了兩週時間本身用C寫了一個分佈式版本控制系統,這就是Git!一個月以內,Linux系統的源碼已經由Git管理了!牛是怎麼定義的呢?你們能夠體會一下。
Git迅速成爲最流行的分佈式版本控制系統,尤爲是2008年,GitHub網站上線了,它爲開源項目免費提供Git存儲,無數開源項目開始遷移至GitHub,包括jQuery,PHP,Ruby等等。
歷史就是這麼偶然,若是不是當年BitMover公司威脅Linux社區,可能如今咱們就沒有免費而超級好用的Git了。
若是要想了解分佈式是什麼意思,那麼咱們得先去了解它的對立面集中式
工具:git
內容:布式版本控制系統沒有「中央服務器」,每一個人的電腦上都是一個完整的版本庫,這樣,你工做的時候,就不須要聯網了,由於版本庫就在你本身的電腦上。既然每一個人電腦上都有一個完整的版本庫,那多我的如何協做呢?比方說你在本身電腦上改了文件A,你的同事也在他的電腦上改了文件A,這時,大家倆之間只需把各自的修改推送給對方,就能夠互相看到對方的修改了。
優勢:和集中式版本控制系統相比,分佈式版本控制系統的安全性要高不少,由於每一個人電腦裏都有完整的版本庫,某一我的的電腦壞掉了沒關係,隨便從其餘人那裏複製一個就能夠了。而集中式版本控制系統的中央服務器要是出了問題,全部人都無法幹活了。在實際使用分佈式版本控制系統的時候,其實不多在兩人之間的電腦上推送版本庫的修改,由於可能大家倆不在一個局域網內,兩臺電腦互相訪問不了,也可能今天你的同事病了,他的電腦壓根沒有開機。所以,分佈式版本控制系統一般也有一臺充當「中央服務器」的電腦,但這個服務器的做用僅僅是用來方便「交換」你們的修改,沒有它你們也同樣幹活,只是交換修改不方便而已。固然,Git的優點不單是沒必要聯網這麼簡單,後面咱們還會看到Git極其強大的分支管理,把SVN等遠遠拋在了後面(svn其實也有分支功能,不過是在服務器上的分支)
能夠直接從官網下載相應操做系統的Git而後進行安裝,固然也能夠使用命令行的方式
yum install -y git
https://git-scm.com/
用戶名和郵箱地址的做用
修改用戶名和郵箱地址
查看用戶名和郵箱地址
如下全部操做都在centos上操做完成
版本庫又名倉庫,英文名repository,你能夠簡單理解成一個文件夾,這個文件夾裏面的全部文件均可以被Git管理起來,每一個文件的修改、刪除,Git都能跟蹤,以便任什麼時候刻均可以追蹤歷史,或者在未來某個時刻能夠「還原」。因此,建立一個版本庫很是簡單。
首先,選擇一個合適的地方,建立一個空目錄
#建立一個文件件 [llg@localhost 桌面]$ mkdir llg-test-git #進入文件夾目錄 [llg@localhost 桌面]$ cd llg-test-git/ #顯示當前文件夾路徑 [llg@localhost llg-test-git]$ pwd
接着,最重要的一步 經過git init 的命令將當前文件夾變成一個版本庫
[llg@localhost llg-test-git]$ git init 初始化空的 Git 版本庫於 /home/llg/桌面/llg-test-git/.git/ [llg@localhost llg-test-git]$
最後,經過ls -al 命令,發現多了個git文件夾。這個目錄是Git來跟蹤管理版本庫的,沒事千萬不要手動修改這個目錄裏面的文件,否則改亂了,就把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]$
首先須要注意的是版本管理的受衆範圍
首先,使用vi建立一個文件而且添加一些內容。確保此文件必須在這個版本倉庫裏面也就是咱們惡毒llg-test-git文件夾,否則放在其餘地方是不能被版本控制的。
[llg@localhost llg-test-git]$ vi llg.txt
[llg@localhost llg-test-git]$
接着,將文件顯示的經過git add命令添加到版本庫裏面,不過在這以前咱們使用git status 來查看一下還沒使用git add命令時候的狀態和使用git add以後的狀態,比較一下不一樣。經過比較,咱們發現了當使用git add 命令的時候實際上是創建起了文件跟蹤的功能,以後使用git status 就能夠看到有一個新文件
[llg@localhost llg-test-git]$ git status # 位於分支 master # # 初始提交 # # 未跟蹤的文件: # (使用 "git add <file>..." 以包含要提交的內容) # # 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>..." 撤出暫存區) # # 新文件: llg.txt # [llg@localhost llg-test-git]$
[llg@localhost llg-test-git]$ git commit -m "git練習測試" [master(根提交) abde635] git練習測試 1 file changed, 1 insertion(+) create mode 100644 llg.txt [llg@localhost llg-test-git]$
疑問:爲何Git添加文件須要add
,commit
一共兩步呢?
由於commit
能夠一次提交不少文件,因此你能夠屢次add
不一樣的文件,好比下圖,能夠跟蹤多個文件而後所有一次性提交到版本庫裏面.
[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 "此次測試一次提交三個文件" [master 44449dc] 此次測試一次提交三個文件 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
無文件要提交,乾淨的工做區
[llg@localhost llg-test-git]$
在學習版本回退以前咱們線來了解下兩個經常使用的命令git status和git diff
剛剛在建立版本庫的時候咱們已經使用了,用來查看git的狀態,通常能夠拿來查看咱們作的某些操做以後的狀態,例如修改文件,添加文件等等
例如咱們修改一個文件而後使用git status查看,發現了提示llg.txt是修改過的文件
[llg@localhost llg-test-git]$ vi llg.txt [llg@localhost llg-test-git]$ git status # 位於分支 master # 還沒有暫存以備提交的變動: # (使用 "git add <file>..." 更新要提交的內容) # (使用 "git checkout -- <file>..." 丟棄工做區的改動) # # 修改: llg.txt # 修改還沒有加入提交(使用 "git add" 和/或 "git commit -a") [llg@localhost llg-test-git]$
因爲文件修改事後,咱們有時候可能想知道具體修改了什麼內容,位置在那裏,區別是什麼等等。,因此咱們須要git sdiff命令來得到這個修改先後的對照信息
[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]$
[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那裏,這優勢相似與打通關遊戲,你能夠在任意經過的關卡中來往穿梭
首先,咱們須要使用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 測試兩個文件提交留一個文件不提交 commit 44449dc5261b8a66bac14ce302519f26895d0163 Author: llg <903857227@qq.com> Date: Fri Sep 14 20:11:22 2018 +0800 此次測試一次提交三個文件 commit abde635c93434ac4172caa4e0c6383e9dfc3d522 Author: llg <903857227@qq.com> Date: Fri Sep 14 20:07:31 2018 +0800 git練習測試 [llg@localhost llg-test-git]$
--pretty=oneline
參數
[llg@localhost llg-test-git]$ git log --pretty=oneline
3956cc36e1017c14e79d9de0944bb9baa6d2ff51 測試兩個文件提交留一個文件不提交
44449dc5261b8a66bac14ce302519f26895d0163 此次測試一次提交三個文件
abde635c93434ac4172caa4e0c6383e9dfc3d522 git練習測試
[llg@localhost llg-test-git]$
首先,Git必須知道當前版本是哪一個版本,在Git中,用HEAD
表示當前版本,也就是最新的提交3956cc...
(注意個人提交ID和你的確定不同),上一個版本就是HEAD^
,上上一個版本就是HEAD^^
,固然往上100個版本寫100個^
比較容易數不過來,因此寫成HEAD~100
。
咱們要把當前版本<測試兩個文件提交留一個文件不提交>回退到上一個版本<此次測試一次提交三個文件>,就能夠使用git reset
命令:
從下圖咱們能夠分析出,其實HEAD表明的是頭指針,畢竟這個git使用c語言寫的,咱們對C應該也是不陌生的,因此這是一個雙向鏈表,能夠向前也能夠向後,只要咱們知道commit ID。
[llg@localhost llg-test-git]$ git reset --hard HEAD HEAD 如今位於 3956cc3 測試兩個文件提交留一個文件不提交 [llg@localhost llg-test-git]$ git reset --hard HEAD^ HEAD 如今位於 44449dc 此次測試一次提交三個文件 [llg@localhost llg-test-git]$ git reset --hard HEAD^ HEAD 如今位於 abde635 git練習測試 [llg@localhost llg-test-git]$
當咱們跳的比較遠的時候,也能夠直接指定commit ID 來跳轉
[llg@localhost llg-test-git]$ git reset --hard 3956cc3
HEAD 如今位於 3956cc3 測試兩個文件提交留一個文件不提交
[llg@localhost llg-test-git]$
當咱們想要回到以前最新的版本的時候,咱們會想到用git log,可是很不幸咱們發現以前的版本信息都沒有了。因此咱們還有一個命令用來找回以前的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練習測試 [llg@localhost llg-test-git]$
能夠拿到全部的操做記錄
從下面咱們能夠找到帶有commit字樣的就是咱們以前建立的版本,可是隻提供了ID的七爲數,可是不要緊,git會自動識別出來
[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: 測試兩個文件提交留一個文件不提交 44449dc HEAD@{3}: commit: 此次測試一次提交三個文件 abde635 HEAD@{4}: commit (initial): git練習測試 [llg@localhost llg-test-git]$ git reset --hard 3956cc3 HEAD 如今位於 3956cc3 測試兩個文件提交留一個文件不提交 [llg@localhost llg-test-git]$
首先是官圖解釋,從下圖能夠看出若是咱們想直接提交文件到master分支上,那麼直接使用 git commit -a便可
接着再看看其他大佬繪製的圖
工做區有一個隱藏目錄.git
,這個不算工做區,而是Git的版本庫。
Git的版本庫裏存了不少東西,其中最重要的就是稱爲stage(或者叫index)的暫存區,還有Git爲咱們自動建立的第一個分支master
,以及指向master
的一個指針叫HEAD
。
假如咱們在commit以後沒有任何操做,那麼咱們暫存區就是空的
當咱們添加了文件或者修改了文件,而且使用了add命令那麼暫存區stage就又有了文件
當咱們使用commit提交以後,那麼早存區又變成了空
git checkout -- file
。首先修改工做區的文件,不執行add操做
檢查git狀態,發現提示使用git checkout -- file 命令撤回操做 ,執行以後發現已經成功撤回
[llg@localhost llg-test-git]$ git status # 位於分支 master # 還沒有暫存以備提交的變動: # (使用 "git add <file>..." 更新要提交的內容) # (使用 "git checkout -- <file>..." 丟棄工做區的改動) # # 修改: 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]$
git reset HEAD <file>
,就回到了場景1,第二步按場景1操做。首先修改文件而且經過add放到暫存區
[llg@localhost llg-test-git]$ git status # 位於分支 master # 要提交的變動: # (使用 "git reset HEAD <file>..." 撤出暫存區) # # 修改: one.txt # [llg@localhost llg-test-git]$
根據提示使用git reset HEAD <file> 撤出暫存區,執行成功
[llg@localhost llg-test-git]$ git status # 位於分支 master # 要提交的變動: # (使用 "git reset HEAD <file>..." 撤出暫存區) # # 修改: one.txt # [llg@localhost llg-test-git]$ git reset HEAD one.txt 重置後撤出暫存區的變動: M one.txt [llg@localhost llg-test-git]$ git status # 位於分支 master # 還沒有暫存以備提交的變動: # (使用 "git add <file>..." 更新要提交的內容) # (使用 "git checkout -- <file>..." 丟棄工做區的改動) # # 修改: one.txt # 修改還沒有加入提交(使用 "git add" 和/或 "git commit -a") [llg@localhost llg-test-git]$
此處的刪除文件是指當一個文件提交到版本庫後,也就是master分支。若是在工做區刪除這個文件,那麼將會使工做區文件與版本庫文件不對應,在這裏須要分清兩種使用狀況。
那麼就應該使用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>..." 撤出暫存區) # # 刪除: delete.txt # [llg@localhost llg-test-git]$
固然咱們經過git status 命令能夠看出這一操做只是保留在了暫存區,因此咱們還須要commit命令提交這一更改,其實能夠把這一命令想象成修改的命令
[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 無文件要提交,乾淨的工做區 [llg@localhost llg-test-git]$
根據git status 提示的方法,咱們能夠從版本庫中checkout中某些文件
[llg@localhost llg-test-git]$ git checkout -- delete.txt
另一個一個簡單的方法就是從新把版本庫更新回來,可是這個前提是你得保證只有這麼一個刪除文件,若是有其餘文件修改了而且未放到暫存區,那麼就很是可怕了。
[llg@localhost llg-test-git]$ git reset --hard HEAD^ HEAD 如今位於 eda17f9 這是一個將要被刪除的文件 [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]$
既然git的其中一個目的就是爲了協做開發,那麼遠程倉庫就是爲了這一個目的的。經過將倉庫放在一個遠程的服務器上,讓全部人均可以訪問這個倉庫,能夠一塊兒更新和提交。
實際狀況每每是這樣,找一臺電腦充當服務器的角色,天天24小時開機,其餘每一個人都從這個「服務器」倉庫克隆一份到本身的電腦上,而且各自把各自的提交推送到服務器倉庫裏,也從服務器倉庫中拉取別人的提交。
徹底能夠本身搭建一臺運行Git的服務器,不過現階段,爲了學Git先搭個服務器絕對是小題大做。好在這個世界上有個叫GitHub的神奇的網站,從名字就能夠看出,這個網站就是提供Git倉庫託管服務的,因此,只要註冊一個GitHub帳號,就能夠免費得到Git遠程倉庫。
在繼續閱讀後續內容前,請自行註冊GitHub帳號。因爲你的本地Git倉庫和GitHub倉庫之間的傳輸是經過SSH加密的,因此,須要一點設置:
第1步:建立SSH Key。在用戶主目錄下,看看有沒有.ssh目錄,若是有,再看看這個目錄下有沒有id_rsa
和id_rsa.pub
這兩個文件,若是已經有了,可直接跳到下一步。若是沒有,打開Shell(Windows下打開Git Bash),建立SSH Key:
[llg@localhost ~]$ ssh-keygen -t rsa -C "903857227@qq.com"
若是一切順利的話,能夠在用戶主目錄裏找到.ssh
目錄,裏面有id_rsa
和id_rsa.pub
兩個文件,這兩個就是SSH Key的祕鑰對,id_rsa
是私鑰,不能泄露出去,id_rsa.pub
是公鑰,能夠放心地告訴任何人。
第2步:登錄GitHub,打開「Account settings」,「SSH Keys」頁面:
而後,點「Add SSH Key」,填上任意Title,在Key文本框裏粘貼id_rsa.pub
文件的內容:
[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呢?由於GitHub須要識別出你推送的提交確實是你推送的,而不是別人冒充的,而Git支持SSH協議,因此,GitHub只要知道了你的公鑰,就能夠確認只有你本身才能推送。
固然,GitHub容許你添加多個Key。假定你有若干電腦,你一下子在公司提交,一下子在家裏提交,只要把每臺電腦的Key都添加到GitHub,就能夠在每臺電腦上往GitHub推送了。
最後友情提示,在GitHub上免費託管的Git倉庫,任何人均可以看到喔(但只有你本身才能改)。因此,不要把敏感信息放進去。
若是你不想讓別人看到Git庫,有兩個辦法,一個是交點保護費,讓GitHub把公開的倉庫變成私有的,這樣別人就看不見了(不可讀更不可寫)。另外一個辦法是本身動手,搭一個Git服務器,由於是你本身的Git服務器,因此別人也是看不見的。這個方法咱們後面會講到的,至關簡單,公司內部開發必備。
確保你擁有一個GitHub帳號後,咱們就即將開始遠程倉庫的學習。
首先咱們github上登錄本身賬號後建立一個倉庫
接着咱們能夠看到建立完倉庫後給咱們的提示
根據上邊提示輸入命令
[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 設置爲跟蹤來自 origin 的遠程分支 master。
git remote add origin git@server-name:path/repo-name.git
;git push -u origin master
第一次推送master分支的全部內容;git push origin master
推送最新修改;首先咱們從github上建立一個遠程倉庫
首先在github上找到能夠克隆的地址
下一步是用命令git clone
克隆一個本地庫,咱們能夠發現項目已經克隆下來
[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 接收對象中: 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 計算機組成原理201407
測試從本地倉庫推送回遠程倉庫
[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 # 您的分支領先 'origin/master' 共 1 個提交。 # (使用 "git push" 來發布您的本地提交) # 無文件要提交,乾淨的工做區 [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 設置爲跟蹤來自 origin 的遠程分支 master。
分支就是科幻電影裏面的平行宇宙,當你正在電腦前努力學習Git的時候,另外一個你正在另外一個平行宇宙裏努力學習SVN。
若是兩個平行宇宙互不干擾,那對如今的你也沒啥影響。不過,在某個時間點,兩個平行宇宙合併了,結果,你既學會了Git又學會了SVN!
分支在實際中有什麼用呢?假設你準備開發一個新功能,可是須要兩週才能完成,第一週你寫了50%的代碼,若是馬上提交,因爲代碼還沒寫完,不完整的代碼庫會致使別人不能幹活了。若是等代碼所有寫完再一次提交,又存在丟失天天進度的巨大風險。
如今有了分支,就不用怕了。你建立了一個屬於你本身的分支,別人看不到,還繼續在原來的分支上正常工做,而你在本身的分支上幹活,想提交就提交,直到開發完畢後,再一次性合併到原來的分支上,這樣,既安全,又不影響別人工做。
其餘版本控制系統如SVN等都有分支管理,可是用過以後你會發現,這些版本控制系統建立和切換分支比蝸牛還慢,簡直讓人沒法忍受,結果分支功能成了擺設,你們都不去用。
但Git的分支是不同凡響的,不管建立、切換和刪除分支,Git在1秒鐘以內就能完成!不管你的版本庫是1個文件仍是1萬個文件。
在版本回退裏,每次提交,Git都把它們串成一條時間線,這條時間線就是一個分支。截止到目前,只有一條時間線,在Git裏,這個分支叫主分支,即master
分支。HEAD
嚴格來講不是指向提交,而是指向master
,master
纔是指向提交的,因此,HEAD
指向的就是當前分支。
一開始的時候,master
分支是一條線,Git用master
指向最新的提交,再用HEAD
指向master
,就能肯定當前分支,以及當前分支的提交點:
當咱們建立新的分支,例如dev
時,Git新建了一個指針叫dev
,指向master
相同的提交,再把HEAD
指向dev
,就表示當前分支在dev
上
git checkout
命令加上-b
參數表示建立分支並切換分支
[llg@localhost llg-test-git]$ git checkout -b dev 切換到一個新分支 'dev' [llg@localhost llg-test-git]$
上面的命令等價與下面兩條命令的結合
[llg@localhost llg-test-git]$ git branch dev [llg@localhost llg-test-git]$ git checkout dev 切換到分支 'dev'
咱們能夠使用git branch 查看當前分支的狀況
[llg@localhost llg-test-git]$ git branch * dev master
你看,Git建立一個分支很快,由於除了增長一個dev
指針,改改HEAD
的指向,工做區的文件都沒有任何變化!
不過,從如今開始,對工做區的修改和提交就是針對dev
分支了,好比新提交一次後,dev
指針往前移動一步,而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 無文件要提交,乾淨的工做區 [llg@localhost llg-test-git]$
當咱們從新切換到master分支時候發現one.txt根本沒有變化,由於咱們commit的是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
假如咱們在dev
上的工做完成了,就能夠把dev
合併到master
上。Git怎麼合併呢?最簡單的方法,就是直接把master
指向dev
的當前提交,就完成了合併 。注意下面的Fast-forwar 信息,Git告訴咱們此次合併是「快進模式」,也就是直接把master
指向dev
的當前提交,因此合併速度很是快。固然,也不是每次合併都能Fast-forward
,咱們後面會講其餘方式的合併。
[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
由於建立、合併和刪除分支很是快,因此Git鼓勵你使用分支完成某個任務,合併後再刪掉分支,這和直接在master
分支上工做效果是同樣的,但過程更安全。
git branch
git branch <name>
git checkout <name>
git checkout -b <name>
git merge <name>
git branch -d <name>
首先建立一個分支而且提交了一次版本倉庫,主分支也提交了一次版本倉庫,如圖所示
這種狀況下,Git沒法執行「快速合併」,只能試圖把各自的修改合併起來,但這種合併就可能會有衝突
[llg@localhost llg-test-git]$ git merge fantasy
自動合併 dele
衝突(內容):合併衝突於 dele
自動合併失敗,修正衝忽然後提交修正的結果。
果真衝突了!Git告訴咱們,readme.txt
文件存在衝突,必須手動解決衝突後再提交。git status
也能夠告訴咱們衝突的文件
[llg@localhost llg-test-git]$ git status # 位於分支 master # 您的分支領先 'origin/master' 共 7 個提交。 # (使用 "git push" 來發布您的本地提交) # # 您有還沒有合併的路徑。 # (解決衝突並運行 "git commit") # # 未合併的路徑: # (使用 "git add <file>..." 標記解決方案) # # 雙方修改: dele # 修改還沒有加入提交(使用 "git add" 和/或 "git commit -a")
咱們能夠直接查看dele的內容,Git用<<<<<<<
,=======
,>>>>>>>
標記出不一樣分支的內容
咱們手動修改衝突位置,以後提交文件到暫存區而且commit
[llg@localhost llg-test-git]$ git add dele [llg@localhost llg-test-git]$ git commit -m "cscs" [master b1dd3cc] cscs
如今,master
分支和feature1
分支變成了下圖所示
用帶參數的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 | |
一般,合併分支時,若是可能,Git會用Fast forward
模式,但這種模式下,刪除分支後,會丟掉分支信息。
若是要強制禁用Fast forward
模式,Git就會在merge時生成一個新的commit,這樣,從分支歷史上就能夠看出分支信息。
下面咱們實戰一下--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(+) 合併分支時,加上--no-ff參數就能夠用普通模式合併,合併後的歷史有分支,能看出來曾經作過合併,而fast forward合併就看不出來曾經作過合併。 [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 測試兩個文件提交留一個文件不提交 * 44449dc 此次測試一次提交三個文件 * abde635 git練習測試
咱們來看看不適用no-ff下的策略,發現會直接合並,分支信息不能再找到
[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 測試兩個文件提交留一個文件不提交 * 44449dc 此次測試一次提交三個文件 * abde635 git練習測試
Fast forward
模式,merge後就像這樣。
在實際開發中,咱們應該按照幾個基本原則進行分支管理:
首先,master
分支應該是很是穩定的,也就是僅用來發布新版本,平時不能在上面幹活;
那在哪幹活呢?幹活都在dev
分支上,也就是說,dev
分支是不穩定的,到某個時候,好比1.0版本發佈時,再把dev
分支合併到master
上,在master
分支發佈1.0版本;
你和你的小夥伴們每一個人都在dev
分支上幹活,每一個人都有本身的分支,時不時地往dev
分支上合併就能夠了。
因此,團隊合做的分支看起來就像這樣:
軟件開發中,bug就像屢見不鮮同樣。有了bug就須要修復,在Git中,因爲分支是如此的強大,因此,每一個bug均可以經過一個新的臨時分支來修復,修復後,合併分支,而後將臨時分支刪除。
當你接到一個修復一個代號101的bug的任務時,很天然地,你想建立一個分支issue-101
來修復它,可是,等等,當前正在dev
上進行的工做尚未提交:
[llg@localhost llg-test-git]$ git status # 位於分支 master # 您的分支領先 'origin/master' 共 15 個提交。 # (使用 "git push" 來發布您的本地提交) # # 還沒有暫存以備提交的變動: # (使用 "git add <file>..." 更新要提交的內容) # (使用 "git checkout -- <file>..." 丟棄工做區的改動) # # 修改: dele # 修改還沒有加入提交(使用 "git add" 和/或 "git commit -a")
並非你不想提交,而是工做只進行到一半,還無法提交,預計完成還需1天時間。可是,必須在兩個小時內修復該bug,怎麼辦?
幸虧,Git還提供了一個stash
功能,能夠把當前工做現場「儲藏」起來,等之後恢復現場後繼續工做,再經過git status 查看發現工做區已經乾淨。
[llg@localhost llg-test-git]$ git stash Saved working directory and index state WIP on master: 7dec792 ss HEAD 如今位於 7dec792 ss [llg@localhost llg-test-git]$ git status # 位於分支 master # 您的分支領先 'origin/master' 共 15 個提交。 # (使用 "git push" 來發布您的本地提交) # 無文件要提交,乾淨的工做區
master
分支上修復,就從
master
建立臨時分支
[llg@localhost llg-test-git]$ git checkout -b issue-101 切換到一個新分支 'issue-101'
如今修復bug,咱們經過修改文件模擬這一個過程
[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(+)
修復完成後,切換到master
分支,並完成合並,最後刪除issue-101
分支
[llg@localhost llg-test-git]$ git checkout master 切換到分支 'master' 您的分支領先 'origin/master' 共 15 個提交。 (使用 "git push" 來發布您的本地提交) [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(+)
太棒了,原計劃兩個小時的bug修復只花了5分鐘!
如今,是時候接着回到dev
分支幹活了,切換到dev分支而後用git stash list
命令看看
[llg@localhost llg-test-git]$ git stash list stash@{0}: WIP on master: 7dec792 ss
工做現場還在,Git把stash內容存在某個地方了,可是須要恢復一下,有兩個辦法:
一是用git stash apply
恢復,可是恢復後,stash內容並不刪除,你須要用git stash drop
來刪除;
另外一種方式是用git stash pop
,恢復的同時把stash內容也刪了:
[llg@localhost llg-test-git]$ git stash pop # 位於分支 master # 您的分支領先 'origin/master' 共 17 個提交。 # (使用 "git push" 來發布您的本地提交) # # 還沒有暫存以備提交的變動: # (使用 "git add <file>..." 更新要提交的內容) # (使用 "git checkout -- <file>..." 丟棄工做區的改動) # # 修改: dele # 修改還沒有加入提交(使用 "git add" 和/或 "git commit -a") 丟棄了 refs/stash@{0} (fa2bbbe411ba20c94501e912ec120fa944c06b92)
git stash list
查看,就看不到任何stash內容了
[llg@localhost llg-test-git]$ git stash list
[llg@localhost llg-test-git]$
git stash
一下,而後去修復bug,修復後,再git stash pop
,回到工做現場
當須要開發一個新功能的時候,最好建立一個新的分支進行代碼編輯,可是由於一些狀況不須要這個分支了,可是這個分支歷來沒有合併過,因此要使用 git branch -D 的方式強制刪除
[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' 您的分支領先 'origin/master' 共 17 個提交。 (使用 "git push" 來發布您的本地提交) [llg@localhost llg-test-git]$ git branch -D feature-vulcan 已刪除分支 feature-vulcan(曾爲 4cd8736)。
在上一節咱們看到了,多人在同一個分支上協做時,很容易出現衝突。即便沒有衝突,後push的童鞋不得不先pull,在本地合併,而後才能push成功。
每次合併再push後,分支變成了這樣
總之看上去很亂,有強迫症的童鞋會問:爲何Git的提交歷史不能是一條幹淨的直線?
實際上是能夠作到的!
Git有一種稱爲rebase的操做,有人把它翻譯成「變基」。
先不要隨意展開想象。咱們仍是從實際問題出發,看看怎麼把分叉的提交變成直線。
在和遠程分支同步後,咱們對hello.py
這個文件作了兩次提交。用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)
標識出當前分支的HEAD和遠程origin的位置分別是582d922 add author
和d1be385 init hello
,本地分支比遠程分支快兩個提交。
如今咱們嘗試推送本地分支:
$ 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.
很不幸,失敗了,這說明有人先於咱們推送了遠程分支。按照經驗,先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
看看狀態:
$ 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
加上剛纔合併的提交,如今咱們本地分支比遠程分支超前3個提交。
用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 ...
對強迫症童鞋來講,如今事情有點不對頭,提交歷史分叉了。若是如今把本地分支push到遠程,有沒有問題?
有!
什麼問題?
很差看!
有沒有解決方法?
有!
這個時候,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
本來分叉的提交如今變成一條直線了!這種神奇的操做是怎麼實現的?其實原理很是簡單。咱們注意觀察,發現Git把咱們本地的提交「挪動」了位置,放到了f005ed4 (origin/master) set exit=1
以後,這樣,整個提交歷史就成了一條直線。rebase操做先後,最終的提交內容是一致的,可是,咱們本地的commit修改內容已經變化了,它們的修改再也不基於d1be385 init hello
,而是基於f005ed4 (origin/master) set exit=1
,但最後的提交7e61ed4
內容是一致的。
這就是rebase操做的特色:把分叉的提交歷史「整理」成一條直線,看上去更直觀。缺點是本地的分叉提交已經被修改過了。
最後,經過push操做把本地分支推送到遠程:
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
遠程分支的提交歷史也是一條直線。
rebase操做能夠把本地未push的分叉提交歷史整理成直線;
rebase的目的是使得咱們在查看歷史提交的變化時更容易,由於分叉的提交須要三方對比。
發佈一個版本時,咱們一般先在版本庫中打一個標籤(tag),這樣,就惟一肯定了打標籤時刻的版本。未來不管何時,取某個標籤的版本,就是把那個打標籤的時刻的歷史版本取出來。因此,標籤也是版本庫的一個快照。
Git的標籤雖然是版本庫的快照,但其實它就是指向某個commit的指針(跟分支很像對不對?可是分支能夠移動,標籤不能移動),因此,建立和刪除標籤都是瞬間完成的。
Git有commit,爲何還要引入tag?
「請把上週一的那個版本打包發佈,commit號是6a5819e...」
「一串亂七八糟的數字很差找!」
若是換一個辦法:
「請把上週一的那個版本打包發佈,版本號是v1.2」
「好的,按照tag v1.2查找commit就行!」
因此,tag就是一個讓人容易記住的有意義的名字,它跟某個commit綁在一塊兒。
在Git中打標籤很是簡單,首先,切換到須要打標籤的分支上
[llg@localhost llg-test-git]$ git branch dev issue-101 * master [llg@localhost llg-test-git]$ git checkout dev 切換到分支 'dev'
而後,敲命令git tag <name>
就能夠打一個新標籤
[llg@localhost llg-test-git]$ git tag v1.0
默認標籤是打在最新提交的commit上的。有時候,若是忘了打標籤,好比,如今已是週五了,但應該在週一打的標籤沒有打,怎麼辦?
方法是找到歷史提交的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 測試兩個文件提交留一個文件不提交 44449dc 此次測試一次提交三個文件 abde635 git練習測試 [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
[llg@localhost llg-test-git]$ git tag v0.8 v0.9 v1.0
注意,標籤不是按時間順序列出,而是按字母排序的。能夠用git show <tagname>
查看標籤信息
[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 +0800 merge with no-ff
還能夠建立帶有說明的標籤,用-a
指定標籤名,-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 +0800 version 0.8 released commit b68ba371b04d5b7b6305454c160d7ef88178ea2d Author: llg <903857227@qq.com> Date: Sun Sep 16 16:04:19 2018 +0800 add merge diff --git a/dele b/dele index 20c0828..a36d773 100644 --- a/dele +++ b/dele @@ -10,3 +10,4 @@ sad end 1111111111111111111111 +2222222222222222222222
若是標籤打錯了,也能夠刪除
[llg@localhost llg-test-git]$ git tag -d v0.8 已刪除 tag 'v0.8'(曾爲 658e2ab)
由於建立的標籤都只存儲在本地,不會自動推送到遠程。因此,打錯的標籤能夠在本地安全刪除。
若是要推送某個標籤到遠程,使用命令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
或者,一次性推送所有還沒有推送到遠程的本地標籤:
[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
首先在本地刪除標籤
[llg@localhost llg-test-git]$ git tag -d v0.8 已刪除 tag 'v0.9'(曾爲 3a5456c)
而後,從遠程刪除。刪除命令是 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
最後去官網github上查看tag是否被刪除,發現確實被刪除了
咱們一直用GitHub做爲免費的遠程倉庫,若是是我的的開源項目,放到GitHub上是徹底沒有問題的。其實GitHub仍是一個開源協做社區,經過GitHub,既可讓別人參與你的開源項目,也能夠參與別人的開源項目。
在GitHub出現之前,開源項目開源容易,但讓廣大人民羣衆參與進來比較困難,由於要參與,就要提交代碼,而給每一個想提交代碼的羣衆都開一個帳號那是不現實的,所以,羣衆也僅限於報個bug,即便能改掉bug,也只能把diff文件用郵件發過去,很不方便。
可是在GitHub上,利用Git極其強大的克隆和分支功能,廣大人民羣衆真正能夠第一次自由參與各類開源項目了。
如何參與一個開源項目呢?好比人氣極高的bootstrap項目,這是一個很是強大的CSS框架,你能夠訪問它的項目主頁https://github.com/twbs/bootstrap,點「Fork」就在本身的帳號下克隆了一個bootstrap倉庫,而後,從本身的帳號下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 接收對象中: 100% (126027/126027), 123.12 MiB | 4.97 MiB/s, done. 處理 delta 中: 100% (83420/83420), done.
必定要從本身的帳號下clone倉庫,這樣你才能推送修改。若是從bootstrap的做者的倉庫地址git@github.com:twbs/bootstrap.git
克隆,由於沒有權限,你將不能推送修改。
Bootstrap的官方倉庫twbs/bootstrap
、你在GitHub上克隆的倉庫my/bootstrap
,以及你本身克隆到本地電腦的倉庫,他們的關係就像下圖顯示的那樣:
若是你想修復bootstrap的一個bug,或者新增一個功能,馬上就能夠開始幹活,幹完後,往本身的倉庫推送。
若是你但願bootstrap的官方庫能接受你的修改,你就能夠在GitHub上發起一個pull request。固然,對方是否接受你的pull request就不必定了。
使用GitHub時,國內的用戶常常遇到的問題是訪問速度太慢,有時候還會出現沒法鏈接的狀況(緣由你懂的)。
若是咱們但願體驗Git飛通常的速度,能夠使用國內的Git託管服務——碼雲(gitee.com)。
和GitHub相比,碼雲也提供免費的Git倉庫。此外,還集成了代碼質量檢測、項目演示等功能。對於團隊協做開發,碼雲還提供了項目管理、代碼託管、文檔管理的服務,5人如下小團隊免費。
碼雲的免費版本也提供私有庫功能,只是有5人的成員上限。
使用碼雲和使用GitHub相似,咱們在碼雲上註冊帳號並登陸後,須要先上傳本身的SSH公鑰。選擇右上角用戶頭像 -> 菜單「修改資料」,而後選擇「SSH公鑰」,填寫一個便於識別的標題,而後把用戶主目錄下的.ssh/id_rsa.pub
文件的內容粘貼進去:
若是咱們已經有了一個本地的git倉庫(例如,一個名爲learngit的本地庫),如何把它關聯到碼雲的遠程庫上呢?
首先,咱們在碼雲上建立一個新的項目,選擇右上角用戶頭像 -> 菜單「控制面板」,而後點擊「建立項目」:
因爲剛纔已經關聯了github,若是用同一個tag orgin的話將會關聯失敗,因此我用了orgins 關聯碼雲
[llg@localhost llg-test-git]$ git remote add origin git@gitee.com:eill/llg-test-git.git fatal: 遠程 origin 已經存在。 [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 設置爲跟蹤來自 origin 的遠程分支 master。 Everything up-to-date
這樣一來,咱們的本地庫就能夠同時與多個遠程庫互相同步:
[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功能,可讓其餘小夥伴參與到開源項目中來。你能夠經過Fork個人倉庫:https://gitee.com/liaoxuefeng/learngit,建立一個your-gitee-id.txt
的文本文件, 寫點本身學習Git的心得,而後推送一個pull request給我,這個倉庫會在碼雲和GitHub作雙向同步。
在安裝Git一節中,咱們已經配置了user.name
和user.email
,實際上,Git還有不少可配置項。
好比,讓Git顯示顏色,會讓命令輸出看起來更醒目
[llg@localhost llg-test-git]$ git config --global color.ui true
有些時候,你必須把某些文件放到Git工做目錄中,但又不能提交它們,好比保存了數據庫密碼的配置文件啦,等等,每次git status
都會顯示Untracked files ...
,有強迫症的童鞋內心確定不爽。
好在Git考慮到了你們的感覺,這個問題解決起來也很簡單,在Git工做區的根目錄下建立一個特殊的.gitignore
文件,而後把要忽略的文件名填進去,Git就會自動忽略這些文件。
不須要從頭寫.gitignore
文件,GitHub已經爲咱們準備了各類配置文件,只須要組合一下就能夠使用了。全部配置文件能夠直接在線瀏覽:https://github.com/github/gitignore
忽略文件的原則是:
.class
文件;舉個例子:
假設你在Windows下進行Python開發,Windows會自動在有圖片的目錄下生成隱藏的縮略圖文件,若是有自定義目錄,目錄下就會有Desktop.ini
文件,所以你須要忽略Windows自動生成的垃圾文件:
# Windows:
Thumbs.db
ehthumbs.db
Desktop.ini
而後,繼續忽略Python編譯產生的.pyc
、.pyo
、dist
等文件或目錄:
# Python: *.py[cod] *.so *.egg *.egg-info dist build
加上你本身定義的文件,最終獲得一個完整的.gitignore
文件,內容以下:
# 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,就完成了!固然檢驗.gitignore
的標準是git status
命令是否是說working directory clean
。
使用Windows的童鞋注意了,若是你在資源管理器裏新建一個.gitignore
文件,它會很是弱智地提示你必須輸入文件名,可是在文本編輯器裏「保存」或者「另存爲」就能夠把文件保存爲.gitignore
了。
有些時候,你想添加一個文件到Git,但發現添加不了,緣由是這個文件被.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.
若是你確實想添加該文件,能夠用-f
強制添加到Git:
$ git add -f App.class
或者你發現,多是.gitignore
寫得有問題,須要找出來到底哪一個規則寫錯了,能夠用git check-ignore
命令檢查:
$ git check-ignore -v App.class .gitignore:3:*.class App.class
Git會告訴咱們,.gitignore
的第3行規則忽略了該文件,因而咱們就能夠知道應該修訂哪一個規則。
忽略某些文件時,須要編寫.gitignore
;
.gitignore
文件自己要放到版本庫裏,而且能夠對.gitignore
作版本管理!
有沒有常常敲錯命令?好比git status
?status
這個單詞真心很差記。
若是敲git st
就表示git status
那就簡單多了,固然這種偷懶的辦法咱們是極力同意的。
咱們只須要敲一行命令,告訴Git,之後st
就表示status
(這個功能在linux上也有)
[llg@localhost llg-test-git]$ git config --global alias.st status [llg@localhost llg-test-git]$ git st # 位於分支 dev # 還沒有暫存以備提交的變動: # (使用 "git add <file>..." 更新要提交的內容) # (使用 "git checkout -- <file>..." 丟棄工做區的改動) # # 修改: dele # 修改還沒有加入提交(使用 "git add" 和/或 "git commit -a")
配置Git的時候,加上--global
是針對當前用戶起做用的,若是不加,那隻針對當前的倉庫起做用。
配置文件放哪了?每一個倉庫的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]
後面,要刪除別名,直接把對應的行刪掉便可。
而當前用戶的Git配置文件放在用戶主目錄下的一個隱藏文件.gitconfig
中:
$ cat .gitconfig [alias] co = checkout ci = commit br = branch st = status [user] name = Your Name email = your@email.com
給Git配置好別名,就能夠輸入命令時偷個懶。咱們鼓勵偷懶。
在遠程倉庫一節中,咱們講了遠程倉庫實際上和本地倉庫沒啥不一樣,純粹爲了7x24小時開機並交換你們的修改。
GitHub就是一個免費託管開源代碼的遠程倉庫。可是對於某些視源代碼如生命的商業公司來講,既不想公開源代碼,又捨不得給GitHub交保護費,那就只能本身搭建一臺Git服務器做爲私有倉庫使用。
搭建Git服務器須要準備一臺運行Linux的機器,強烈推薦用Ubuntu或Debian,這樣,經過幾條簡單的apt
命令就能夠完成安裝。
假設你已經有sudo
權限的用戶帳號,下面,正式開始安裝。(在這裏我使用的是Centos)
第一步,安裝git
[llg@localhost llg-test-git]$ sudo yum install git
第二步,建立一個git
用戶,用來運行git
服務
[llg@localhost llg-test-git]$ sudo adduser git
第三步,建立證書登陸:
收集全部須要登陸的用戶的公鑰,就是他們本身的id_rsa.pub
文件,把全部公鑰導入到/home/git/.ssh/authorized_keys
文件裏,一行一個。
第四步,初始化Git倉庫:
先選定一個目錄做爲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就會建立一個裸倉庫,裸倉庫沒有工做區,由於服務器上的Git倉庫純粹是爲了共享,因此不讓用戶直接登陸到服務器上去改工做區,而且服務器上的Git倉庫一般都以.git
結尾。而後,把owner改成git(用戶權限)
[llg@localhost llg-test-git]$ sudo chown -R git:git sample.git
第五步,禁用shell登陸:
出於安全考慮,第二步建立的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,由於咱們爲git
用戶指定的git-shell
每次一登陸就自動退出。
第六步,克隆遠程倉庫:
如今,能夠經過git clone
命令克隆遠程倉庫了,在各自的電腦上運行:
[llg@localhost llg-test-git]$ git clone git@127.0.0.1:/llg-test-git/sample.git/
剩下的推送就簡單了。
若是團隊很小,把每一個人的公鑰收集起來放到服務器的/home/git/.ssh/authorized_keys
文件裏就是可行的。若是團隊有幾百號人,就無法這麼玩了,這時,能夠用Gitosis來管理公鑰。
這裏咱們不介紹怎麼玩Gitosis了,幾百號人的團隊基本都在500強了,相信找個高水平的Linux管理員問題不大。
有不少不但視源代碼如生命,並且視員工爲竊賊的公司,會在版本控制系統裏設置一套完善的權限控制,每一個人是否有讀寫權限會精確到每一個分支甚至每一個目錄下。由於Git是爲Linux源代碼託管而開發的,因此Git也繼承了開源社區的精神,不支持權限控制。不過,由於Git支持鉤子(hook),因此,能夠在服務器端編寫一系列腳原本控制提交等操做,達到權限控制的目的。Gitolite就是這個工具。
這裏咱們也不介紹Gitolite了,不要把有限的生命浪費到權限鬥爭中。
通過兩天的學習,站在巨人的肩膀上,我把命令都執行了一遍,大概有了個印象。
Git雖然極其強大,命令繁多,但經常使用的就那麼十來個,掌握好這十幾個經常使用命令,你已經能夠駕輕就熟地使用Git了。
友情附贈國外網友製做的Git Cheat Sheet,建議打印出來備用:
Git的官方網站:http://git-scm.com
做者:廖雪峯
連接:https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000來源:廖雪峯的官方網站