| 時(shí)間 | 更新備注 |
|---|---|
| 2018-02-28 | 新建文章 |
| 2018-06-07 | 添加白話Git內(nèi)容 |
| 2019-01-18 | 更新鏈接 |
目錄
- Git 筆記系列(一)—— Git簡(jiǎn)介
- Git 筆記系列(二)—— Git工作流程
- Git 筆記系列(三)—— Git常用命令-一覽
- Git 筆記系列(四)—— Git常用命令-Checkout
- Git 筆記系列(五)—— Git常用命令-Branch
- Git 筆記系列(六)—— Git常用命令-Reset
- Git 筆記系列(七)—— Git常用命令-Rebase
- Git 筆記系列(八)—— Git常用命令-Stash等
- Git 筆記系列(九)—— Git進(jìn)階
引言
上一篇簡(jiǎn)單介紹了
Git后,這篇來看看使用Git的工作流程吧。
① 創(chuàng)建版本庫(kù)
第一步,通過git init命令把這個(gè)目錄變成Git可以管理的倉(cāng)庫(kù)。
第二步,用命令git add告訴Git,把文件添加到倉(cāng)庫(kù),進(jìn)行變化跟蹤:
$ git add readme.txt
第三步,把文件提交到倉(cāng)庫(kù),-m后面輸入的是本次提交的說明,能從歷史記錄里方便地找到改動(dòng)記錄。
git commit -m "xxx"
② 添加遠(yuǎn)程庫(kù)
$ git remote add origin https://github.com/xx/test.git
添加后,遠(yuǎn)程庫(kù)的名字就是origin,這是Git默認(rèn)遠(yuǎn)程庫(kù)。
下一步,就可以把本地庫(kù)的所有內(nèi)容推送到遠(yuǎn)程庫(kù)上:
$ git push -u origin master
把本地庫(kù)的內(nèi)容推送到遠(yuǎn)程,用git push命令,實(shí)際上是把當(dāng)前分支master推送到遠(yuǎn)程。
由于遠(yuǎn)程庫(kù)是空的,我們第一次推送master分支時(shí),加上了-u參數(shù),Git不但會(huì)把本地的master分支內(nèi)容推送的遠(yuǎn)程新的master分支,還會(huì)把本地的master分支和遠(yuǎn)程的master分支關(guān)聯(lián)起來,在以后的推送或者拉取時(shí)就可以簡(jiǎn)化命令。
總結(jié):從現(xiàn)在起,只要本地作了提交,就可以通過命令:git push origin master
把本地master分支的最新修改推送至GitHub,現(xiàn)在,你就擁有了真正的分布式版本庫(kù)!
要關(guān)聯(lián)一個(gè)遠(yuǎn)程庫(kù),使用命令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)程庫(kù)的存在,也就是有沒有聯(lián)網(wǎng)都可以正常工作,而SVN在沒有聯(lián)網(wǎng)的時(shí)候是拒絕干活的!當(dāng)有網(wǎng)絡(luò)的時(shí)候,再把本地提交推送一下就完成了同步,真是太方便了!
③ 從遠(yuǎn)程庫(kù)克隆
上次我們講了先有本地庫(kù),后有遠(yuǎn)程庫(kù)的時(shí)候,如何關(guān)聯(lián)遠(yuǎn)程庫(kù)。
現(xiàn)在,假設(shè)我們從零開發(fā),那么最好的方式是先創(chuàng)建遠(yuǎn)程庫(kù),然后,從遠(yuǎn)程庫(kù)克隆。
要克隆一個(gè)倉(cāng)庫(kù),首先必須知道倉(cāng)庫(kù)的地址,然后使用git clone命令克隆。
Git支持多種協(xié)議,包括https,但通過ssh支持的原生Git協(xié)議速度最快。
④ 場(chǎng)景操作
在下圖中,可以看到部分Git命令是如何影響工作區(qū)和暫存區(qū)(stage,亦稱index)的。

