Git教程
一、Git簡介
1.1. Git的誕生
1.2.集中式的vs分布式
二、安裝Git
三轧苫、創(chuàng)建版本庫
四、時光穿梭機
4.1版本回退
4.2工作區(qū)和暫存區(qū)
4.3管理修改
4.4撤銷修改
4.5刪除文件
五疫蔓、遠(yuǎn)程倉庫
5.1添加遠(yuǎn)程倉庫
5.2從遠(yuǎn)程庫中克隆
六、分支管理
6.1創(chuàng)建與合并分支
6.2解決沖突
6.3分支管理策略
6.4Bug分支
6.5Feature分支
6.6多人協(xié)作
七身冬、標(biāo)簽管理
7.1創(chuàng)建標(biāo)簽
7.2操作標(biāo)簽
八衅胀、使用GitHub
九、自定義Git
9.1忽略特殊定義符
9.2配置別名
9.3搭建Git服務(wù)器
十酥筝、總結(jié)
1滚躯、Git簡介
Git是什么?
Git是目前世界上最先進(jìn)的分布式版本控制系統(tǒng)(沒有之一)嘿歌。
Git有什么特點掸掏?簡單來說就是:高端大氣上檔次!
1.1 Git的誕生
你也許會想宙帝,為什么Linus不把Linux代碼放到版本控制系統(tǒng)里呢丧凤?不是有CVS、SVN這些免費的版本控制系統(tǒng)嗎步脓?因為Linus堅定地反對CVS和SVN愿待,這些集中式的版本控制系統(tǒng)不但速度慢,而且必須聯(lián)網(wǎng)才能使用靴患。有一些商用的版本控制系統(tǒng)仍侥,雖然比CVS、SVN好用鸳君,但那是付費的农渊,和Linux的開源精神不符。
1.2 分布式 VS 集中式
集中式
SVN - CVS - ClearCase(IBM 收費) - VSS(微軟)分布式
git - BitKeeper(促使git誕生) - Mercurial - Bazaar
目前集中式常用的SVN, 分布式常用git
集中式
集中式版本控制系統(tǒng), 版本庫需要集中的放到一臺服務(wù)器上, 在工作時, 用自己的電腦從中央服務(wù)器上將目前最新內(nèi)容下載到本地, 實現(xiàn)效果后再講內(nèi)容推送到中央服務(wù)器.
- 缺點
1.中央服務(wù)器崩潰, 所有人都干不了活
2.網(wǎng)絡(luò)帶寬會影響文件下載和上傳速度
分布式
分布式版本控制系統(tǒng)壓根沒有”中央服務(wù)器”這個東西, 每個人的電腦都是一個完整的版本庫, 這樣工作的時候并不需要網(wǎng)絡(luò). 多人協(xié)作, 在合并作品的時候, 只需將自己的內(nèi)容傳給對方, 對方既可以看到你修改的內(nèi)容. 同時, git提供強大的分支, 可以將項目拆分, 使項目更加安全.
注意
git雖然沒有”中央服務(wù)器”, 但常常找出一臺電腦來充當(dāng)”中央服務(wù)器”, 不過其作用是為了方便交換, 因為, 協(xié)作的兩個人不在同一個局域網(wǎng), 或者其中一人電腦未開啟等特殊情況.
- 優(yōu)點
安全性極高, 即便自己的電腦壞了, 只需要從別人的電腦上重新clone一個版本庫即可
強大的分支, 可以將一個大項目拆分成若干小功能來實現(xiàn), 實現(xiàn)后再合并
安裝git(Linux)
1.在終端輸入 git 查看git信息(如果沒有安裝會有下方的友好提示)
$ git
The program 'git' is currently not installed. You can install it by typing:sudo apt-get install git
2.如果沒有安裝, 在終端輸入sudo apt-get install git
安裝
注意:
老一點的Debian或Ubuntu Linux或颊,要把命令改為sudo apt-get install git-core
砸紊,因為以前有個軟件也叫GIT(GNU Interactive Tools)传于,結(jié)果Git就只能叫g(shù)it-core了。由于Git名氣實在太大批糟,后來就把GNU Interactive Tools
改成gnuit格了,git-core
正式改為git。
3徽鼎、創(chuàng)建版本庫
版本庫又名倉庫盛末,英文名repository,你可以簡單理解成一個目錄否淤,這個目錄里面的所有文件都可以被Git管理起來悄但,每個文件的修改、刪除石抡,Git都能跟蹤檐嚣,以便任何時刻都可以追蹤歷史,或者在將來某個時刻可以“還原”啰扛。
在一個有足夠權(quán)限的地方創(chuàng)建空文件夾
在終端使用命令:
$git init
git initInitialized empty Git repository in /Users/michael/learngit/.git/
這時git參考就建立好了, 而且是一個空倉庫, 此時文件夾下會多一個.git隱藏文件, 它是來跟蹤倉庫變化的, 不要隨意改動這個文件.
將內(nèi)容放到版本庫
1.git add fileName
2.git commit -m "info"
$ git add readme.md
$ git add git_study.md
$ git commit -m "add 2 files."
說明:
git add
告訴 git 我要加入某個文件, git commit
告訴 git 內(nèi)容可以放入版本庫了, git commit
后的 -m ‘xxx’ 參數(shù)的意思是這次提交做了哪些改動, 強烈建議寫上, 因為用不了多久你就會忘了曾經(jīng)做了什么. 因為git commit
一次可以提交多個文件, 所以可以先通過add多個文件, 然后commit
一次提交.
4嚎京、時光機穿梭
在終端使用命令
git status
查看那些文件被改動, 以及那些文件將要被commit提交在終端使用命令
git diff
查看文件被改動了什么
4.1版本回退
如果在修改文件過程中出現(xiàn)了什么錯誤, 需要回退到就版本, 怎么辦呢?
在終端使用命令git log
查看提交歷史
commit f384b35e6c614ac5444efd0167e29fee66c9c37d
Merge: c65e7a0 2a0f55c
Author: caoyuan <2675142924@qq.com>
Date: Wed Sep 21 15:46:03 2016 +0800
merge with no-ff
commit 2a0f55c64f68abb7cb69547063330821a3a0df39
Author: caoyuan <2675142924@qq.com>
Date: Wed Sep 21 15:35:31 2016 +0800
add merge
commit c65e7a0f684587adce36c2f972de7fb4ce53cd69
Merge: 28d8785 71dbe9d
Author: caoyuan <2675142924@qq.com>
Date: Wed Sep 21 14:58:04 2016 +0800
如果覺得內(nèi)容太多, 可以使用命令git log --graph --pretty=oneline --abbrev-commit 查看
yuan@yuan:~/learngit$ git log --pretty=oneline --abbrev-commit
f384b35 merge with no-ff
2a0f55c add merge
c65e7a0 conflict fixed
28d8785 & simple
71dbe9d AND simple
fc62eb2 brach test
4c51d94 remove test.txt
1ee3747 add test.text
5895409 add cao
9a97047 git track changes
440c6b3 understand how stage works
5396aed append GPL
21c867f add 3 file
9c6ce9f add 1 file
說明:
前面的一大串?dāng)?shù)字是commit id, 和SVN不一樣,Git的commit id不是1隐解,2鞍帝,3……遞增的數(shù)字,而是一個SHA1計算出來的一個非常大的數(shù)字煞茫,用十六進(jìn)制表示.
上一個版本就是HEAD帕涌,上上一個版本就是HEAD,當(dāng)然往上100個版本寫100個比較容易數(shù)不過來续徽,所以寫成HEAD~100蚓曼。
yuan@yuan:~/learngit$ git reset --hard HEAD^
HEAD is now at c65e7a0 conflict fixed
注意:
要重返未來,用git reflog查看命令歷史钦扭,以便確定要回到未來的哪個版本纫版。
4.2工作區(qū)和暫存區(qū)
Git和其他版本控制系統(tǒng)如SVN的一個不同之處就是有暫存區(qū)的概念。
- 工作區(qū)
工作區(qū)可以簡單的理解為是git倉庫目錄下內(nèi)容.
- 暫存區(qū)
回顧一下, 在將內(nèi)容提交到倉庫時候, 需要先使用git add
一下, 此時這個add其實是吧內(nèi)容提交到stage
暫存區(qū), 在執(zhí)行commit的使用才會將stage暫存區(qū)中的內(nèi)容提交到工作區(qū).
git add
命令將文件提交到緩存區(qū)
Git和其他版本控制系統(tǒng)如SVN的一個不同之處就是有暫存區(qū)的概念客情。
先來看名詞解釋捎琐。
工作區(qū)(Working Directory)
就是你在電腦里能看到的目錄,比如我的learngit文件夾就是一個工作區(qū):
working-dir
版本庫(Repository)
工作區(qū)有一個隱藏目錄.git裹匙,這個不算工作區(qū)瑞凑,而是Git的版本庫。
Git的版本庫里存了很多東西概页,其中最重要的就是稱為stage(或者叫index)的暫存區(qū)籽御,還有Git為我們自動創(chuàng)建的第一個分支master,以及指向master的一個指針叫HEAD。
git-repo
分支和HEAD的概念我們以后再講技掏。
前面講了我們把文件往Git版本庫里添加的時候铃将,是分兩步執(zhí)行的:**
第一步:是用git add把文件添加進(jìn)去,實際上就是把文件修改添加到暫存區(qū)哑梳;
第二步:是用git commit提交更改劲阎,實際上就是把暫存區(qū)的所有內(nèi)容提交到當(dāng)前分支。
因為我們創(chuàng)建Git版本庫時鸠真,Git自動為我們創(chuàng)建了唯一一個master分支悯仙,所以,現(xiàn)在吠卷,git commit
就是往master分支上提交更改锡垄。
你可以簡單理解為,需要提交的文件修改通通放到暫存區(qū)祭隔,然后货岭,一次性提交暫存區(qū)的所有修改。
俗話說疾渴,實踐出真知∏Ч幔現(xiàn)在,我們再練習(xí)一遍搞坝,先對readme.txt做個修改丈牢,比如加上一行內(nèi)容:
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
然后,在工作區(qū)新增一個LICENSE文本文件(內(nèi)容隨便寫)瞄沙。
先用git status查看一下狀態(tài):
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: readme.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
LICENSE
no changes added to commit (use "git add" and/or "git commit -a")
Git非常清楚地告訴我們,readme.txt被修改了慌核,而LICENSE還從來沒有被添加過距境,所以它的狀態(tài)是Untracked。
現(xiàn)在垮卓,使用兩次命令git add垫桂,把readme.txt和LICENSE都添加后,用git status再查看一下:
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: LICENSE
modified: readme.txt
現(xiàn)在粟按,暫存區(qū)的狀態(tài)就變成這樣了:
git-stage
所以诬滩,git add命令實際上就是把要提交的所有修改放到暫存區(qū)(Stage),然后灭将,執(zhí)行g(shù)it commit就可以一次性把暫存區(qū)的所有修改提交到分支疼鸟。
$ git commit -m "understand how stage works"
[master 27c9860] understand how stage works
2 files changed, 675 insertions(+)
create mode 100644 LICENSE
一旦提交后,如果你又沒有對工作區(qū)做任何修改庙曙,那么工作區(qū)就是“干凈”的:
$ git status
# On branch master
nothing to commit (working directory clean)
現(xiàn)在版本庫變成了這樣空镜,暫存區(qū)就沒有任何內(nèi)容了:
git-stage-after-commit
小結(jié)
暫存區(qū)是Git非常重要的概念,弄明白了暫存區(qū),就弄明白了Git的很多操作到底干了什么吴攒。
沒弄明白暫存區(qū)是怎么回事的童鞋张抄,請向上滾動頁面,再看一次洼怔。
4.3 git撤銷修改
如果在reqdme.txt中多加了一行署惯,在提交前,我們要撤銷修改
刪除添加的行镣隶,返回到上一個歷史版本极谊。
例1:
yuan@yuan:~/learngit$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
執(zhí)行git status
后git會提醒git checkout -- file
git checkout -- file
可以丟棄工作區(qū)的修改
文件在工作區(qū)的修改全部撤銷
修改后還沒被放到暫存區(qū)
撤銷修改就回到和版本庫一模一樣狀態(tài)
修改后已經(jīng)添加到暫存區(qū)
又作了修改,現(xiàn)在矾缓,撤銷修改就回到添加到暫存區(qū)后的狀態(tài)
git commit
git add
git checkout -- file
命令中的 --的作用
沒用-- 就變成切換到另一分支命令
git checkout
命令
在commit之前發(fā)現(xiàn)這個問題怀酷,git status
修改只是添加到了暫存區(qū),還沒有提交:
```
yuan@yuan:~/learngit$ vim readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes.
dddd cao yuan
i love you
```
通過git diff
可以看到里面添加了一個 I love you的內(nèi)容
yuan@yuan:~/learngit$ git diff
diff --git a/readme.txt b/readme.txt
index 5d1ed32..fcb9573 100644
--- a/readme.txt
+++ b/readme.txt
@@ -3,3 +3,4 @@ Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes.
dddd cao yuan
+i love you^M //此行是添加的內(nèi)容嗜闻,可以看到前面有一個+號
2蜕依、我們現(xiàn)在把readme.txt添加到暫存區(qū)
yuan@yuan:~/learngit$ git add readme.txt //把readme.txt添加到暫存區(qū)
yuan@yuan:~/learngit$ git status //查看狀態(tài)
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage) //提示撤銷暫存區(qū)修改
modified: readme.txt //提示修改reqdme.txt
yuan@yuan:~/learngit$ git reset HEAD readme.txt //撤銷暫存區(qū)修改,重新放回工作區(qū)
Unstaged changes after reset:
M readme.txt
查看狀態(tài),當(dāng)前已前暫存區(qū)回到的工作區(qū)
yuan@yuan:~/learngit$ git status //查看狀態(tài)
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a") //
再從工作區(qū)撤銷命令琉雳,看到結(jié)果中沒有i love you字母了
yuan@yuan:~/learngit$ git checkout -- readme.txt //撤銷工作區(qū)修改
yuan@yuan:~/learngit$ cat readme.txt //查看readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes.
cao
3样眠、如果從暫存區(qū)提交到了版本庫,只能用前面講到的版本回退操作
前提是沒有把本地版本庫推送到遠(yuǎn)程翠肘,否則無法撤銷檐束。
總結(jié):
1、修改內(nèi)容有誤時了束倍,但沒有提交到暫存區(qū) 直接使用 git checkout -- file
2被丧、修改某文件內(nèi)容有誤后,提交到暫存區(qū)想撤銷修改分如下2步
第一步: 先讓文件回到工作區(qū) git rest HEAD file
第二步:從工作區(qū)撤銷修改 git checkout -- file
3绪妹、已經(jīng)提交了修改內(nèi)容到版本庫時甥桂,想要撤銷本次提交只能用版本回退,前提沒有推送到遠(yuǎn)程庫
4.4 刪除文件
1邮旷、添加一個test.txt新文件
```
yuan@yuan:~/learngit$ vim test.txt
yuan@yuan:~/learngit$ ls //ls查看到當(dāng)前目錄下多了一個test.txt文件
LICENSE.txt readme.txt test.txt
```
2黄选、把test文件提交到暫存區(qū)
```
yuan@yuan:~/learngit$ git add test.txt //把test添加到暫存區(qū)
yuan@yuan:~/learngit$ git commit -m "add test.text" //把test添加到本地庫
[master 1ee3747] add test.text
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test.txt
```
3、刪除test.txt文件
yuan@yuan:~/learngit$ rm test.txt
刪除后Git知道你刪除了文件婶肩,因此办陷,工作區(qū)和版本庫就不一致了
4、git status查看狀態(tài)
yuan@yuan:~/learngit$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
deleted: test.txt //提示文件被刪除
no changes added to commit (use "git add" and/or "git commit -a")
5律歼、是否確認(rèn)刪除文件
如果刪除文件執(zhí)行g(shù)it rm test.txt 刪掉民镜,并且git commit
yuan@yuan:~/learngit$ git rm test.txt
rm 'test.txt'
yuan@yuan:~/learngit$ git commit -m "remove test.txt"
[master 4c51d94] remove test.txt
1 file changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 test.txt
如果不小心刪錯了用git checkout -- test.txt 就可以找回來
git checkout用版本庫里的版本替換工作區(qū)的版本,無論工作區(qū)是修改還是刪除险毁,都可以“一鍵還原”殃恒。
總結(jié):
1植旧、執(zhí)行g(shù)it rm file 刪除文件
2、只要提交到版本庫不用提心誤刪除离唐,但只能恢復(fù)最版本病附。
5、遠(yuǎn)程倉庫
1亥鬓、時光穿梭可恢復(fù)歷史版本
2完沪、git分布式版本控制系統(tǒng)
同一個Git倉庫,可以分布到不同的機器上嵌戈。
從版本庫機器上克隆原始版本庫覆积,每臺機器都一樣
3、通過一臺電腦玩遠(yuǎn)程庫
一臺電腦上可以克隆多個版本庫熟呛,只要不在同一個目錄下
4宽档、多臺電腦玩遠(yuǎn)程庫
一臺電腦當(dāng)服務(wù)器用,其它的電腦從服務(wù)器中克隆一份到電腦上庵朝,并把各自的提交到服務(wù)器倉庫吗冤,也
可從服務(wù)器拉取最新版本
5、GitHub網(wǎng)站提供版本托管服務(wù)
只要注冊一個GitHub帳號九府,就可免費獲得Git遠(yuǎn)程倉庫,GitHub通過SSH加密傳輸
第一步:創(chuàng)建SSH Key
查看用戶主目錄下是否有.ssh
目錄椎瘟,有再看看有沒有id_rsa
和id_rsa.pub
這兩個文件如果有跳過
沒有就創(chuàng)建SSH Key,執(zhí)行完.ssh目錄下生成 id_rsa和id_rsa.pub兩個密鑰文件,
id_rsa私鑰侄旬,不可泄露肺蔚,id_rsa.pub是公鑰可以告訴別人
ssh-keygen -t rsa -C "2675142924@qq.com" //更換自己的郵件地址
第2步:登陸GitHub,打開“Account settings”儡羔,“SSH Keys”頁面:
然后宣羊,點“Add SSH Key”,填上任意Title汰蜘,在Key文本框里粘貼id_rsa.pub文件的內(nèi)容:
點“Add Key”仇冯,你就應(yīng)該看到已經(jīng)添加的Key:
總結(jié):
1、Github 有公鑰就可以確認(rèn)只有你自己推送
2鉴扫、允許添加多個key,多臺電腦澈缺,只要把每臺要訪問的電腦都加到GitHub中坪创,就可以每臺推送到Github中
3、GitHub免費托管的Git倉庫姐赡,任何人都可以看到莱预,但只有自己可以修改,所以重要信息不能放進(jìn)去
4项滑、如果不想讓別人看到放在GitHub中第一交點錢依沮,把公開的變成私有的,別人就看不見了,再一個就是自己
搭建一個Git服務(wù)器危喉,自己的服務(wù)器別人就看不到
5.1添加遠(yuǎn)程庫
1宋渔、創(chuàng)建本地Git倉庫,GitHub創(chuàng)建一個Git倉庫
2辜限、讓本地倉庫與遠(yuǎn)程倉庫進(jìn)行遠(yuǎn)程同步皇拣,可以作為備份
3、登錄GitHub右上角Create a new repo創(chuàng)建一個新庫
Respository name 填learngit 點擊Create repository
4薄嫡、本地庫與遠(yuǎn)程庫關(guān)聯(lián)
yuan@yuan:~/learngit$ git remote add origin 2675142924@qq.com:michaelliao/learngit.git
5氧急、本地所有內(nèi)容添加到遠(yuǎn)程庫上
yuan@yuan:~/learngit$ git push -u origin master
用git push命令,實際上是把當(dāng)前分支master推送到遠(yuǎn)程
第一次推送master加上-u參數(shù)
本地master分支內(nèi)容添加到遠(yuǎn)程新的master分支內(nèi)容
還會把本地的master分支與遠(yuǎn)程master分支關(guān)聯(lián)起來毫深,方便以后推送
以后推送就可以通過以下命令
git push origin master
第一次使用Git的clone或者push命令連接GitHub時會有警告
The authenticity of host 'github.com (xx.xx.xx.xx)' can't be established.
RSA key fingerprint is xx.xx.xx.xx.xx.
Are you sure you want to continue connecting (yes/no)?
提示確認(rèn)GitHub的Key的指紋信服務(wù)息是否真的來自GitHub服務(wù)器,輸入Yes即可
Warning: Permanently added 'github.com' (RSA) to the list of known hosts.
警告出現(xiàn)一次吩坝,后面的操作就不會有任何警告了
總結(jié):
1、關(guān)聯(lián)遠(yuǎn)程庫使用命令
git remote add origin 2675142924@qq.com:path/repo-name.git
2哑蔫、第一次推送分支所有內(nèi)容:git push -u origin master
3钉寝、以后每次提次只需輸入命令:git push origin master
推送最新修改
6.3分支管理策略
合并分支時,Git會用Fast forwards模式鸳址,這種模式瘩蚪,刪除分支后會丟掉信息
強制禁用Fast forward模式,Git就會在merge時生成一個新的commit,這樣稿黍,從分支歷史上就可以看出分支信息
--no--ff方式的git merge
1疹瘦、創(chuàng)建并切換dev分支:
yuan@yuan:~/learngit$ git checkout -b dev
Switched to a new branch 'dev'
2、修改readme.txt巡球,提交一個新的add commit
yuan@yuan:~/learngit$ git add readme.txt
yuan@yuan:~/learngit$ git commit -m "add merge"
[dev 2a0f55c] add merge
1 file changed, 1 insertion(+), 5 deletions(-)
3言沐、切換回master分支
yuan@yuan:~/learngit$ git branch
* dev
master
yuan@yuan:~/learngit$ git checkout master
Switched to branch 'master'
yuan@yuan:~/learngit$ git branch
dev
* master
4、合并dev分支酣栈,請注意--no-ff參數(shù)险胰,表示禁用Fast forward:
yuan@yuan:~/learngit$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
readme.txt | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
因為本次合并要創(chuàng)建一個新的commit,所以加上-m參數(shù)矿筝,把commit描述寫進(jìn)去起便。
5、查看分支歷史git log:
yuan@yuan:~/learngit$ git log --graph --pretty=oneline --abbrev-commit //查看分支
* f384b35 merge with no-ff
|\
| * 2a0f55c add merge
|/
* c65e7a0 conflict fixed
|\
| * 71dbe9d AND simple
* | 28d8785 & simple
|/
* fc62eb2 brach test
* 4c51d94 remove test.txt
……
可以看到窖维,不使用Fast forward模式榆综,merge后就像這樣:
6、分支策略
管理分支原則
master分支非常穩(wěn)定铸史,僅用來發(fā)布新版本鼻疮,平時不在上面干活
干活一般都在dev分支上,dev分支是不穩(wěn)定的琳轿,到某個時候判沟,比如1.0版本發(fā)布耿芹,再把dev分支合并到master上,在master分支發(fā)布1.0版本
每個人都在dev分支上干活挪哄,每個人都可以有自己的分支吧秕,時不時地往dev分支上合并就可以了
團(tuán)隊合作的支支看起來就像這樣
總結(jié)
1、合并分支時中燥,加上--no-ff參數(shù)就可以用普通模式合并
2寇甸、合并后的歷史有分支,能看出來曾經(jīng)做過合并
3疗涉、fast forward合并就看不出來曾經(jīng)做過合并拿霉。
6.3Bug分支
開發(fā)中Bug修復(fù)辦法
yuan@yuan:~/learngit$ git status
On branch master
nothing to commit, working directory clean
在Git中分支功能比較強大,每個bug都可以通過一個新的臨時分支來修復(fù)咱扣,修復(fù)后绽淘,合并分支,然后將臨時分支刪除闹伪。
并不是你不想提交沪铭,而是工作只進(jìn)行到一半,還沒法提交偏瓤,預(yù)計完成還需1天時間杀怠。但是,必須在兩個小時內(nèi)修復(fù)該bug厅克,怎么辦赔退?
幸好,Git還提供了一個stash功能证舟,可以把當(dāng)前工作現(xiàn)場“儲藏”起來硕旗,等以后恢復(fù)現(xiàn)場后繼續(xù)工作:
yuan@yuan:~/learngit$ git stash
Saved working directory and index state WIP on dev: f384b35 merge with no-ff
HEAD is now at f384b35 merge with no-ff
現(xiàn)在,用git status查看工作區(qū)女责,就是干凈的(除非有沒有被Git管理的文件)漆枚,因此可以放心地創(chuàng)建分支來修復(fù)bug。
首先確定要在哪個分支上修復(fù)bug抵知,假定需要在master分支上修復(fù)墙基,就從master創(chuàng)建臨時分支:
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 6 commits.
$ git checkout -b issue-101
Switched to a new branch 'issue-101'
現(xiàn)在修復(fù)bug,需要把“Git is free software ...”改為“Git is a free software ...”刷喜,然后提交:
yuan@yuan:~/learngit$ git commit -m "fix bug 101"
On branch master
nothing to commit, working directory clean
yuan@yuan:~/learngit$ git commit -m "fix bug 101"
[master 32614a1] fix bug 101
1 file changed, 1 insertion(+), 1 deletion(-)
修復(fù)完成后残制,切換到master分支,并完成合并吱肌,最后刪除issue-101分支:
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 2 commits.
$ git merge --no-ff -m "merged bug fix 101" issue-101
Merge made by the 'recursive' strategy.
readme.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
$ git branch -d issue-101
Deleted branch issue-101 (was cc17032).
太棒了痘拆,原計劃兩個小時的bug修復(fù)只花了5分鐘仰禽!現(xiàn)在氮墨,是時候接著回到dev分支干活了纺蛆!
$ git checkout dev
Switched to branch 'dev'
$ git status
# On branch dev
nothing to commit (working directory clean)
工作現(xiàn)場還在,Git把stash內(nèi)容存在某個地方了规揪,但是需要恢復(fù)一下桥氏,有兩個辦法:
1、是用git stash apply恢復(fù)猛铅,但是恢復(fù)后字支,stash內(nèi)容并不刪除,你需要用git stash drop來刪除奸忽;
2堕伪、另一種方式是用git stash pop,恢復(fù)的同時把stash內(nèi)容也刪了:
yuan@yuan:~/learngit$ git stash pop
On branch issue-101
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (a3c15cae9ce0df80247abf06a3462f3d7a44a1d0)
3栗菜、再用git stash list查看欠雌,就看不到任何stash內(nèi)容了
yuan@yuan:~/learngit$ git stash list
4、你可以多次stash疙筹,恢復(fù)的時候富俄,先用git stash list查看,然后恢復(fù)指定的stash而咆,用命令:
git stash apply stash@{0}
總結(jié)
修復(fù)bug時霍比,我們會通過創(chuàng)建新的bug分支進(jìn)行修復(fù),然后合并暴备,最后刪除悠瞬;
當(dāng)手頭工作沒有完成時,先把工作現(xiàn)場git stash一下馍驯,然后去修復(fù)bug阁危,修復(fù)后,再git stash pop汰瘫,回到工作現(xiàn)場狂打。
6.4Feature分支
軟件開發(fā)中,總要不斷添加進(jìn)來,添加新功能時混弥。
你肯定不希望因為一些實驗性質(zhì)的代碼趴乡,把主分支搞亂了,所以蝗拿,每添加一個新功能晾捏,最好新建一個feature分支,在上面開發(fā)哀托,完成后惦辛,合并,最后仓手,刪除該feature分支胖齐。
yuan@yuan:~/learngit$ git checkout -b feature-vulcan
M readme.txt
Switched to a new branch 'feature-vulcan'
5分鐘后玻淑,開發(fā)完畢:
yuan@yuan:~/learngit$ git add vulcan.py
yuan@yuan:~/learngit$ git commit -m "add feature vulcan"
[feature-vulcan afb809a] add feature vulcan
1 file changed, 1 insertion(+)
create mode 100644 vulcan.py
切回dev
準(zhǔn)備合并:
yuan@yuan:~/learngit$ git checkout dev
feature分支和bug分支合并,然后刪除呀伙。
但是补履,
就在此時,接到上級命令剿另,因經(jīng)費不足箫锤,新功能必須取消!
雖然白干了雨女,但是這個分支還是必須就地銷毀:
yuan@yuan:~/learngit$ git branch -d feature-vulcan
error: The branch 'feature-vulcan' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature-vulcan'.
銷毀失敗谚攒。Git友情提醒,feature-vulcan
分支還沒有被合并氛堕,如果刪除五鲫,將丟失掉修改,如果要強行刪除岔擂,需要使用命令git branch -D feature-vulcan
位喂。
現(xiàn)在我們強行刪除:
yuan@yuan:~/learngit$ git branch -d feature-vulcan
error: The branch 'feature-vulcan' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature-vulcan'.
終于刪除成功!
6.5多人協(xié)作
多人協(xié)作, 往往要用到遠(yuǎn)程倉庫, 那么要如何解決與遠(yuǎn)程倉庫之間的同步以及和伙伴代碼合并的問題呢?
和遠(yuǎn)程倉庫同步
當(dāng)你從遠(yuǎn)程倉庫克隆時乱灵,實際上Git自動把本地的master分支和遠(yuǎn)程的master分支對應(yīng)起來了塑崖,并且,遠(yuǎn)程倉庫的默認(rèn)名稱是origin痛倚。
可是使用git remote
查看遠(yuǎn)程倉庫的信息
$ git remote
origin
或者规婆,使用git remote -v查看詳細(xì)的信息
$ git remote -v
origin git@github.com:michaelliao/learngit.git (fetch)
origin git@github.com:michaelliao/learngit.git (push)
上面顯示了可以抓取和推送的origin的地址。如果沒有推送權(quán)限蝉稳,就看不到push的地址抒蚜。
推送分支
推送分支,就是把該分支上的所有本地提交推送到遠(yuǎn)程庫耘戚。推送時嗡髓,要指定本地分支,這樣收津,Git就會把該分支推送到遠(yuǎn)程庫對應(yīng)的遠(yuǎn)程分支上, 比如下面這句就是吧本地的master分支推送到遠(yuǎn)程的master分支上:
$ git push origin master
但是并不是所有分支都需要推送, 像一些大家都需要用到的諸如: master(主分支), dev(開發(fā)分支)等這些需要推送, 像一些只是自己完成任務(wù)的獨立分支, 類似:bug(修改bug的分支)就不用推送, 除非你的老板想知道你都修改了哪些bug.
抓取分支
多人協(xié)作時饿这,大家都會往master和dev分支上推送各自的修改。
當(dāng)你的協(xié)作伙伴從遠(yuǎn)程clone時, 他只能看到master分支, 如果想看到dev等其他分支, 撞秋,就必須創(chuàng)建遠(yuǎn)程origin的dev分支到本地长捧,可以使用這個命令創(chuàng)建本地dev分支:
$ git checkout -b dev origin/dev
此后, 你的伙伴就可以在分支上做修改了, 并且會提交修改, 如果他提交后(此時有個問題: 你手里的版本已經(jīng)不是最新版本了), 你同樣做好了修改需要提交, 這時當(dāng)你pull時, 你會發(fā)現(xiàn)報錯, 因為你和你的伙伴可能修改了同樣的文件, 這就和前面分支合并一樣, 出現(xiàn)了沖突. 解決辦法也很簡單,Git已經(jīng)提示我們吻贿,就是先用git pull把最新的提交從origin/dev抓下來串结,然后,在本地合并,解決沖突肌割,再推送(這時可能會git pull失敗,原因是沒有指定本地dev分支與遠(yuǎn)程origin/dev分支的鏈接赵抢,根據(jù)提示,設(shè)置dev和origin/dev的鏈接).
創(chuàng)建分支鏈接
$ git branch --set-upstream dev origin/dev
然后pull到本地
$ git pull
這時, 在本地對伙伴修改的內(nèi)容和自己修改的內(nèi)容進(jìn)行合并, 會有合并沖突, 需要手動解決, 解決后在推送.
注意:
多人協(xié)作的工作模式通常是這樣:
1声功、可以試圖用git push origin branch-name推送自己的修改;
2宠叼、如果推送失敗先巴,則因為遠(yuǎn)程分支比你的本地更新,需要先用git pull試圖合并冒冬;
3伸蚯、如果合并有沖突,則解決沖突简烤,并在本地提交剂邮;
4、沒有沖突或者解決掉沖突后横侦,再用git push origin branch-name推送就能成功挥萌!
5、如果git pull提示“no tracking information”枉侧,則說明本地分支和遠(yuǎn)程分支的鏈接關(guān)系沒有創(chuàng)建引瀑,用命令git branch –set-upstream branch-name origin/branch-name。
說明:
- 查看遠(yuǎn)程庫信息榨馁,使用git remote -v憨栽;
- 本地新建的分支如果不推送到遠(yuǎn)程,對其他人就是不可見的翼虫;
- 從本地推送分支屑柔,使用git push origin branch-name,如果推送失敗珍剑,先用git pull抓取遠(yuǎn)程的新提交掸宛;
- 在本地創(chuàng)建和遠(yuǎn)程分支對應(yīng)的分支,使用git checkout -b branch-name origin/branch-name招拙,本地和遠(yuǎn)程分支的名稱最好一致旁涤;
- 建立本地分支和遠(yuǎn)程分支的關(guān)聯(lián),使用git branch –set-upstream branch-name origin/branch-name迫像;
- 從遠(yuǎn)程抓取分支劈愚,使用git pull,如果有沖突闻妓,要先處理沖突菌羽。
7、標(biāo)簽管理
標(biāo)簽(tag), 一個簡單的理解就是它記錄了一次commit id, tag一般建立在主分支上, 方便用于版本發(fā)布. 標(biāo)簽和分支類似, 一個指針指向某次提交, 只不過分支可以繼續(xù)先前移動, 而標(biāo)簽不可移動.
7.1創(chuàng)建標(biāo)簽
在創(chuàng)建標(biāo)簽前需要先切換到需要打標(biāo)簽的分支上, 然后使用命令 git tag v1.0 來創(chuàng)建標(biāo)簽. 默認(rèn)標(biāo)簽是打在HEAD指向的地方(即最新提交), 如果想把標(biāo)簽創(chuàng)建在先前的提交上, 需要先知道commit id(用命令git log –pretty oneline –abbrev-commit), 然后用命令 git tag v0.9 6224937 在對應(yīng)的提交上打上標(biāo)簽, 可以使用 git tag 查看所有標(biāo)簽, 使用命令 git show v0.9 來查看標(biāo)簽詳細(xì)信息.
還可以創(chuàng)建帶有說明的標(biāo)簽由缆,用-a指定標(biāo)簽名注祖,-m指定說明文字:
$ git tag -a v0.1 -m "version 0.1 released" 3628164
還可以通過-s用私鑰簽名一個標(biāo)簽:
$ git tag -s v0.2 -m "signed version 0.2 released" fec145a
注意:
簽名采用PGP簽名猾蒂,因此,必須首先安裝gpg(GnuPG)是晨,如果沒有找到gpg肚菠,或者沒有g(shù)pg密鑰對,就會報錯
7.2操作標(biāo)簽
如果標(biāo)簽打錯了罩缴,也可以刪除:
$ git tag -d v0.1
如果要推送某個標(biāo)簽到遠(yuǎn)程蚊逢,使用命令git push origin
$ git push origin v1.0
或者,一次性推送全部尚未推送到遠(yuǎn)程的本地標(biāo)簽:
$ git push origin --tags
如果標(biāo)簽已經(jīng)推送到遠(yuǎn)程箫章,要刪除遠(yuǎn)程標(biāo)簽就麻煩一點烙荷,先從本地刪除:
$ git tag -d v0.9
然后,從遠(yuǎn)程刪除檬寂。刪除命令也是push终抽,但是格式如下:
$ git push origin :refs/tags/v0.9
8、使用GitHub
- 在GitHub上桶至,可以任意Fork開源倉庫昼伴;
- 自己擁有Fork后的倉庫的讀寫權(quán)限;
- 可以推送pull request給官方倉庫來貢獻(xiàn)代碼镣屹。
9亩码、自定義Git
- 讓Git顯示顏色,會讓命令輸出看起來更醒目:
$ git config --global color.ui true
8.1忽略特殊文件
在工作目錄下創(chuàng)建.gitignore文件, 在這個文件中填寫需要忽略的文件內(nèi)容, 然后git add進(jìn)去. 此后這個.gitignore就開始起作用了.
忽略文件的原則是:
忽略操作系統(tǒng)自動生成的文件野瘦,比如縮略圖等描沟;
忽略編譯生成的中間文件、可執(zhí)行文件等鞭光,也就是如果一個文件是通過另一個文件自動生成的吏廉,那自動生成的文件就沒必要放進(jìn)版本庫,比如Java編譯產(chǎn)生的.class文件惰许;
忽略你自己的帶有敏感信息的配置文件席覆,比如存放口令的配置文件。
如果有些時候汹买,你想添加一個文件到Git佩伤,但發(fā)現(xiàn)添加不了,原因是這個文件被.gitignore忽略了.
如果你確實想添加該文件晦毙,可以用-f強制添加到Git:
$ git add -f App.class
8.2配置別名
通過以下命令將status 縮寫成st
$ git config --global alias.st status
8.3搭建Git服務(wù)器
搭建Git服務(wù)器需要準(zhǔn)備一臺運行Linux的機器生巡,強烈推薦用Ubuntu或Debian,這樣见妒,通過幾條簡單的apt命令就可以完成安裝孤荣。
假設(shè)你已經(jīng)有sudo權(quán)限的用戶賬號,下面,正式開始安裝。
1、安裝git
yuan@yuan:~$ sudo apt-get install git
2瓜喇、創(chuàng)建一個git用戶,用來運行g(shù)it服務(wù)
$ sudo adduser git
3牲尺、創(chuàng)建證書登錄
收集所有需要登錄的用戶的公鑰,就是他們自己的id_rsa.pub文件幌蚊,把所有公鑰導(dǎo)入到/home/git/.ssh/authorized_keys文件里谤碳,一行一個。
4霹肝、初始化Git倉庫:
先選定一個目錄作為Git倉庫,假定是/srv/sample.git塑煎,在/srv目錄下輸入命令:
$ sudo git init --bare sample.git
Git就會創(chuàng)建一個裸倉庫沫换,裸倉庫沒有工作區(qū),因為服務(wù)器上的Git倉庫純粹是為了共享最铁,所以不讓用戶直接登錄到服務(wù)器上去改工作區(qū)讯赏,并且服務(wù)器上的Git倉庫通常都以.git結(jié)尾。然后冷尉,把owner改為git:
$ sudo chown -R git:git sample.git
5漱挎、禁用shell登錄:
出于安全考慮,第二步創(chuàng)建的git用戶不允許登錄shell雀哨,這可以通過編輯/etc/passwd文件完成磕谅。找到類似下面的一行:
git:x:1001:1001:,,,:/home/git:/bin/bash
改為:
git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell
這樣,git用戶可以正常通過ssh使用git雾棺,但無法登錄shell膊夹,因為我們?yōu)間it用戶指定的git-shell每次一登錄就自動退出。
6捌浩、克隆遠(yuǎn)程倉庫:
現(xiàn)在放刨,可以通過git clone命令克隆遠(yuǎn)程倉庫了,在各自的電腦上運行:
$ git clone git@server:/srv/sample.git
Cloning into 'sample'...
warning: You appear to have cloned an empty repository.
剩下的推送就簡單了尸饺。
管理公鑰
如果團(tuán)隊很小进统,把每個人的公鑰收集起來放到服務(wù)器的/home/git/.ssh/authorized_keys文件里就是可行的。如果團(tuán)隊有幾百號人浪听,就沒法這么玩了螟碎,這時,可以用Gitosis來管理公鑰迹栓。
這里我們不介紹怎么玩Gitosis了抚芦,幾百號人的團(tuán)隊基本都在500強了,相信找個高水平的Linux管理員問題不大。
管理權(quán)限
有很多不但視源代碼如生命叉抡,而且視員工為竊賊的公司尔崔,會在版本控制系統(tǒng)里設(shè)置一套完善的權(quán)限控制,每個人是否有讀寫權(quán)限會精確到每個分支甚至每個目錄下褥民。因為Git是為Linux源代碼托管而開發(fā)的季春,所以Git也繼承了開源社區(qū)的精神,不支持權(quán)限控制消返。不過载弄,因為Git支持鉤子(hook),所以撵颊,可以在服務(wù)器端編寫一系列腳本來控制提交等操作宇攻,達(dá)到權(quán)限控制的目的。Gitolite就是這個工具倡勇。