Git實用指南第一篇

本篇提要:git的核心理念、結構、代碼庫的建立和Mergegit

從開始使用git至今看過無數文章,大多時候是爲了解決一個特定問題,尋求一個特定的解決方案,偶爾也會看一些新手向的教程。對於前者,可能須要你具有必定的git能力,這無可厚非。但大多新手向的教程主要鋪陳git的經常使用命令,看的時候以爲本身懂了,但實際使用時就會問題重重。github

磕磕絆絆至今,我對git也算是有了一些瞭解,固然都是使用向而不是原理向。在此但願可以以我本身理解的方式,描述我在使用git時的一些心得,但願可以幫助一些新手或者經常被git困擾的夥伴。編程

git的核心理念和結構

五花八門的命令是使用git的手段,並非git的核心。在我看來,與其掌握100條命令,不如先大體瞭解一下git的思想和大致架構。從使用者角度出發,git的目的就是爲了方便咱們隨時找到須要的代碼並進行處理,而咱們經常使用的大多數命令,都是爲了這一點服務的,確切的來講這一點就是一條commit。bash

從結構來講,git主要有工做區、暫存區和版本庫三大區域。工做區就是咱們寫代碼的地方,git會追蹤你幹了什麼,並告訴你你的操做和版本庫有哪些不一樣。暫存區就是對你如今的工做拍照,也就是所謂快照,繼續在工做區操做,暫存區仍是會停留在拍照那一刻,就像手機截屏同樣。版本庫就是當你以爲暫存區的代碼沒問題以後,就能夠入庫了,這時候git就真正把你所作的事變成了一條有價值的commit。微信

使git變得錯綜複雜的概念是分支,但分支又是必不可少的,不少時候你不得不放下手頭的工做,先去處理其餘的問題,處理完後再回來繼續工做。這種狀況下,必需要保證的是被中斷的工做就停留在它剛纔的狀態,不然現有的工做就沒法繼續下去了。分支看起來就像一個副本(雖然git確定不是這麼實現的,但咱們仍是能夠簡單的理解它就是複製了一次),確保了在某個分支上操做,不會影響到其餘分支的內容。架構

以上就是咱們平常使用git的所有了,在工做區工做,到某個節點拍照存到暫存區,確認無誤後合併到版本庫。偶爾來個突發事件,停下手頭的工做到另外一個分支處理,結束後回來繼續工做。不過這都是概念性的,至關於定義了遊戲規則,接下來就是看git給咱們提供了哪些手段來完成此事。ide

建模,讓git更有趣

在正式操做git命令以前,我以爲對概念建模能對咱們理解git提供有效幫助。咱們把git看作一片竹林,我是一個園丁,我和其餘的園丁一塊兒照料這片林子,只不過這裏的每根竹子要生長一節都是咱們園丁說了算,而不是大地(看起來咱們都是上帝?)。而咱們每一個人的工做,就是決定什麼時間讓竹子長一節,記錄咱們工做的工具是分配給每一個人的一臺電腦。工具

咱們的模型就是這麼簡單,一堆人一塊兒「造」竹子,接下來跟隨着時間的腳步看下咱們的模型如何運做吧。(PS:看起來怪怪的,莫不是咱們開了一個竹子蠟像館?問題是能吸引來哪怕一個遊客嗎?無論那麼多了,老闆的想法不是咱們普通工人應該琢磨的,有錢拿就好了。。。)fetch

git命令和模型結合,推動時間線

第一天:項目的創建和代碼合併(Merge)

1. 項目啓動儀式

一開始咱們很窮,除了錢什麼都沒有。要想造竹子,得先有地盤吧,因此咱們就拿錢買了塊地,它大概是ui

好了,不開玩笑,它大概這麼大:

打開你的命令行,輸入如下字母,你就獲得了同樣大的土地:

mkdir first_git
cd ./first_git/
git init
複製代碼

當你看到這樣的輸出,就成功了:

git init

這裏看到了 master,這是git默認給咱們建立的分支,也叫主分支,畢竟git須要在某個分支工做。給咱們的模型挖一個坑,稍大一點,之後就是咱們的明星產品了。