圖中左側(cè)為工作區(qū),右側(cè)為版本庫(kù)。在版本庫(kù)中標(biāo)記為index的區(qū)域是暫存區(qū)(stage,亦稱index),標(biāo)記為master的是master分支所代表的目錄樹。
-
HEAD實(shí)際是指向指向當(dāng)前所在的本地分支的一個(gè)“游標(biāo)”。告訴Git當(dāng)前的工作區(qū)在哪一個(gè)分支上。 -
head(小寫)是commit對(duì)象的引用,每個(gè)head都有一個(gè)名字(分支名字或者標(biāo)簽名字等等),但是默認(rèn)情況下,每個(gè)叫master的repository都會(huì)有一個(gè)head, 一個(gè)repository可以包含任意數(shù)量的head。在任何時(shí)候,只要這個(gè)head被選擇成為current head,那么這個(gè)head就成了HEAD,總是大寫
圖中的objects標(biāo)識(shí)的區(qū)域?yàn)?code>Git的對(duì)象庫(kù),實(shí)際位于.git/objects目錄下。
文件變動(dòng)更改
在Git中,我們用一個(gè)提交來保存更改,當(dāng)對(duì)工作區(qū)修改(或新增)的文件執(zhí)行git add命令時(shí),暫存區(qū)的目錄樹被更新,同時(shí)工作區(qū)修改(或新增)的文件內(nèi)容被寫入到對(duì)象庫(kù)中的一個(gè)新的對(duì)象中,而該對(duì)象的ID被記錄在暫存區(qū)的文件索引中。
git add 跟蹤文件變化
- git add -A 提交所有變化
- git add -u 提交被修改(modified)和被刪除(deleted)文件,不包括新文件(new)
- git add . 提交新文件(new)和被修改(modified)文件,不包括被刪除(deleted)文件
Git Flow
當(dāng)你第一次checkout一個(gè)分支,HEAD就指向當(dāng)前分支的最近一個(gè)commit。在HEAD中的文件集(實(shí)際上他們從技術(shù)上不是文件,他們是blobs(一團(tuán)),但是為了討論的方便我們就簡(jiǎn)化認(rèn)為他們就是一些文件)和在index中的文件集是相同的,在working copy的文件集和HEAD,Index中的文件集是完全相同的。所有三者(HEAD,Index(Staging),Working Copy)都是相同的狀態(tài),Git很happy。
當(dāng)你對(duì)一個(gè)文件執(zhí)行一次修改,Git感知到了這個(gè)修改,并且說:“嘿,文件已經(jīng)變更了!你的Working Copy不再和index,head相同!”,隨后Git標(biāo)記這個(gè)文件是修改過的。
然后,當(dāng)你執(zhí)行一個(gè)git add,它就stages the file in the index,并且GIT說:“嘿,OK,現(xiàn)在你的working copy和index區(qū)是相同的,但是他們和HEAD區(qū)是不同的!”
當(dāng)你執(zhí)行一個(gè)git commit, Git就創(chuàng)建一個(gè)新的commit,隨后HEAD就指向這個(gè)新的commit,而index, working copy的狀態(tài)和HEAD就又完全匹配相同了,Git又一次Happy了。
文件提交
當(dāng)執(zhí)行提交操作(git commit)時(shí),暫存區(qū)的目錄樹寫到版本庫(kù)(對(duì)象庫(kù))中,被提交的分支,比如master分支,會(huì)做相應(yīng)的更新。即master最新指向的目錄樹就是提交時(shí)原暫存區(qū)的目錄樹。
當(dāng)執(zhí)行git reset HEAD命令時(shí),暫存區(qū)的目錄樹會(huì)被重寫,被master分支指向的目錄樹所替換,但是工作區(qū)不受影響。
1.要隨時(shí)掌握工作區(qū)的狀態(tài),使用git status命令。
2.如果git status告訴你有文件被修改過,用git diff可以查看修改內(nèi)容。
刪除文件
1.命令git rm用于刪除一個(gè)文件。
2.確實(shí)要從版本庫(kù)中刪除該文件,那就用命令git rm刪掉,并且git commit:
$ git rm test.txt
rm 'test.txt'
$ git commit -m "remove test.txt"
[master d17efd8] remove test.txt
1 file changed, 1 deletion(-)
delete mode 100644 test.txt
撤銷修改
場(chǎng)景1
當(dāng)你改亂了工作區(qū)某個(gè)文件的內(nèi)容,想直接丟棄工作區(qū)的修改時(shí),用命令
$ git checkout -- file。
場(chǎng)景2
當(dāng)你不但改亂了工作區(qū)某個(gè)文件的內(nèi)容,還添加到了暫存區(qū)時(shí),想丟棄修改,分兩步:
用命令
git reset HEAD file,取消暫存,就回到了場(chǎng)景1;按場(chǎng)景1操作:
$ git checkout -- file。
(git reset命令既可以回退版本,也可以把暫存區(qū)的修改回退到工作區(qū)。當(dāng)我們用HEAD時(shí),表示最新的版本。)
場(chǎng)景3
已經(jīng)提交了不合適的修改到版本庫(kù)時(shí),沒有推送到遠(yuǎn)程庫(kù)時(shí),想要撤銷本次提交,git reset HEAD^
| git刪除文件情況 | 恢復(fù)命令 |
|---|---|
| 刪除本地文件,但是未添加到暫存區(qū); | git checkout --deletedFileName |
| 刪除本地文件,并且把刪除操作添加到了暫存區(qū); | git reset HEAD deletedFileName, git co deletedFileName |
| 把暫存區(qū)的操作提交到了本地git庫(kù); |
git reset --hard ORIG_HEAD強(qiáng)制回滾到未刪除版本 |
| 把本地git庫(kù)的刪除記錄推送到了遠(yuǎn)程服務(wù)器github。 | 強(qiáng)制回滾到未刪除版本,然后強(qiáng)制推送git push -f
|
文件操作圖示

