Git分布式版本控制系統
1.linux 安裝git
sudo apt-get install git
創建版本庫(當前文件夾為工作空間)
$ git init
Initialized empty Git repository in d:/localresporty/.git/
版本庫(Repository)
工作區有一個隱藏目錄.git
,這個不算工作區,而是Git的版本庫。具體參考http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/0013745374151782eb658c5a5ca454eaa451661275886c6000
Git的版本庫裏存了很多東西,其中最重要的就是稱為stage(或者叫index)的暫存區,還有Git為我們自動創建的第一個分支master
master
的一個指針叫HEAD
。
在當前文件夾下創建文件
$ touch a.txt
第一步,用命令git add
告訴Git,把文件修改添加到暫存區
$ git add a.txt
第二步,用命令git commit
告訴Git,把暫存區的所有內容提交到當前分支:Git自動為我們創建了唯一一個master
分支
$ git commit -m "zhu shi 1"
第三步
$ git push origin brandon.ma
完成
二:版本回退
1 . 查看當前倉庫當前的狀態
$ git status
2. 查看文件作了什麽修改(且沒有add到倉庫)
$ git diff a.txtdiff --git a/a.txt b/a.txt index 9ac30bc..8c9534b 100644 --- a/a.txt +++ b/a.txt @@ -1 +1 @@ -this is two . +this is tw .^M
3.顯示從最近到最遠的提交日誌
$ git log commit 04853c688c41d72e2efcb34f59b163bdaae6b17c Author: Brandon Ma <[email protected]> Date: Sat Jul 15 15:37:46 2017 +0800 zhu shi 3 commit 05b8bcec10435f2d688c536ffc10a74df7cd25c7 Author: Brandon Ma<[email protected]> Date: Sat Jul 15 15:33:54 2017 +0800 zhu shi 2 commit 4080700e24a3714edba71deb34072d754a48245f Author: Brandon Ma <[email protected]> Date: Sat Jul 15 15:28:23 2017 +0800 zhu shi 1
$ git log --pretty=oneline 只顯示 commit id 04853c688c41d72e2efcb34f59b163bdaae6b17c zhu shi 3 05b8bcec10435f2d688c536ffc10a74df7cd25c7 zhu shi 2 4080700e24a3714edba71deb34072d754a48245f zhu shi 1
在Git中,用HEAD
表示當前版本,也就是最新的提交3628164...882e1e0
(註意我的提交ID和你的肯定不一樣),上一個版本就是HEAD^
,上上一個版本就是HEAD^^
,當然往上100個版本寫100個^
比較容易數不過來,所以寫成HEAD~100
。回到上一個版本
,也可寫commit id
$ git reset --hard HEAD^ HEAD is now at 05b8bce zhu shi 2
$ cat a.txt 文件以回到上個版本 this is two .
後悔了若要回到新的版本
$ git reflog 查找所有的記錄 05b8bce HEAD@{0}: reset: moving to HEAD^ 04853c6 HEAD@{1}: commit: zhu shi 3 05b8bce HEAD@{2}: commit: zhu shi 2 4080700 HEAD@{3}: commit (initial): zhu shi 1
$ git reset --hard 4080700 回到新的版本 HEAD is now at 4080700 zhu shi 1
丟棄工作區的修改
$ git checkout -- a.txt
命令git checkout -- readme.txt
意思就是,把readme.txt
文件在工作區的修改全部撤銷,
場景1:當你改亂了工作區某個文件的內容,想直接丟棄工作區的修改時,用命令git checkout -- file
。
場景2:當你不但改亂了工作區某個文件的內容,還添加到了暫存區時,想丟棄修改,分兩步,第一步用命令git reset HEAD file
,就回到了場景1,第二步按場景1操作。
場景3:已經提交了不合適的修改到版本庫時,想要撤銷本次提交,參考版本回退一節,不過前提是沒有推送到遠程庫。
沒有--
,就變成了“切換到另一個分支”的命令
4. 刪除文件
$ rm a.txt $ git rm a.txt 確實要從版本庫中刪除該文件
$ git commit -m "buxiang yao le " 提交
誤刪的話 ,相當於修改後後悔 , 返回版本庫操作
$ git checkout --file
三 ,遠程倉庫操作
第1步:創建SSH Key。在用戶主目錄下,看看有沒有.ssh目錄,如果有,再看看這個目錄下有沒有id_rsa
和id_rsa.pub
這兩個文件,如果已經有了,可直接跳到下一步。如果沒有,打開Shell(Windows下打開Git Bash),創建SSH Key:
$ ssh-keygen -t rsa -C "[email protected]"
在用戶主目錄裏找到.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
文件的內容:
關聯遠程庫並推送本地庫
$ git remote add origin [email protected]:maxingzheng/mxz.git
推送master分支的所有內容
$ git push -u origin master
從遠程克隆一個本地庫
$ git clone [email protected]:maxingzheng/mxz.git
四.分支管理
當前在dev分支上
假如我們在dev
上的工作完成了,就可以合並
1.創建dev分支
$ git branch brandon 創建分支 [email protected] /D/mxz (master) $ git checkout brandon 切換分支 Switched to branch ‘brandon‘ [email protected] /D/mxz (brandon)
git checkout
命令加上-b
參數表示創建並切換
當在dev分支上進行一系列操作後,可以切換到master進行合並
$ git merge dev
合並完後刪除dev分支
$ git branch -d dev
沖突
master
分支和feature1
分支各自都分別有新的提交,變成了這樣:
必須首先解決沖突。解決沖突後,再提交,合並完成。
用git log --graph
命令可以看到分支合並圖。
分支管理策略
閱讀: 473979通常,合並分支時,如果可能,Git會用Fast forward
模式,但這種模式下,刪除分支後,會丟掉分支信息。
如果要強制禁用Fast forward
模式,Git就會在merge時生成一個新的commit,這樣,從分支歷史上就可以看出分支信息。
下面我們實戰一下--no-ff
方式的git merge
:
首先,仍然創建並切換dev
分支:
$ git checkout -b dev
Switched to a new branch ‘dev‘
修改readme.txt文件,並提交一個新的commit:
$ git add readme.txt
$ git commit -m "add merge"
[dev 6224937] add merge
1 file changed, 1 insertion(+)
現在,我們切換回master
:
$ git checkout master
Switched to branch ‘master‘
準備合並dev
分支,請註意--no-ff
參數,表示禁用Fast forward
:
$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the ‘recursive‘ strategy.
readme.txt | 1 +
1 file changed, 1 insertion(+)
因為本次合並要創建一個新的commit,所以加上-m
參數,把commit描述寫進去。
合並後,我們用git log
看看分支歷史:
$ git log --graph --pretty=oneline --abbrev-commit
* 7825a50 merge with no-ff
|| * 6224937 add merge
|/
* 59bc1cb conflict fixed
...
可以看到,不使用Fast forward
模式,merge後就像這樣:
分支策略
在實際開發中,我們應該按照幾個基本原則進行分支管理:
首先,master
分支應該是非常穩定的,也就是僅用來發布新版本,平時不能在上面幹活;
那在哪幹活呢?幹活都在dev
分支上,也就是說,dev
分支是不穩定的,到某個時候,比如1.0版本發布時,再把dev
分支合並到master
上,在master
分支發布1.0版本;
你和你的小夥伴們每個人都在dev
分支上幹活,每個人都有自己的分支,時不時地往dev
分支上合並就可以了。
所以,團隊合作的分支看起來就像這樣:
修復bug時,我們會通過創建新的bug分支進行修復,然後合並,最後刪除;
當手頭工作沒有完成時,先把工作現場git stash
一下,然後去修復bug,修復後,再git stash pop
,回到工作現場。
刪除未合並的分支
開發一個新feature,最好新建一個分支;
如果要丟棄一個沒有被合並過的分支,可以通過git branch -D <name>
強行刪除
多人協作
要查看遠程庫的信息,用git remote
:
$ git remote -v origin [email protected]:maxingzheng/mxz.git (fetch) origin [email protected]:maxingzheng/mxz.git (push)
多人協作
閱讀: 499364當你從遠程倉庫克隆時,實際上Git自動把本地的master
分支和遠程的master
分支對應起來了,並且,遠程倉庫的默認名稱是origin
。
要查看遠程庫的信息,用git remote
:
$ git remote
origin
或者,用git remote -v
顯示更詳細的信息:
$ git remote -v
origin git@github.com:michaelliao/learngit.git (fetch)
origin git@github.com:michaelliao/learngit.git (push)
上面顯示了可以抓取和推送的origin
的地址。如果沒有推送權限,就看不到push的地址。
推送分支
推送分支,就是把該分支上的所有本地提交推送到遠程庫。推送時,要指定本地分支,這樣,Git就會把該分支推送到遠程庫對應的遠程分支上:
$ git push origin 分支名
抓取分支
當你的小夥伴從遠程庫clone時,默認情況下,只能看到本地的master
分支。git branch
命令看看:
$ git branch
* master
要在dev
分支上開發,就必須創建遠程origin
的dev
分支到本地,於是他用這個命令創建本地dev
分支:
$ git checkout -b dev origin/dev
現在,他就可以在dev
上繼續修改,然後,時不時地把dev
分支push
到遠程:
$ git push origin 分支名
-
首先,可以試圖用
git push origin branch-name
推送自己的修改; -
如果推送失敗,則因為遠程分支比你的本地更新,需要先用
git pull
試圖合並; -
如果合並有沖突,則解決沖突,並在本地提交;
-
沒有沖突或者解決掉沖突後,再用
git push origin branch-name
推送就能成功!
如果git pull
提示“no tracking information”,則說明本地分支和遠程分支的鏈接關系沒有創建,用命令git branch --set-upstream branch-name origin/branch-name
-
命令
git tag <name>
用於新建一個標簽,默認為HEAD
,也可以指定一個commit id; -
git tag -a <tagname> -m "blablabla..."
可以指定標簽信息; -
git tag -s <tagname> -m "blablabla..."
可以用PGP簽名標簽; -
命令
git tag
可以查看所有標簽。-
命令
git push origin <tagname>
可以推送一個本地標簽; -
命令
git push origin --tags
可以推送全部未推送過的本地標簽; -
命令
git tag -d <tagname>
可以刪除一個本地標簽; -
命令
git push origin :refs/tags/<tagname>
可以刪除一個遠程標簽。
-
標簽
給當前分支打上標簽 默認標簽是打在最新提交的commit上的
$ git tag v1.0 (commitid)
讓Git顯示顏色,會讓命令輸出看起來更醒目:
$ git config --global color.ui true
-
忽略某些文件時,需要編寫
.gitignore
; -
.gitignore
文件本身要放到版本庫裏,並且可以對.gitignore
做版本管理
搭建Git服務器
第一步,安裝git
:
$ sudo apt-get install git
第二步,創建一個git
用戶,用來運行git
服務:
$ sudo adduser git
第三步,創建證書登錄:
收集所有需要登錄的用戶的公鑰,就是他們自己的id_rsa.pub
文件,把所有公鑰導入到/home/git/.ssh/authorized_keys
文件裏,一行一個。
第四步,初始化Git倉庫:
先選定一個目錄作為Git倉庫,假定是/srv/sample.git
,在/srv
目錄下輸入命令:
$ sudo git init --bare sample.git
Git就會創建一個裸倉庫,裸倉庫沒有工作區,因為服務器上的Git倉庫純粹是為了共享,所以不讓用戶直接登錄到服務器上去改工作區,並且服務器上的Git倉庫通常都以.git
結尾。然後,把owner改為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
命令克隆遠程倉庫了,在各自的電腦上運行:
$ git clone git@server:/srv/sample.git
Cloning into ‘sample‘...
warning: You appear to have cloned an empty repository.
剩下的推送就簡單了。
管理公鑰
如果團隊很小,把每個人的公鑰收集起來放到服務器的/home/git/.ssh/authorized_keys
文件裏就是可行的。如果團隊有幾百號人,就沒法這麽玩了,這時,可以用Gitosis來管理公鑰。
這裏我們不介紹怎麽玩Gitosis了,幾百號人的團隊基本都在500強了,相信找個高水平的Linux管理員問題不大。
管理權限
有很多不但視源代碼如生命,而且視員工為竊賊的公司,會在版本控制系統裏設置一套完善的權限控制,每個人是否有讀寫權限會精確到每個分支甚至每個目錄下。因為Git是為Linux源代碼托管而開發的,所以Git也繼承了開源社區的精神,不支持權限控制。不過,因為Git支持鉤子(hook),所以,可以在服務器端編寫一系列腳本來控制提交等操作,達到權限控制的目的。Gitolite就是這個工具。
這裏我們也不介紹Gitolite了,不要把有限的生命浪費到權限鬥爭中。
參考:廖學鋒 http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000
Git分布式版本控制系統