master

我(飛機醬)和個人小夥伴(姑且叫他路人丙)深得老闆器重,因此這塊地目前所有屬於咱們。雖然說咱們只有兩我的,但也要衡量誰作的多作的好,發給每一個人的電腦就是用來記錄咱們天天都作了什麼,最後每一個人的成果還要彙總一下交給老闆。因此還須要一臺公共的電腦用來彙總咱們的信息,把咱們各自的工做整理後發到這臺電腦上,最終整合成美觀的結果報告等待老闆查閱。既然這臺電腦已經開了頭,就把它充公吧。

事情要由老闆牽頭,因此老闆在這臺電腦上籤了名,並寫下如下內容:「竹林001號項目啓動」。接下來就什麼都無論了...

使用git完成老闆的操做可不簡單,你得依次作如下幾個事情:

git config --global user.name "boss"
git config --global user.email "boss@git.com"
複製代碼

以上就是老闆簽名的步驟,--global 是說這個電腦上的所有項目都是老闆的,操做者也是他本身,並且他也不必每次開一個項目都再次簽名認證了(這樣一來,路人丙若是想搗亂,老闆必定會發現他)。

接下來老闆新建了一個README.txt並將內容竹林001號項目啓動寫進去保存了起來

echo 竹林001號項目啓動 > README.txt
複製代碼

寫好了開場白,還得按照規矩把它存到版本庫裏,否則事情就白作了。先用 git status 看看如今版本庫的狀態:

README

那個紅色的 README.txt 就是咱們的工做區,git發現了工做區改動,可是暫存區裏沒有它,版本庫裏也沒有。既然用git工具,就務必按照規則來,先把工做區拍照存到暫存區,再進入版本庫:

// 添加到暫存區
git add README.txt
複製代碼

再看看狀態,發現紅色變成綠色了,這時候就進了暫存區:

暫存區

最後,終於能夠入庫了,咱們的項目也算正式啓動。

// 併入版本庫
git commit -m "老闆寫下了啓動標語"
複製代碼

-m 後邊加的內容表示此次作了什麼,方便之後查閱。執行完成以後,咱們就擁有了第一個commit,也就是第一個有價值的節點。

first commit

使用 git log 能夠看看咱們作過什麼:

log

commit 後邊那個長長的字符串,它是此次commit的惟一標識,後邊咱們會明白它的意義。

如今,咱們有了第一節竹子(畫圖很差,勿吐槽):

first commit

2. 開工,各自爲戰

老闆只在公共的電腦上寫下了標語,咱們本身的電腦尚未呢,總不能讓老闆挨個寫吧?(老闆:……)因此咱們要有個辦法把公共電腦的內容搞過來,這就是git clone。咱們只要在本身的電腦上,執行 git clone + 版本庫的路徑,就能把代碼同步過來,我這裏只能在同一個電腦操做,因此用倉庫名稱進行 clone(同時在源版本庫執行git config receive.denyCurrentBranch warn):

clone

能夠看到老闆修改的內容已通過來了。路人丙也執行了一樣的操做,這樣就能夠各作各的。爲了知道是誰作的工做,咱們還分別設置了本身的名字,這樣之後的每一個commit都會攜帶做者(路人丙幹了壞事,咱們看看 git log 就能抓到他!)。若是隻有一個項目,能夠不加--global。如今咱們的土地上有了三根同樣的竹子:

clone

一切準備就緒,接下來就能夠開始幹活了,飛機醬和路人丙都在全力造竹子,並記錄到本身的電腦裏,此時公共電腦並不知道他們幹了什麼。第一天由於沒有經驗,工做中出現了屢次失誤,飛機醬只造好了一竹節,路人丙好一些,造好了兩節。因此他們的竹子是這樣的:

第一天

在他們本身的版本庫裏,都在 work_01.txt文件裏記錄了本身的工做,並保存到了版本庫:

飛機醬的日誌

路人丙的日誌