版本回退
-
HEAD指向的版本就是當(dāng)前版本,因此,Git允許我們?cè)诎姹镜臍v史之間穿梭,使用命令
$ git reset --hard commit_id
- 穿梭前,用
git log可以查看提交歷史,以便確定要回退到哪個(gè)版本。 - 要重返未來,用
git reflog查看命令歷史,以便確定要回到未來的哪個(gè)版本。 - 使用
git diff命令可以查看工作區(qū)和版本庫(kù)里面最新版本的區(qū)別
$ git diff HEAD -- readme.txt
⑤白話Git
能不能講人話?
好的,舉個(gè)栗子,一次產(chǎn)品發(fā)布后,上了不少新功能。你和同事激動(dòng)的討論著。
隔壁產(chǎn)品小妹十分好奇,問你:『你們都在說的變基、Merge 都是做什么的?』你想了想,這么解釋給她聽:Merge 合并與沖突『你和你的男朋友生活非常幸福』你說:『兩個(gè)人一起為共同生活而努力,我們來假設(shè)家庭生活是你們兩個(gè)人的主線,每天工作、休息、吃愛吃的食物,做愛做的事情,像這樣』

白話分支
『而分支就是偶爾他和朋友看個(gè)球,你和閨蜜逛個(gè)街。主線之外,你們還有各自的支線任務(wù)。但是完成支線任務(wù)之后,你們兩個(gè)還是可以去一起看個(gè)電影啊,像這樣支線任務(wù)完成回到了主線任務(wù),并且可能你去逛了街穿了美美的衣服,有了一次很棒的約會(huì),支線任務(wù)也是為主線添磚加瓦的?!?/p>

白話沖突
『那你們平常說的沖突呢?』『沖突是這樣的。比如今天他下班去踢球,說好今晚約會(huì),結(jié)果他一身臭汗的回來。你會(huì)不會(huì)不開心?』『生氣啊,他都記不得今晚有約會(huì)?!弧憾?,這個(gè)時(shí)候沖突就產(chǎn)生了,沖突產(chǎn)生的時(shí)候,他的支線任務(wù)就很難合并到主線任務(wù)中。在我們使用 WebIDE 的時(shí)候,合并的時(shí)候會(huì)提示你「發(fā)現(xiàn)沖突」,并且彈出沖突列表,再進(jìn)行逐行處理,協(xié)調(diào)主線任務(wù)和支線任務(wù)。比如他早點(diǎn)回來洗澡,你花點(diǎn)時(shí)間補(bǔ)妝?!弧喊““。@挺好,省的男朋友老問我為什么生氣。笨死了?!弧喝缓笪覀?cè)賮碚f說儲(chǔ)藏。』Stash 儲(chǔ)藏『儲(chǔ)藏的話,是不是說工作做到一半,要存著接著做?』『某種程度上說是的,你做到一半要有其他事情的時(shí)候,就需要把這件事情存起來。比如男朋友要送你一個(gè)手工的禮物,像這樣可愛的龍貓』

