首先爲何要寫這篇文章?由於最近老是遇到有人在問一些關於代碼管理的問題,好比怎麼從 倉庫拉代碼,上傳代碼,也有徹底沒用過代碼管理系統的。所以這篇文章是結合這幾年來使用 git 團隊協做或我的的代碼管理的使用心得。html
那 git 是什麼呢?git 是一個分佈式代碼管理系統,可能不少人以前用過 svn 這樣的代碼管理系統。不過 git 的特色是分佈式,以及更加便捷的協做方式。git 的使用也是十分普遍,好比程序員交友圈 github, gitlab, gogs 等等代碼託管平臺都是使用 git 做爲代碼管理工具。git
SSH加密認證原理: SSH(Secure Shell)是一種非對稱加密與對稱加密算法相結合的安全網絡協議,用於計算機通訊加密。一個SSH會話的創建過程分爲兩個階段:第一階段,雙方溝通並贊成創建一個加密鏈接通道以供後續信息傳輸用;第二階段,對請求接入的用戶進行身份驗證以肯定服務器端是否要給該用戶開放訪問權限。詳細的文章請參考理解SSH的加密與鏈接過程 。程序員
首先,若是主機本地沒有創建祕鑰對,就須要生成。生成方式:github
固然你可使用默認的方式,一路回車下去便可。或者也能夠指定名稱。例如 test,一路回車便可。算法
在當前目錄下會看到生成的祕鑰對以下,其中帶後綴.pub 爲公鑰,沒有後綴的爲私鑰。vim
這樣就生成好了祕鑰對,切記不要將私鑰隨意上傳到能被網絡訪問、下載。我的的作法是用一套密鑰對來管理全部的終端,好比雲主機的 ssh 登錄方式。緩存
這裏以 github 舉例,你將你的公鑰拷貝後,登入 github, 而後找到 Settings -> SSH and GPG keys。 如圖的所示的地方新建並粘貼。安全
點擊進入,如圖所示:bash
當搞定這個了就能夠愉快的在 github 代碼託管倉庫建立你的項目了,這裏我就一個測試的項目講解個人使用過程。第一步新建項目:服務器
點擊進入,填寫項目名稱以及項目的訪問方式, 這裏我以公開訪問方式,也就是全部人均可以訪問這個項目。
新建項目完成後第一個要作的就是將這個項目 clone(克隆) 到本地主機。
而後在終端中輸入, 這是第一個命令。
git clone git@github.com:huangxiaojingCN/LearningGit.git
複製代碼
在終端命令行中輸入: ls -al 查看, 能夠看到有一個隱藏的目錄文件 .git, 在這個文件下就是記錄這個代碼倉庫的全部信息,其中也有不少功能能夠用以咱們對代碼的自動化,代碼檢查等等。
接下來是第二個命令:git add 文件
// 建立一個新的空白文件,你可使用文本編輯器打開並編輯內容,也可使用 echo "This is a a.txt." >> a.txt
touch a.txt
// 將字符串 "hello world" 重定向到 a.txt
echo "This is a a.txt" >> a.txt
// 經過 git add a.txt 文件加入到本地代碼管理
git add a.txt
複製代碼
固然你也可使用 git add -p 命令來提交文件中的添加記錄, 前提是這個文件以及在本地代碼管理庫中存在。稍後再說這個用法,很是實用。
第三個命令: git status, 查看當前代碼庫的狀態
git status
複製代碼
不難看到,咱們發現剛纔執行了 git add a.txt 的命令被加入到了緩存區,即將要被提交 commit,固然你也能夠刪除它,執行 git rm --cached a.txt。
第四個命令: git commit -m "提交消息",只有在執行了 git add 將其加入到本地緩存區後才能使用 commit, 將其加入到本地代碼倉庫。
git commit -m "添加了 a.txt 文件,並加入了 hello world 文本內容."
複製代碼
從上面的結果顯示中能夠看到,a.txt 被正確建立並加入到了本地代碼管理庫中。接着經過前面的命令 git status 查看下當前的代碼庫狀態, 能夠發現已經沒有文件要被提交。
通過上面的兩個步驟:git add、git commit 就已經代碼加入到了本地代碼倉庫中,經過 git status 輔助查看本地代碼倉庫的狀態。 這三個命令構成另外一次本地代碼的的提交,比較基礎可是很是經常使用。
第五個命令: git log, 從名字不難看出就是要看看咱們本地代碼倉庫的日誌。
git log
複製代碼
看到上面的截圖是否是就發現,咱們剛纔提交的信息也被展示出來啦!沒錯,這就是告訴你文件被正確提交併加入到了本地代碼倉庫中。可能你們發現了有一個 HEAD-> master,你只須要記住,當前 HEAD 所在的地方就是你的代碼的版本。若是你發現你的截圖跟我不一致,沒有 Author 那是由於還沒配置,這個後面再說,先說完整個 git 使用流程。
如今再來修改下 a.txt 的內容: 好比咱們加入其餘文本內容以下, 筆者使用的 vim 編輯方式,固然你可使用你順手的,好比編輯器等等。
編輯完後引入新的 git add 帶參數的方式:
git add -p
複製代碼
請你仔細看, 從第一行開始: diff --git a/a.txt b/a.txt 就是比較原來的 a.txt 和如今更改後的 a.txt 有啥區別。 綠色的 "+" 號表示新添加的,紅色的 "-" 號表明刪除的內容。最後一行方框中有選擇[y, n,q,a,d, /, e, ?],而後讓你填寫一種,通常咱們使用最多的就是: y(yes)、n(no)、q(quit)。 這裏咱們寫入 y 後回車。
不知道還記不記得前面提到的 git status, 用來查看當前本地代碼倉庫的狀態。你看出了什麼變化嗎?😄😄 前面添加的文件若是是新的, 那麼看到的就是 new file, 若是是修改的是 modified。這也很好理解嘛!
那下一步咱們是否是又要提交啦!繼續 git commit -m "提交信息"
而後查看一下 git log 日誌吧!嗯嗯,是否是又看到了新修改的 a.txt 文件啦!
爲了鞏固前面的學到的知識,咱們將繼續新建一個文件, 鞏固 add、commit、status、log 的用法, 來來來
touch b.txt
echo "This is a b.txt" >> b.txt
git add b.txt
複製代碼
按照管理,看看本地代碼庫的狀態: git status
ok! 翻譯一下吧!說的就是告訴你這個文件未被追蹤,也就是未被加入本地代碼倉庫中。你可使用 git add file 的方式去添加。那就執行 git add b.txt, 而後經過 git status 看看。 是否是很熟悉啦!可是我寫到想吐😄
到了這人咱們是否是就要提交了,從它的結果中也是能夠看出的。繼續執行:
git commit -m "添加了 a.txt 文件,加入了 This is a b.txt 文本內容."
複製代碼
這個結果也是前面見過的,你應該有感受了吧!這裏告訴咱們的是 b.txt 也被加入到本地代碼倉庫中。
快快使用 git status 和 git log 來瞅瞅吧!大佬!
又一個文件被添加到本地代碼庫管理了。可是這裏你看看 log 的方式是不不夠清晰,咱們能不能看看它的生長過程。這個時候咱們就要爲 log 加上一些參數啦!
// --graph 圖形化展現
// --decorate 查看當前提交的 commit 信息和其餘的描述信息
// --all 查看全部的分支,分支的機率後面再說。
git log --graph --decorate --all
複製代碼
看到區別了吧! 是否是旁邊多了一條線,這個就比如咱們物流時間軸。後面的確定是包含前面的過程,在這裏就是後面會包含前面提交的文件。好比當前 HEAD 所在的地方,執行 ls,能夠看到即包含了 a.txt 又包含了 b.txt。
梳理一下前面的過程: 其無非核心的就是: add -> commit, 輔助 git status, git log 來完成提交到本地代碼庫的操做。
接下來就開始往遠程倉庫推代碼和拉取代碼啦!首先先來解釋下前面老是提到的本地代碼倉庫,這個含義就是你的服務端代碼倉庫可能不包含你本地新建的文件,很簡單嘛!你沒有把信息同步給別人,別人是不知情你的本地的變化的。在這裏我就引入遠程代碼倉庫。接下來就是和遠程倉庫的交互。
再回顧下前面 log 日誌打印內容, 你會發現有一串很長的數字。它表明了當前的提交的惟一標示,即咱們能夠經過它找到任意一次提交的代碼。
第七個命令: git push。 push 的單詞意思就是推送,即客戶端向遠程倉庫推送代碼。那 origin 又是什麼? 這個實際上是遠程倉庫的名字而已,它等效於前面克隆的地址。你能夠經過 git remote show origin 來查看。
git push origin HEAD:分支
複製代碼
從打印能夠看到,Push URL: 即咱們要推送的地址,而 Fetch URL 就是咱們要拉取代碼的地址。
好吧! 那咱們執行提交代碼的命令看看效果。
// HEAD 即當前所在的分支
// : 冒號左邊是本地分支, 右邊是遠程分支, 那這裏的 huangsanyang/add_a_and_b 即爲遠程的分支名稱
// 完整的理解就是: 將本地 HEAD 的分支推向遠程倉庫名爲 huangsanyang/add_a_and_b 的分支
HEAD:huangsanyang/add_a_and_b
複製代碼
使用 git log --graph --decorate --all 查看日誌,這下多了點區別,能夠看到當前 HEAD 所在地方,右側還有一個紅色的 origin/huangsanyang/add_a_and_b, 這就是告訴咱們這是一個遠程分支, 從前面的 origin 就能夠看出。
再次回顧: 一次完整的推送代碼到遠程倉庫的流程爲: add -> commit -> push。 再次 看看 github 代碼倉庫,是否是已經包含了咱們的提交啦!說明已經正確將本地的代碼倉庫提交到遠程代碼倉庫。至關於作了一次遠程備份。
到了這兒,咱們就將從零新建項目到推送代碼到遠程服務器倉庫的流程啦!
拉取代碼和多人協做一塊兒講解,如今假定你是項目組長,你擁有這個代碼倉庫的全部權,你能夠刪除、指定誰能協助項目開發、審覈代碼、合併代碼。
這裏我掏出了我本身使用的電腦,做爲一個項目管理者的方式參與到協做開發中。由於我也是第一次克隆,各位請注意這是新的人員。因此你不是一我的在戰鬥....
老生常談:查看一下 log 日誌吧! 是否是和前面的 push 後同樣。
接着我開始開發個人功能,好比我新建了 123.txt
touch 123.txt
echo "123456" >> 123.txt
git add 123.txt
複製代碼
如今你還會忘記要幹嗎嗎?若是忘記就該撞牆去。 git commit -m "添加了 123.txt "
再來看看 log, 是否是當前的 HEAD 指向了 huangsanyang/add_a_and_b, 這個也就是當前的本地分支啦!你還會看到後面一個分支有一個 origin/HEAD, 這個告訴咱們遠程服務器的 HEAD 分支比咱們本地剛纔提交分支少了一個 123.txt 文件。也就是說前面的開發者是無法拿到 123.txt, 那若是要拿到該怎麼辦呢?
繼續提交吧!這一次提交是項目管理員,也是另外一個協做的開發者提交的代碼。
別慌,苟住。繼續來看 log 日誌。這裏我提交另外一個新的文件 123.txt, 推向了遠程服務器分支 huangxiaojing/add_123。
OK, 讓咱們回到前面的開發者,看他怎麼獲取最新的代碼。這就很天然的過多到了 git fetch
git fetch --all
複製代碼
sorry,可能仔細的你發現,我是用的是 git fetchall 而不是 git fetch --all, 那是由於我使用別名的方式簡化了拉取指令。別名在後面的 git 補充篇講解。
來看 log 日誌,是否是拿到最新的代碼了呢? 也就是管理員做者提交的代碼 123.txt。
能夠看到分支確實能看到了吧!不過你經過 ls 查看並無發現咱們想要的 123.txt。 那是由於你沒有留意的你本地的 HEAD 指向的是哪裏。能夠看到當前的 HEAD 是要早於 123.txt 以前提交的。因此確定沒有的。那怎麼辦?
啊哈!咱們就來看看怎麼把分支切換到最新的版本上去。引入了新的命令:
// checkout 切換分支
// 分支名: huangsanyang/fetch_123_txt,固然也能夠不指定,最好仍是帶上。這樣更好,更清晰
// 指定分支的哈希值: 這個前面說過,用來肯定惟一的提交記錄。
git checkout -b 分支名 指定分支的哈希值
複製代碼
來看 log 日誌, OK! 切換過來了吧!經過 ls 看看
通過上面的過程,你已經能夠和同事進行代碼交換啦!你能夠拿到同事的代碼,經過 fetch -> checkout。可是這樣其實也不是很好,咱們的代碼倉庫應該要有一個好的規範,在全部知名的 git 代碼管理的項目中,都會經過維護一個 master 分支來保證穩定的版本。 master 分支應該遵循的原則是,必定要保證能編譯經過,能正常部署運行。根據實際狀況也能夠增長 developer 分支來表示開發的過程的分支。那這裏是否是就出現了兩條分支了,一個是開發分支,一個是發佈分支。 這個時候項目管理員的做用就來了,他務必保證 master 分支的代碼必定是全部開發者的代碼合體、保證代碼穩定運行、代碼質量審查。
接下來就要引入稍微高階的內容:代碼合併、審查。
如今回到項目管理者,他首要的就是要保證代碼的 master 主幹分支是最新的。
很顯然不是,由於咱們並無看到 origin/master 是否在最後一次提交的分支。 這裏先執行 git push origin HEAD:master 建立出遠程 master 分支。
因爲沒有新的內容須要條,因此能夠看到 Total 爲 0。接着看看 log 日誌,各位再次強調一下,善於使用 log 能讓咱們清楚知道當前代碼庫的狀態。
如今看到 origin/master, 咱們已經建立出這樣一個用於項目發佈的分支。所以做爲管理員就要維護這個分支。接下來演示一次合併請求。也就是其餘的開發者,編寫了代碼提交到遠程非 master 的分支。開發者能夠設置遠程 master 分支爲保護分支,那麼別的開發者就不能往 master 推送代碼。
如今切換到普通開發者,編寫一個文件 utils.txt
touch utils.txt
echo "這是一個描述項目中使用工具的文件" >> utils.txt
git add utils.txt
複製代碼
這裏就再也不提供 git status 打印, 讀者自行使用查看。經過 commit -> push 以下:
能夠看到,開發者已經提交了新代碼而且提交了指定分支 origin/huangsanyang/push_utils。 能夠看出這樣的提交代碼風格很是好。由於讓項目管理者,能夠快速清晰的知道他幹了什麼。
讓咱們切回到項目管理者,來看看他是如何合併代碼的。請務必記住,必定要先執行 git fetch --all
git fetch -all
複製代碼
再看 log 日誌
到了這一步其實也是前面都用到的知識,知識不斷的軟磨硬泡,旨在讓小白變成一個真正的高手。固然若是你看完不練習,當我沒說。
在合併的時候,開發者應該要將分支切換到遠程 master 所在的地方,而後再合併別的開發的代碼。爲何要這樣,由於是將別的開發者代碼往 master 合併,而不是把 master 往開發者合併。要分清那個分支纔是最重要的分支。由於開發者寫的功能也許有問題。因此必定要注意。
合併的命令:
// merge 合併分支
// --no-ff 不要強制解決衝突,由合併者自行處理
git merge --no-ff 指定合併的分支
複製代碼
執行以下的合併指令:
git merge --no-ff c17c8f7e46b666ab84f3ba5b99efc57c1711baed
複製代碼
最終的 log 截圖, 請你仔細看看,分支走向發生了變化。能夠看到有一個分支合併到了 5df2ffb37f131f93fc1db775e1a7dd36674814c9 分支。
若是確認無誤,通過嚴格測試之後符合功能需求,再將其推送到遠程 master 分支。
再查看 log
好了,正常合併流程已經講完。可是你想一想,既然要成爲一個高手,若是不去解決點衝突,這能符合高手的常規操做嗎?
營造一個衝突環境,好比管理員開發的某個文件的一些代碼被另外一個開發者改掉,那麼開發者最終提交給管理員的代碼和原來管理員的代碼確定不一樣的。這樣是否是就要處理衝突了。
回到開發者,記得 fetch, 記得 checkout 切換分支。 而後修改一下 123.txt 文件, 能夠看到他將新增了一些文件,而且修改了原來 12345 改成 1234 sdf6。而後提交。
1234 sdf6
故人西辭富士康
爲學技術到藍翔
藍翔畢業包分配
尼瑪仍是富士康
複製代碼
來看看 log 日誌,能夠看到已經正確提交啦!
這個時候項目管理員就來合併代碼啦!記得 fetch, 記得切換到 master 分支。
接着再來執行
git merge --no-ff 348a5e9987981d34ceea031c9cf442bd0aaa7c3c
複製代碼
😄😄,你會發現並無衝突,哈哈這是否是很尷尬呀。 那是由於咱們是在 master 上將開發提交的分支往 master 合併。 而開發者實際上是包含了 master 的全部文件和記錄。所以此次合併是正常的。其實我就是爲了再一次鞏固一下合併代碼的流程。
其實衝突是多個開發者之間提交的代碼中可能都修改同一個文件,且各自的代碼都不一致。這個時候項目管理者就要作權衡,選擇最好的結果。舉個例子,如今代碼管理者對 123.txt 進行修改後提交,普通開發者也修改了 123.txt 並提交。
先來看看普通開發者的修改,請注意必定要拉取代碼 fetch, 而後 checkout。再次鞏固這個兩個命令的使用:
// 拉取遠程代碼倉庫的全部分支
git fetch --all
// checkout 切換, branc_name 有意義的分支名, hash: 當前分支的惟一標示
git checkout -b branch_name hash
複製代碼
而後使用文本編輯修改內容爲:
111111111111111
asdfasdfsa;dlf
故人西辭富士康
爲學技術到藍翔
藍翔畢業包分配
尼瑪仍是富士康
複製代碼
而後提交和推送代碼到遠程倉庫。再次回顧命令的使用:
// 將其加入到本地緩存
git add 123.txt
// 提交代碼到本地倉庫
git commit -m "修改了 123.txt 內容"
// 將代碼推送到遠程倉庫
git push origin HEAD
複製代碼
使用 log 查看,命令回顧:
git log --graph --decorate --all
複製代碼
不難看出,這一次提交要晚於遠程代碼倉庫的 master 分支的。
接下來看項目管理者的修改, 請注意,這裏並無將分支切換到開發者提交的分支上,而是在原來的老的分支上進行直接的修改。
看到下面的 log, 我沒有騙你,我確實是在老的分支上,而開發者新提交的代碼並無合併到 master
來看項目管理者修改內容變成了什麼,是否是和以前的徹底不同,而且將以前的所有改掉啦!
接着又是熟悉的步驟, add、commit、push
OK, 提交成功後,嘗試合併。並將最終分支合併到 master。
合併的命令回顧:
git merge --no-ff 被合併的分支
複製代碼
看到執行 merge 後的打印了嗎?
// 告訴咱們嘗試自動合併失敗,須要手動合併解決衝突
Automatic merge failed; fix conflicts and then commit the result.
複製代碼
OK, 這裏你應該選擇你最使用方便的編輯器來進行代碼的合併操做,好比你可使用 AS 自帶的 git 插件。筆者這裏使用的是 Emacs 的 git 插件。下面是本次合併信息,能夠看出來是分段的,第一、2 行表示當前的分支,三、4兩行表示要被合併的分支; 剩下的幾行表示有哪些文件修改須要被合併。
咱們進入到未合併的文件 123.txt, 能夠發現當前 HEAD 就是管理員提交的代碼,而下面的就是要被合併的開發者提交的代碼。
這裏我就直接選擇管理員的代碼做爲最終的代碼,在實際開發中,審覈着就是要承擔這樣的責任,須要合理的選擇誰提交的代碼可用,或者抽取各自好的代碼進行合併。
最終選擇的結果,能夠看到我刪除了開發者的代碼,並將輔助的信息所有刪除。好比有:
>> 開頭的
<< 開頭的
==== 開頭的
複製代碼
合併完成後又進入到熟悉的步驟, commit、push。看到下面的圖,能夠看到分支又被何在一塊兒,你能夠本身好好觀察下分支走向。那些分支合到那個分支上,只要看懂了,遇到再複雜的分支也不會暈頭轉向。
好啦, 寫到這兒就將整個 git 的常規操做所有講完了。讓咱們來再一次回顧一下,由於內容太長,爲了讓讀者能熟悉命令,看完後能記住大部分。我給你再總結一次。
寫在前面: 若是你的倉庫已經存在提交,你第一步就須要 fetch, 而後切換到最新的版本上去,通常是 master 所在的分支
git fetch --all
2. 切換到指定 hash 的分支
git checkout -b branch_name hash
3. 新建一個文件後,須要將其加入到緩衝區,稱爲追蹤文件
git add xxx
4. 將緩存去的文件加入到本地代碼倉庫
git commit -m "提交消息內容"
5. 提交到遠程倉庫
git push origin HEAD:branch_name
輔助命令:
1. 查看當前提交的狀態
git status
2. 查看日誌,分支樹
git log --graph --decorate --all
管理者使用:
1. merge 合併代碼,將指定分支合併到某一個分支,通常是 master
git merge --no-ff hash
複製代碼
其實上面的是最多見的幾個命令啦!基本上熟練使用這幾個指令就能完成大部分工做。筆者用的最多也是這幾個命令。下一篇做爲補充,再增長几個命令,雖然不經常使用,可是也要知道。