下班後,飛機醬把記錄同步到了公共電腦上,而後開心的回家了。他是這麼操做的:

git push origin master:master
複製代碼

push

origin是遠程版本庫名稱,雖然咱們沒有配置它,但它默認就是origin,第一個master是飛機醬電腦上使用的分支,第二個master是遠程版本庫的分支。(飛機醬可能提早補課了,命令寫的很全)

接下來到路人丙同步了,他也使用了相似的操做,可是卻發生了意外:

push

同樣的操做,結果卻迥異,路人丙的心裏必定是凌亂的,但他還認識幾個單詞,大體明白了提示的意思。原來飛機醬在他前面進行了push操做,致使他這裏文件不夠新,git就拒絕了他。因此他按照提示中 (e.g., 'git pull ...') before pushing again. 又試了一次。結果在git pull時再次發生意外:

pull

conflict的意思是衝突,conflict出如今對同一個文件的同一行進行了不一樣修改的時候。咱們記得飛機醬和路人丙都建立了 work_01.txt文件並寫入了內容,因此git合併時發現第一行都寫入了內容,就無法決定讓誰的修改在前,就會要求咱們手動解決。如今咱們打開路人丙的 work_01.txt,看看它的內容:

conflict

能夠看到,兩人輸入的內容用 <<<<HEAD...====...>>>>{commitId}這樣的格式包裹起來了。前面是路人丙的內容,後邊是飛機醬的內容。想要合併到遠程版本庫,就必定要先解決掉這個問題,不然老闆看到就要發火了~因此路人丙改了它,並把飛機醬的內容放在了下邊(老闆確定會先看到前面的內容):

修改內容

由於又發生了修改,因此內容如今還在工做區,就須要再次把它加到暫存區,再入庫。一通操做後,總算合併成功了:

push

如今讓咱們更新一下當前模型的狀態,路人丙爲了解決衝突增長了一個commit,這時候公共電腦的log看起來是這樣的:

遠端版本庫

是否是理所固然的認爲竹子長這樣呢:

想象中

看起來沒有問題,並且git log顯示也是如此。可是這裏有個問題,你們都是今天干完的活,都要把本身的竹子安到明星產品上,憑什麼你先放?路人丙的工做又快又好,難道不是更有資格先放嗎?路人丙認爲把兩我的的竹子擰在一塊兒,最後再用灰色的那節整合在一塊兒最公平了,老闆一眼就明白咱們是同時完成的工做:

整合

看起來很奇怪吧?好好的竹子由於互相爭搶鼓了一個包,看起來十分不美觀(話說這樣老闆不會生氣嗎?仍是可能會吸引來奇怪的旅客?)。

實際上git pull操做是由兩個命令組成的,第一個是git fetch,表示把遠端版本庫的內容拉取到本地,第二步纔是執行git merge操做把拉取下來的新內容和咱們本身的內容合併在一塊兒。既然都想佔第一個位置,乾脆git幫你整合一下,而後用一個新的commit代替就行了。要想證實事實上的確如此,使用上面的 git log 是不行的,你要在後邊加上 --pretty=raw

git log --pretty=raw
複製代碼

pretty

commit較多,但最後一條顯示不全的是老闆的提交,並不影響咱們分析它。咱們主要看每條commit的parent字段,能夠發現最上方的那一條有兩個parent,分別指向了飛機醬的第一條和路人丙的第二條,而被指向的這兩條數據的parent都是老闆的那次提交,這和咱們預期的徹底一致。

3. 老闆的怒火,推倒重來

解決了問題,路人丙很開心。關掉電腦,背上揹包,正準備回去美餐一頓,老闆卻過來視察工做了,先是誇了一頓路人丙工做努力,轉眼看到造好的竹子,怒髮衝冠,責令路人丙立刻把問題解決掉!

這問題難不倒他,既然能把竹子合起來,再拆開豈不是至關容易,因而他拿起那臺公共電腦,輸入瞭如下命令:

// reset --merge 重置merge,後邊跟上以前的commitId,就能夠回到過去
git reset --merge 2b0218d74edbea391c8b7853580c99164af8d32a
複製代碼