白話stash
『哇,好萌?!弧簩?duì)的,但是又有了別的工作,可是他做到一半的時(shí)候可能是這樣的,所以不想讓你看到,不能放家里只能放在辦公室。就把現(xiàn)在的工作存儲(chǔ)下來。并不提交到主線任務(wù)。而且可以順利恢復(fù)上次的進(jìn)度。』

白話rebase
『這么說就很好理解了,那你快告訴我變基是什么啊。是不是男朋友跟別的男孩子跑了?!弧侯~,怎么會(huì),你男朋友又不是程序員……』Rebase 變基『變基的基其實(shí)是基礎(chǔ)的意思,簡(jiǎn)單來說就是把支線任務(wù)變成主線任務(wù)?!弧喊ィ柯犉饋砗?Merge 有點(diǎn)像啊?!弧菏堑?,目的上都是把分支任務(wù)整合到主線任務(wù)上,但是還是有一些區(qū)別的,畫個(gè)圖你就了解了,第一張圖是 Merge?!?/p>

『第二張圖是 Rebase,他會(huì)對(duì)比主線「工作」之后兩個(gè)支線分支 A「追番」和 B「燒飯」的相似與不同,將不同之處「爐子上要燉湯」提取出來作為 B1,然后把「A+B1」即「追番(一起)」和「燉湯 ing」放在主線任務(wù)里。』

白話reset
『哦?看起來變基是個(gè)好功能呢?!弧菏堑模?Merge 的線路更加流暢整潔,特別是支線任務(wù)復(fù)雜的時(shí)候。』Reset 重置『重置就是你和男朋友吵架了,他特別想用的功能……』『就是返回到不生氣的狀態(tài)是嗎?』『是的是的?!?/p>

白話Tag
Tag 標(biāo)簽『這就是給任務(wù)改名字嗎?』『是的,常常會(huì)把任務(wù)改成更有意義的名字,比如這樣。』

Git文件4種狀態(tài)

Untracked: 未跟蹤, 此文件在文件夾中, 但并沒有加入到git庫(kù), 不參與版本控制. 通過
git add狀態(tài)變?yōu)?code>Staged.Unmodify: 文件已經(jīng)入庫(kù), 未修改, 即版本庫(kù)中的文件快照內(nèi)容與文件夾中完全一致. 這種類型的文件有兩種去處, 如果它被修改, 而變?yōu)?code>Modified. 如果使用
git rm移出版本庫(kù), 則成為Untracked文件Modified: 文件已修改, 僅僅是修改, 并沒有進(jìn)行其他的操作. 這個(gè)文件也有兩個(gè)去處, 通過
git add可進(jìn)入暫存staged狀態(tài), 使用git checkout則丟棄修改過, 返回到unmodify狀態(tài), 這個(gè)git checkout即從庫(kù)中取出文件, 覆蓋當(dāng)前修改Staged: 暫存狀態(tài). 執(zhí)行
git commit則將修改同步到庫(kù)中, 這時(shí)庫(kù)中的文件和本地文件又變?yōu)橐恢? 文件為Unmodify狀態(tài). 執(zhí)行git reset HEAD filename取消暫存, 文件狀態(tài)為Modified
總結(jié)
-
git add files把把文件修改添加到暫存區(qū)。 -
git commit給暫存區(qū)域生成快照并提交。 -
git reset -- files用來撤銷最后一次git add files,你也可以用git reset撤銷所有暫存區(qū)域文件。 -
git checkout -- files把文件從暫存區(qū)域復(fù)制到工作目錄,用來丟棄本地修改。暫存區(qū)的所有內(nèi)容提交到當(dāng)前分支 - Git是如何跟蹤修改的:每次修改,如果不add到暫存區(qū),那就不會(huì)加入到commit中。