Git 與Github
1金吗、簡單介紹
很多人都知道,Linus在1991年創(chuàng)建了開源的Linux趣竣,從此摇庙,Linux系統(tǒng)不斷發(fā)展,已經(jīng)成為最大的服務(wù)器系統(tǒng)軟件了遥缕。
Linus雖然創(chuàng)建了Linux卫袒,但Linux的壯大是靠全世界熱心的志愿者參與的,這么多人在世界各地為Linux編寫代碼单匣,那Linux的代碼是如何管理的呢夕凝?
事實是宝穗,在2002年以前,世界各地的志愿者把源代碼文件通過diff的方式發(fā)給Linus码秉,然后由Linus本人通過手工方式合并代碼逮矛!
你也許會想,為什么Linus不把Linux代碼放到版本控制系統(tǒng)里呢泡徙?不是有CVS橱鹏、SVN這些免費的版本控制系統(tǒng)嗎膜蠢?因為Linus堅定地反對CVS和SVN堪藐,這些集中式的版本控制系統(tǒng)不但速度慢,而且必須聯(lián)網(wǎng)才能使用挑围。有一些商用的版本控制系統(tǒng)礁竞,雖然比CVS、SVN好用杉辙,但那是付費的模捂,和Linux的開源精神不符。
不過蜘矢,到了2002年狂男,Linux系統(tǒng)已經(jīng)發(fā)展了十年了,代碼庫之大讓Linus很難繼續(xù)通過手工方式管理了品腹,社區(qū)的弟兄們也對這種方式表達了強烈不滿岖食,于是Linus選擇了一個商業(yè)的版本控制系統(tǒng)BitKeeper,BitKeeper的東家BitMover公司出于人道主義精神舞吭,授權(quán)Linux社區(qū)免費使用這個版本控制系統(tǒng)泡垃。
安定團結(jié)的大好局面在2005年就被打破了,原因是Linux社區(qū)牛人聚集羡鸥,不免沾染了一些梁山好漢的江湖習(xí)氣蔑穴。開發(fā)Samba的Andrew試圖破解BitKeeper的協(xié)議(這么干的其實也不只他一個),被BitMover公司發(fā)現(xiàn)了(監(jiān)控工作做得不錯>逶 )存和,于是BitMover公司怒了,要收回Linux社區(qū)的免費使用權(quán)衷旅。
Linus可以向BitMover公司道個歉捐腿,保證以后嚴(yán)格管教弟兄們,嗯芜茵,這是不可能的叙量。實際情況是這樣的:
Linus花了兩周時間自己用C寫了一個分布式版本控制系統(tǒng),這就是Git九串!一個月之內(nèi)绞佩,Linux系統(tǒng)的源碼已經(jīng)由Git管理了寺鸥!牛是怎么定義的呢?大家可以體會一下品山。
Git迅速成為最流行的分布式版本控制系統(tǒng)胆建,尤其是2008年,GitHub網(wǎng)站上線了肘交,它為開源項目免費提供Git存儲笆载,無數(shù)開源項目開始遷移至GitHub,包括jQuery涯呻,PHP凉驻,Ruby等等。
歷史就是這么偶然复罐,如果不是當(dāng)年BitMover公司威脅Linux社區(qū)涝登,可能現(xiàn)在我們就沒有免費而超級好用的Git了。
2效诅、基本概念
安裝git
yum install git #centos系統(tǒng)默認安裝好的
初始化版本庫
git init #會生成一個.git的隱藏目錄
- 重點理解:工作區(qū)胀滚、暫存區(qū)和master分支
工作區(qū):用于平時的開發(fā),編輯之用乱投,在你創(chuàng)建的倉庫目錄下咽笼,就是工作區(qū)
暫存區(qū):用來暫時存放準(zhǔn)備提交到倉庫的文檔的地方,在.git目錄下
master分區(qū):真正用來存放和發(fā)布已經(jīng)完成代碼的地方
關(guān)系圖
-
最初文件在工作區(qū)
image -
git add readme.txt 后戚炫,文件被添加到暫存區(qū)剑刑,此時工作區(qū)的文件和暫存區(qū)的文件一致。
image -
git commit -m "new file readme.txt" 后嘹悼,在暫存區(qū)的所有文件和目錄都將后被提交(移動)到分支 master叛甫。
image
3、一個文件被提交到版本庫的基本流程
- 初始化一個倉庫
mkdir my_project #建立一個目錄
cd my_project #進入這個目錄
git init #在當(dāng)前目錄初始化一個倉庫
- 提交版本
touch/mkdir… #在工作區(qū)創(chuàng)建/修改文件
git add file #將文件添加到暫存區(qū)
git commit -m "描述" #將暫存區(qū)的內(nèi)容提交到master分支
可以多次添加杨伙,一次提交
- 暫存區(qū)是Git非常重要的概念其监,弄明白了暫存區(qū),就弄明白了Git的很多操作到底干了什么限匣。
4抖苦、更多git操作
時空穿越
git 支持版本的回滾操作,并且米死,你可以在之前任何一個版本和當(dāng)前最新有效提交后的版本之間來回切換锌历。
將代碼提交之后,突然有不要提交的代碼了峦筒,這種情況的話究西,就要用到回滾了
-
git log
命令可以查看提交的版本歷史
git log 常用參數(shù)
某一個人的提交記錄:
git log --author=name
一個壓縮后的每一條提交記錄只占一行的輸出:
git log --pretty=oneline
或者你想通過 ASCII 藝術(shù)的樹形結(jié)構(gòu)來展示所有的分支, 每個分支都標(biāo)示了他的名字和標(biāo)簽:
git log --graph --oneline --decorate --all
看看哪些文件改變了:
git log --name-status
更多的信息,參考:
git log --help
最前面的一串字符,例如
da197f...7955
是commit id(版本號)物喷,是一個SHA1計算出來的一個非常大的數(shù)字卤材,用十六進制表示遮斥。
每提交一個新版本,實際上Git就會把它們自動串成一條時間線
-
開始版本回退
命令用法:
git reset --hard 版本號
版本號的表示形式:
1. 可以是十六進制的形式
2. 也可以是 Git 內(nèi)部變量的形式扇丛。 上一個版本就是HEAD^
上上一個版本就是HEAD^^
100 個版本寫成 HEAD~100
-
回到未來
git reflog
命令會記錄每一次導(dǎo)致版本變化的命令以及涉及到的版本號
bash-3.2$ git reflog
a34d237 (HEAD -> master) HEAD@{0}: reset: moving to HEAD^
da197f4 HEAD@{1}: commit: add GLP for readme.txt
a34d237 (HEAD -> master) HEAD@{2}: commit: add distributed
63e4ecd HEAD@{3}: commit (initial): crete a readme file
(END)
利用命令進行版本切換
bash-3.2$ git reset --hard da197f4
-
深入理解 add 和 commit
再次強調(diào)一下术吗,commit 提交的是暫存區(qū)的所有文件
,而不是工作區(qū)的被修改的文件帆精;每次修改较屿,如果不add到暫存區(qū),那就不會加入到commit中卓练。
-
改變未來(撤銷修改)
你在工作區(qū)隘蝎,對 readme.txt 文件添加了一行新的內(nèi)容 : "這一行內(nèi)容我不能添加",當(dāng)你想要撤銷掉這行內(nèi)容時有兩種方法:
1昆庇、一種是你記得末贾,在這之前你記得你的所有修改。這里我是記得的整吆,因為我只添加了一行內(nèi)容而已,這樣的情況下辉川,你重新編輯這個文件表蝙,刪除你不要的這一行即可。
2乓旗、另一種是府蛇,修改的太多了,一片混亂屿愚,使你無法繼續(xù)進行下去汇跨。你只想會到?jīng)]有修改之前,就是恢復(fù)到最近一次提交到 master 之后的狀態(tài)妆距。那就需要用git checkout -- readme.txt
命令
git checkout -- readme.txt
意思就是穷遂,readme.txt
文件在被添加到暫存區(qū)之前,對在工作區(qū)對此文件的修改全部撤銷
(2)這里有兩種情況:
1娱据、一種是蚪黑,在工作區(qū)對 readme.txt 進行修改之后,還沒有被放到暫存區(qū)中剩,暫存區(qū)為空忌穿;現(xiàn)在,撤銷修改就回到和版本庫一模一樣的狀態(tài)结啼;
2掠剑、一種是,在工作區(qū)對 readme.txt 進行修改之后郊愧,并且已經(jīng)添加到暫存區(qū)了朴译,接著又在工作區(qū)對文件作了修改沸伏。此時,現(xiàn)在 readme.txt 的狀態(tài)是:在工作區(qū)是一種最新修改后的狀態(tài)
在暫存區(qū)是另一種 add 后的狀態(tài)
在 master 是版本庫最新的狀態(tài)
此時动分,撤銷修改毅糟,工作區(qū)的文件就會和暫存區(qū)文件的狀態(tài)保持一致,master 的文件狀態(tài)不變澜公。
bash-3.2$ git checkout -- study/readme.txt
- 注意:
git checkout -- readme.txt
只能使工作區(qū)和緩存區(qū)內(nèi)容保持一致
想要把緩存區(qū)的內(nèi)容也去掉姆另,只能回退版本再統(tǒng)一工作區(qū)和緩存區(qū)。
這樣工作區(qū)就回到了master的狀態(tài)
撤銷總結(jié)
1坟乾、當(dāng)你改亂了工作區(qū)某個文件的內(nèi)容迹辐,想直接丟棄工作區(qū)的修改時,用命令git checkout -- file甚侣。
2明吩、當(dāng)你不但改亂了工作區(qū)某個文件的內(nèi)容,還添加到了暫存區(qū)時殷费,想丟棄修改印荔,分兩步,第一步用命令git reset HEAD file详羡,就回到了 1仍律,第二步按 1 操作。
3实柠、已經(jīng)提交了不合適的修改到版本庫時水泉,想要撤銷本次提交,參考版本回退一節(jié)窒盐,不過前提是沒有推送到遠程庫草则。
-
自毀前程(刪除)
在Git中,刪除也是一個修改操作,分兩種情況:
1蟹漓、一種是炕横,在工作區(qū)刪除的文件,已經(jīng)被添加到了暫存區(qū)牧牢,但是沒有提交看锉。
當(dāng)你在工作區(qū)刪除一個你認為沒用的文件時,但是這個文件被已經(jīng)添加了暫存區(qū)塔鳍,這樣 Git 會知道你刪除了這個文件伯铣,因為此時,工作區(qū)和版本庫就不一致了轮纫,git status命令會立刻告訴你哪些文件被刪除了
- 此時腔寡,你有兩種選擇:
1.真的要刪除這個文件
可以用git rm
刪除在暫存區(qū)的文件
bash-3.2$ git rm useless.txt
rm 'useless.txt'
bash-3.2$ git status
On branch master
nothing to commit, working tree clean
2.刪錯了,需要把文件恢復(fù)到工作區(qū)
利用git checkout -- file
把工作區(qū)和緩存區(qū)統(tǒng)一
2掌唾、另一種是放前,在工作區(qū)刪除的文件忿磅,添加到了暫存區(qū),并且提交了凭语。
- 此時葱她,你也有兩種選擇:
1.真的要刪除這個文件
rm useless.txt //刪除這個文件
git rm useless.txt //從版本庫刪除這個文件
git commit -m "del file useless.txt" //并且提交
此時,文件就從版本庫中被刪除了似扔,一般情況下它再也會不到你身邊了
2.刪錯了吨些,需要把文件恢復(fù)到工作區(qū)
bash-3.2$ ls useless.txt
ls: useless.txt: No such file or directory
bash-3.2$ git checkout -- useless.txt
bash-3.2$ ls useless.txt
useless.txt
bash-3.2$ git status
On branch master
nothing to commit, working tree clean
總結(jié)
git checkout其實是用<mark style="box-sizing: border-box;">版本庫</mark>里的版本替換工作區(qū)的版本,無論工作區(qū)是修改還是刪除炒辉,都可以“一鍵還原”豪墅。
版本庫: 包括 暫存區(qū) 和 分支
5、分支管理
分支就像科幻電影里的平行宇宙黔寇,當(dāng)你正在電腦前努力學(xué)習(xí)Git的時候偶器,另一個你正在另一個平行宇宙里努力學(xué)習(xí)SVN。
如果兩個平行宇宙互不干擾缝裤,那對現(xiàn)在的你也沒啥影響屏轰。不過,在某個時間點倘是,兩個平行宇宙合并了亭枷,結(jié)果,你既學(xué)會了Git又學(xué)會了SVN搀崭!
Git的分支是與眾不同的,無論創(chuàng)建猾编、切換和刪除分支瘤睹,Git在1秒鐘之內(nèi)就能完成!無論你的版本庫是1個文件還是1萬個文件答倡。
-
創(chuàng)建與合并分支
在版本回退里轰传,你已經(jīng)知道催训,每次提交户矢,Git 都把它們串成一條時間線,這條時間線就是一個分支锰茉。截止到目前倔既,只有一條時間線恕曲,在 Git 里,這個分支叫主分支渤涌,即master 分支佩谣。HEAD 嚴(yán)格來說不是指向提交,而是指向 master实蓬, master 才是指向提交的茸俭,所以HEAD 指向的就是當(dāng)前分支吊履。
一開始的時候,master 分支是一條線调鬓,Git 用 master 指向最新的提交點艇炎,再用HEAD 指向 master,就能確定當(dāng)前分支腾窝,以及當(dāng)前分支的提交點:
每次提交缀踪,master 分支都會向前移動一步,這樣燕锥,隨著你不斷提交辜贵,master分支的線也越來越長
當(dāng)我們創(chuàng)建新的分支,例如 bac 時归形,Git 會新建一個指針叫 bac托慨,指向 master 相同的提交點,再把HEAD指向 bac暇榴,就表示當(dāng)前分支在 bac 上:
- Git創(chuàng)建一個分支很快厚棵,因為此時,只是增加一個 bac 指針蔼紧,然后改改 HEAD 的指向即可婆硬,工作區(qū)的文件都沒有任何變化!
從現(xiàn)在開始奸例,對工作區(qū)的修改和提交就是針對 bac 分支了彬犯,比如新提交一次后,bac 指針往前移動一步查吊,而master 指針不變谐区,HEAD 指針同樣不變:
假如我們在dev上的工作完成了,就可以把 bac 合并到 master 上逻卖。Git 怎么合并呢宋列?很簡單,先切換到 master 分支评也,此時 HEAD 指針就會指向 master 指針炼杖,之后就是直接把master 指向 bac 的當(dāng)前提交點,就完成了合并:
- 所以Git合并分支也很快盗迟!就改改指針坤邪,工作區(qū)內(nèi)容也不需要變!
合并完分支后诈乒,你覺得 bac 分支沒什么用了罩扇,甚至可以刪除 bac 分支。刪除 bac 分支就是把 bac 指針給刪掉,刪掉后喂饥,我們就剩下了一條 master 分支:
實戰(zhàn)
1消约、創(chuàng)建分支 bac
bash-3.2$ git branch bac
2、切換到分支 bac
bash-3.2$ git checkout bac
Switched to branch 'bac'
3员帮、創(chuàng)建并切換分支
上面的兩條命令可以合并為一條
bash-3.2$ git checkout -b bac
4或粮、查看分支
bash-3.2$ git branch
* bac
master
// 星號代表當(dāng)前所在的分支
5、在分支 bac 上修改文件捞高,并創(chuàng)建一個新文件 bac_new.txt氯材,最后正常添加、提交硝岗。
bash-3.2$ echo "changes on the branch of bac" >> study/readme.txt
bash-3.2$ touch bac_new.txt
bash-3.2$ git add .
bash-3.2$ git commit -m "added a new line in readme.txt,create a file bac_new.txt"
[bac 096a515] added a new line in readme.txt,create a file bac_new.txt
2 files changed, 1 insertion(+)
create mode 100644 bac_new.txt
bash-3.2$ tail -3 study/readme.txt
Git 管理的是修改
Git 管理的不是文件
changes on the branch of bac
bash-3.2$ ls
bac_new.txt newdir study
// 此時會被提交到 bac 分支氢哮,工作區(qū)當(dāng)然也是屬于 bac 分支的
6、切換到 master 分支型檀,并觀察文件的變化
bash-3.2$ git checkout master
Switched to branch 'master'
bash-3.2$ tail -3 study/readme.txt
Git is free software distributed under the GPL.
Git 管理的是修改
Git 管理的不是文件
bash-3.2$ ls
newdir study
- 切換到 master 分支后冗尤, HEAD 指針也就會指向 master 所指向的提交點,工作區(qū)也就屬于 master胀溺,自然裂七,你看不到在 bac 分支對文件做的任何修改
7、把分支 bac 合并到 master分支
bash-3.2$ git branch # 確定一下你現(xiàn)在所在的分支是 mster
bac
* master
bash-3.2$ git merge bac # 把 bac 分支合并到 master
Updating 6b0e1ca..096a515
Fast-forward
bac_new.txt | 0
study/readme.txt | 1 +
2 files changed, 1 insertion(+)
create mode 100644 bac_new.txt
bash-3.2$ ls # 確認工作區(qū)的文件
bac_new.txt newdir study
-
把 bac 分支合并到 master 分支后的文件變化:
image
8仓坞、合并完成后背零,刪除分支 bac,并查看分支
bash-3.2$ git branch -d bac
Deleted branch bac (was 096a515).
bash-3.2$ git branch
* master
bash-3.2$
- 刪除分支 bac 就變成下圖的樣子:
image
總結(jié)
* 查看分支: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>
6无埃、HEAD 指針
HEAD 指向哪個版本徙瓶,當(dāng)前就是哪個版本;當(dāng)你來回切換版本的時候嫉称,Git 只是把 HEAD 指向你要切換的版本倍啥,順便把工作區(qū)的文件更新一下,見下圖:
-
處于最新提交后的指針指向:
image -
版本回退后的指針指向:
image
7、標(biāo)簽管理
標(biāo)簽是來為某個版本取個標(biāo)簽名
1澎埠、創(chuàng)建標(biāo)簽
git tag tagname #為最新版本打標(biāo)簽
注意: 標(biāo)簽名是為最近提交的一次打的,代表了最近提交的那個版本
git tag #查看所有標(biāo)簽
git show tagname #查看標(biāo)簽信息
2始藕、刪除標(biāo)簽
git tag -d tagname #刪除某個標(biāo)簽
3蒲稳、小結(jié)
git tag -a tagname -m 'comment' #添加標(biāo)簽并且指定描述信息
8、遠程倉庫
設(shè)置全局用戶名和郵箱
git config --global user.name "anan"
git config --global user.email "283728@qq.com"
克隆遠程倉庫到本地
本地沒有倉庫的時候伍派,創(chuàng)建一個本地目錄江耀,并于遠程的GitHub倉庫建立聯(lián)系
git clone git@gitlab.com:alice/test.git #將遠程倉庫克隆到本地
cd test
touch file
git add .
git commit -m "new file"
git push -u origin master #將這個倉庫的master分支上傳到遠程倉庫
注意: 只有第一次上傳到遠程需要-u
在本地目錄創(chuàng)建倉庫,建立聯(lián)系诉植,上傳遠程
cd floder
git init #將目錄變成倉庫
git remote add git@gitlab.com:alice/test.git #與遠程倉庫建立聯(lián)系
git add .
git commit -m ''
git push -u origin master
將本地已有的倉庫上傳到遠程
cd floder
git remote rename origin old-origin
git remote add origin git@gitlab.com:alice/test.git
git push -u origin --all
git push -u origin --tags