再看看日誌,完蛋,紙飛機的記錄不見了,被路人丙的記錄取而代之!

重置merge

這下可怎麼好,明天飛機醬來了很差交代呀,並且把別人的工做整丟也不符合道義,有後悔藥吃就行了。這時候一邊的老闆看不下去了,拿起電腦飛快的敲了一條指令:

git reset --hard HEAD@{1}
複製代碼

而後把電腦交回路人丙,丟下一句:好了,後悔藥吃下去了。(路人丙:我@#$*&^^,發生了什麼事?)再一看,果真又回到剛纔的狀態了,原來老闆是大神呀,惋惜太冷漠,苦事還得我來作。

檢查一下剛纔的 git reset xxx ,後邊跟了路人丙的commitId,結果就剩下了他的工做,這裏一共兩條路,指到飛機醬那邊是否是就行了呢,再試一次,反正有老闆在隨時能吃後悔藥(話說這麼大膽的麼)。

git reset --merge ba65055dab9700d0e814719bbf23713c163ade76
複製代碼

再次重置merge

果真是,我路人丙就是個天才,哈哈哈!

等等,這不是飛機醬離開時的狀態嗎,剛剛的路行不通,我該怎麼辦好呢?回想一下剛恰好像是由於衝突纔多了一個commit,那若是我不讓它衝突豈不就行了?這工做記錄都寫一個文件裏看着也有些亂,我再換個文件也許就行了呢。路人丙用求助的眼神看着老闆,意思是但願老闆能把他本身的工做記錄刪一下,他已經有了好的idea想再試一下。接下來又是老闆炫技的時間,不過此次是在路人丙的電腦上:

git log
// 重置到老闆本身的commitId
git reset --hard 420e8fe77141a4f6c9cfed2518c65b04d21bcec0
複製代碼

因而路人丙的工做全不見了,一切彷彿回到了剛開始。

從新來過

此次路人丙給文件起了一個不同的名字 lurenbing_01.txt,又把工做記錄寫了進去,再次進行提交:

push

果真仍是須要先pull,再pull一下看看結果:

此次確實沒有了衝突,可是彈出了一個框,內容說明這是一次merge,先無論它,直接下一步,再看git log --pretty=raw

log

爲何,都不在一塊兒了仍是這樣,路人丙都要崩潰了。必定是剛剛pull的問題,我要是先pull,再寫個人工做記錄是否是就行了。再次讓老闆幫忙重置後,路人丙先pull了一次:

先pull

這下飛機醬的工做記錄都到我這了,我再寫應該沒問題了吧,一頓操做下來,這一次順利的合併了進去,既沒有衝突,也沒有彈出框。到公共電腦上一看,很好很順利:

完成工做

時間太晚,工做也馬馬虎虎算搞定了,老闆打算放過路人丙,但臨走前問了一個令路人丙瞬間凌亂的問題:若是每次都要先pull再開始寫你本身的commit,那你天天都要等飛機醬下班後纔開始工做?(路人丙:那我天天豈不是比飛機醬多工做一倍的時間?明天我要找他研究研究,這實在不是人乾的事啊~)

最後更新一下咱們的模型,能夠看到路人丙的竹節最後仍是放在了上邊,因此乾的又快又好有什麼用呢,快要快在關鍵時刻。

模型的最終狀態

第一天的工做就到此結束了,能夠看到,只要路人丙但願兩我的的工做可以平等的佔據第一的位置,就必定會造成鼓包,經過一個新竹節把這兩條路歸一。而若是他自願把工做放在後邊,一切就很順暢,有時候真的是退一步海闊天空啊。


我是飛機醬,若是您喜歡個人文章,能夠關注個人微信公衆號: 大大紙飛機

或者掃描下方二維碼直接添加:

公衆號

您也能夠關注個人github:github.com/LtLei/artic…

編程之路,道阻且長。惟,路漫漫其修遠兮,吾將上下而求索。

相關文章
相關標籤/搜索