在之前的GIT入門介紹中,我們了解了本地一些GIT操作的指令和原理,在這一節将一起學習一下GIT遠端管理和版本管理的相關内容。
遠端倉庫
如果要在github上管理我們的代碼,并在本地進行修改送出就需要了解git 遠端倉庫的相關内容。github是git官方提供的一個代碼托管平台,個人可以申請免費的,但是所上傳的内容可以友善大家共享,如果要使用私密倉庫,需要付費。
在github上添加SSH KEY:
在github上注冊好賬戶之後,添加本機的SSH公鑰,這樣在本地在對遠端倉庫操作時就不用頻繁的使用賬号密碼。
1
<code>ssh</code><code>-keygen -t rsa -C </code><code>"[email protected]"</code>
一路預設回車之後,cat .ssh/id_rsa.pub ,然後将cat的内容添加到賬戶的SSH Key中。
建立第一個個人倉庫
首先在github上注冊一個個人賬戶,在New repository中直接輸入建立倉庫的名稱即可。根據提示使用SSH的方法在本地添加一個個人倉庫:
2
<code>git remote add origin [email protected]:YourName</code><code>/gitrepo</code><code>.git</code>
<code>git push -u origin master </code><code># -u更新所有分支 origin預設遠端倉庫名稱</code>
當第一次同步了所有的本地檔案之後,在對檔案做了commit,就可以直接使用:
<code>git push origin master</code>
這樣就直接将本地更新的檔案推到了遠端管理庫。
從遠端倉庫克隆
github上有很多很優秀的代碼和應用,如果我們要是用别人的代碼,直接可以用git clone指令将代碼拉到我們本地,如果是自己的代碼庫可以直接拉取:
git clone [email protected]:YourName/gitrepo.git
分支管理
在進行開發的過程中,很多情況下我們需要對分支進行管理。例如,如果是本地對一個檔案進行修改,那麼這個檔案就是線性的修改方式,如果要對多個檔案進行多次修改,而且不同的修改最終會确認一個最終的版本,最終合并的這個分支就是這個檔案的最終版本,需要注意的是,隻有當執行了commit 指令之後,本地的master分支才會建立。
建立并切換分支:
3
4
<code>git branche dev </code><code>#建立dev分支</code>
<code>git checkout dev </code><code>#切換分支到dev</code>
<code>===============</code>
<code>git checkout -b dev </code><code># 建立并切換分支, 一條指令搞定</code>
檢視分支:
<code>git branch</code>
對分支修改後git add , git commit 之後就可切換到master分支上合并。
合并dev到master分支:
<code>git merge dev</code>
删除分支:
<code>git branch -d dev</code>
當在兩個分支上同時修改了檔案并且送出後,在git合并時就會出現沖突的報錯。這是因為當我們在合并的時候程式也不知道我們到底需要更新哪一個,這就需要我們手動去更新檔案,解決沖突。然後再合并。
5
6
7
8
9
10
11
<code>[root@work gitrepo]</code><code># git merge test # 在master和test分支上都commit後,再merge會報錯</code>
<code>Auto-merging readme.txt</code>
<code>CONFLICT (content): Merge conflict </code><code>in</code> <code>readme.txt</code>
<code>Automatic merge failed; fix conflicts and </code><code>then</code> <code>commit the result.</code>
<code>[root@work gitrepo]</code><code># cat readme.txt </code>
<code>test</code>
<code><<<<<<< HEAD </code><code>#檢視編輯的檔案,系統對我們手動要修改的地方做了标注</code>
<code>this is master </code>
<code>=======</code>
<code>this is </code><code>test</code>
<code>>>>>>>> </code><code>test</code>
修改檔案統一後,再次執行git add 和git commit就可以解決沖突了:
<code>[root@work gitrepo]</code><code># git log --graph --pretty=oneline --abbrev-commit</code>
<code>* 52ed4df confilt</code>
<code>|\ </code>
<code>| * 310f7e7 IT </code><code># 顯示了一個分支的修改</code>
<code>* | a8fa78b master</code>
<code>|/ </code>
<code>* b040742 </code><code>test</code>
用git log --graph指令可以看到分支合并圖。
合并分支時,預設使用的是fast forward模式,但是使用這種模式是不記錄其它分支的修改日志的,在實際應用中,為了更加清楚分支上的修改時間,需要加上--no-ff參數,可以用普通模式合并,合并後的曆史有分支,能看出來曾經做過合并,而fast forward合并就看不出來曾經做過合并。
在一般的開發過程中大豆會有如下流程:
1、leader在遠端倉庫建立2個分支:master和dev
2、張三和李四克隆遠端倉庫到本地
3、張三和李四都切換到dev分支
4、張三建立分支z3,李四建立分支l4
5、開發完成後,張三合并z3到dev,李四合并l4到dev
6、張三和李四把本地庫的dev分支推送到遠端dev
7、leader拉取遠端庫裡的dev和masterd,在本地将dev合并到master 并推送到遠端master
BUG分支管理
如果目前正在dev分支上開發,突然線上出了一個BUG,需要立即修複,這時候我需要暫時隐藏目前的工作,也就是儲存目前dev分支上的進度 git statsh:
<code>[root@work gitrepo]</code><code># git stash</code>
<code>Saved working directory and index state WIP on dev: f241242 </code><code>test</code>
<code>HEAD is now at f241242 </code><code>test</code>
<code>[root@work gitrepo]</code><code># git status #隐藏工作區之後,顯示的工作目錄為空了</code>
<code># On branch dev</code>
<code>nothing to commit, working directory clean</code>
儲存了目前的工作後,我們就要去修複線上的bug了,切換到master分支,并建立一個修複的issue分支:
<code>[root@work gitrepo]</code><code># git checkout master</code>
<code>Switched to branch </code><code>'master'</code>
<code>[root@work gitrepo]</code><code># git checkout -b issue</code>
<code>Switched to a new branch </code><code>'issue'</code>
<code>[root@work gitrepo]</code><code># git branch</code>
<code> </code><code>dev</code>
<code>* issue</code>
<code> </code><code>master</code>
在issue上完成修複工作後,執行git add ,git commit 送出代碼,然後在master上合并issue分支上的代碼删除issue分支:
12
13
14
15
16
17
18
<code>[root@work gitrepo]</code><code># git add readme.txt </code>
<code>[root@work gitrepo]</code><code># git commit -m "fix issue"</code>
<code>[issue 8b29da7] fix issue</code>
<code> </code><code>1 </code><code>file</code> <code>changed, 1 insertion(+)</code>
<code> </code>
<code>[root@work gitrepo]</code><code># git checkout master # 回到master上合并issue分支</code>
<code>[root@work gitrepo]</code><code># git merge --no-ff -m "fix bug issue" issue # 記錄分支日志資訊</code>
<code>Merge made by the </code><code>'recursive'</code> <code>strategy.</code>
<code> </code><code>readme.txt | 1 +</code>
<code>[root@work gitrepo]</code><code># git branch -d issue #删除issue分支</code>
<code>Deleted branch issue (was 8b29da7).</code>
bug修複完成之後,我們要回到自己的dev分支繼續我們的工作了:
19
20
21
22
23
24
25
26
27
28
29
30
<code>[root@work gitrepo]</code><code># git checkout dev</code>
<code>Switched to branch </code><code>'dev'</code>
<code>[root@work gitrepo]</code><code># git status # 原來的dev分支是空的</code>
<code>[root@work gitrepo]</code><code># git stash list # 檢視我們隐藏的分支</code>
<code>stash@{0}: WIP on dev: f241242 </code><code>test</code>
<code>[root@work gitrepo]</code><code># git stash pop # 顯示出隐藏的分支,并将隐藏的分支删除</code>
<code># Changes not staged for commit:</code>
<code># (use "git add <file>..." to update what will be committed)</code>
<code># (use "git checkout -- <file>..." to discard changes in working directory)</code>
<code>#</code>
<code># modified: file.txt</code>
<code>no changes added to commit (use </code><code>"git add"</code> <code>and</code><code>/or</code> <code>"git commit -a"</code><code>)</code>
<code>Dropped refs</code><code>/stash</code><code>@{0} (5a7f46b8a24f1a557a37b0378ee75c65387e024a)</code>
<code>[root@work gitrepo]</code><code># git status</code>
恢複隐藏的分支有兩種方法:
git stash apply # 恢複隐藏的分支
git stash drop # 删除隐藏的分支記錄
============================
git statsh pop # 恢複隐藏的分支,并将隐藏的分支删除,用一條指令做上面兩條指令的事情。
tips:
如果要開發一個新的特性,最好建立一個分支,如果開發的新分支完成一半需要删除(此時還沒有送出)删除一個未送出的分支,可以使用git branch -D BranchName 強制删除。
多人協作分支管理
在進行多人協作開發的團隊中,由于每個人都會去不斷的修改檔案,合并檔案,就會出現當你想遠端送出自己的代碼時,碰巧别人也修改了相同的檔案,這樣你本地的檔案和遠端的檔案内容就不一樣了,需要手動解決沖突再進行送出。
<code>[root@work gitrepo]</code><code># git remote # 檢視遠端分支</code>
<code>origin</code>
<code>[root@work gitrepo]</code><code># git remote -v # 檢視遠端分支詳細資訊</code>
<code>origin [email protected]:AndySkyL</code><code>/gitrepo</code><code>.git (fetch)</code>
<code>origin [email protected]:AndySkyL</code><code>/gitrepo</code><code>.git (push)</code>
送出是出現沖突:
31
32
33
34
35
36
<code>[root@work gitrepo]</code><code># git commit -m "dev2"</code>
<code>[dev 41ad4f8] dev2</code>
<code> </code><code>1 </code><code>file</code> <code>changed, 1 insertion(+), 3 deletions(-)</code>
<code>[root@work gitrepo]</code><code># git push origin dev # 推送dev分支沖突</code>
<code>▽! [rejected] dev -> dev (fetch first)</code>
<code>error: failed to push some refs to </code><code>'[email protected]:AndySkyL/gitrepo.git'</code>
<code>hint: Updates were rejected because the remote contains work that you </code><code>do</code>
<code>hint: not have locally. This is usually caused by another repository pushing</code>
<code>hint: to the same ref. You may want to first merge the remote changes (e.g.,</code>
<code>hint: </code><code>'git pull'</code><code>) before pushing again.</code>
<code>hint: See the </code><code>'Note about fast-forwards'</code> <code>in</code> <code>'git push --help'</code> <code>for</code> <code>details.</code>
<code>[root@work gitrepo]</code><code># git pull # 根據提示使用git pull</code>
<code>remote: Counting objects: 3, </code><code>done</code><code>.</code>
<code>remote: Compressing objects: 100% (2</code><code>/2</code><code>), </code><code>done</code><code>.</code>
<code>remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0</code>
<code>Unpacking objects: 100% (3</code><code>/3</code><code>), </code><code>done</code><code>.</code>
<code>From github.com:AndySkyL</code><code>/gitrepo</code>
<code> </code><code>* [new branch] dev -> origin</code><code>/dev</code>
<code>There is no tracking information </code><code>for</code> <code>the current branch.</code>
<code>Please specify </code><code>which</code> <code>branch you want to merge with.</code>
<code>See git-pull(1) </code><code>for</code> <code>details</code>
<code> </code><code>git pull <remote> <branch> </code>
<code>If you wish to </code><code>set</code> <code>tracking information </code><code>for</code> <code>this branch you can </code><code>do</code> <code>so with:</code>
<code> </code><code>git branch --</code><code>set</code><code>-upstream-to=origin/<branch> dev </code><code># 這裡已經給出提示</code>
<code> </code>
<code>[root@work gitrepo]</code><code># git branch --set-upstream-to=origin/dev dev </code>
<code>Branch dev </code><code>set</code> <code>up to track remote branch dev from origin.</code>
<code>[root@work gitrepo]</code><code># git pull #執行此指令之後再按照之前的方式修改檔案,解決沖突</code>
解決沖突後送出:
<code>[root@work gitrepo]</code><code># git commit -m "fix m"</code>
<code>[dev 3267ad5] fix m</code>
<code>[root@work gitrepo]</code><code># git push origin dev</code>
<code>Counting objects: 10, </code><code>done</code><code>.</code>
<code>Compressing objects: 100% (4</code><code>/4</code><code>), </code><code>done</code><code>.</code>
<code>Writing objects: 100% (6</code><code>/6</code><code>), 570 bytes | 0 bytes</code><code>/s</code><code>, </code><code>done</code><code>.</code>
<code>Total 6 (delta 0), reused 0 (delta 0)</code>
<code> </code><code>17a9b60..3267ad5 dev -> dev</code>
從本地推送分支,使用git push origin branch-name,如果推送失敗,先用git pull抓取遠端的新送出;
在本地建立和遠端分支對應的分支,使用
<code>git checkout -b branch-name origin</code><code>/branch-name</code>
<code># 本地和遠端分支的名稱最好一緻;</code>
建立本地分支和遠端分支的關聯,使用:
<code>git branch --</code><code>set</code><code>-upstream-to=origin</code><code>/dev</code> <code>dev</code>
标簽管理
标簽可以是每一次commit 的辨別,類似于給每次commit添加一個别名:
<code>* master</code>
<code>[root@work gitrepo]</code><code># git tag v1.0</code>
<code>[root@work gitrepo]</code><code># git tag</code>
<code>v1.0</code>
預設标簽是打在最新送出的commit上的。
如果要對之前的某一次commit打标簽後面直接接上commit ID即可:
<code>[root@work gitrepo]</code><code># git log --pretty=oneline --abbrev-commit</code>
<code>e2ce160 fix bug issue</code>
<code>8b29da7 fix issue</code>
<code>881136a fix bug example</code>
<code>[root@work gitrepo]</code><code># git tag v0.9 881136a #根據log 對對應的commit打标簽,可以使用-m</code>
<code>[root@work gitrepo]</code><code># git tag #添加說明</code>
<code>v0.9 </code><code># git标簽的排列預設是以标簽名的字母順序排列的</code>
使用tag檢視具體資訊:
<code>[root@work gitrepo]</code><code># git show v1.0</code>
<code>commit e2ce160ad30d5433c033d9be7dc5dfe23ddbfd6d</code>
<code>Merge: 881136a 8b29da7</code>
<code>Author: trying <[email protected]></code>
<code>Date: Wed Dec 14 16:16:32 2016 +0800</code>
<code> </code><code>fix bug issue</code>
也可以在建立tag時添加說明:
<code> </code><code>git tag -a v2.0 -m </code><code>"version 2.0 released"</code> <code># -a 指定tag名稱 -m 添加說明</code>
删除标簽
<code># git tag -d v2.0</code>
<code>Deleted tag </code><code>'v2.0'</code> <code>(was 959f8b1)</code>
推送标簽到遠端
由于在本地添加的标簽不會自動推送到遠端,如果需要推送本地的标簽到遠端,使用git push origin tagname:
<code># git push origin v1.0 # 推送指定的tag</code>
<code># git push origin --tags # 一次推送所有的tag</code>
删除遠端标簽
删除遠端标簽需要先删除本地标簽:
<code># git tag</code>
<code>v0.9</code>
<code># git tag -d v0.9 # 删除本地tag</code>
<code>Deleted tag </code><code>'v0.9'</code> <code>(was 881136a)</code>
<code># git push origin :refs/tags/v0.9 # 删除遠端标簽</code>
<code> </code><code>- [deleted] v0.9</code>
git push origin :refs/tags/tagname
GIT高亮顯示字型顔色:
<code># git config --global color.ui true</code>
搭建GIT伺服器
如果自己不想使用github的付費倉庫,可以自己搭建一個私有的git 伺服器供企業内部使用。
安裝git:
<code>yum </code><code>install</code> <code>git -y</code>
建立一個git使用者:
<code>useradd</code> <code>git</code>
禁止git 使用者登入shell,編輯/etc/passwd檔案,将git使用者預設的shell改為:
<code>git:x:823:823::</code><code>/home/git</code><code>:</code><code>/usr/bin/git-shell</code>
建立一個用于GIT倉庫的目錄:
<code>mkdir</code> <code>/gitrepo</code>
<code>cd</code> <code>/gitrepo</code>
初始化git倉庫:
<code>git init --bare </code><code>test</code><code>.git</code>
在/home/git使用者的目錄下建立密鑰認證檔案authorized_keys ,将本地的公鑰導入服務端的authorized_keys 檔案中:
<code>cat</code> <code>id_rsa.pub > </code><code>/home/git/</code><code>.</code><code>ssh</code><code>/authorized_keys</code>
然回到本地,就可以擷取git伺服器上的工作目錄了:
<code>[root@work ~]</code><code># git clone [email protected]:/gitrepo/test.git</code>
<code>Cloning into </code><code>'test'</code><code>...</code>
<code>warning: You appear to have cloned an empty repository.</code>
這就可以和在github上一樣操作了。
本文轉自 酥心糖 51CTO部落格,原文連結:http://blog.51cto.com/tryingstuff/1883089