Git 是一種分布式版本控制系統,它可以不受網絡連接配接的限制,加上其它衆多優點,目前已經成為程式開發人員做項目版本管理時的首選,非開發人員也可以用 Git 來做自己的文檔版本管理工具。
<code>Git</code> 是一種分布式版本控制系統,它可以不受網絡連接配接的限制,加上其它衆多優點,目前已經成為程式開發人員做項目版本管理時的首選,非開發人員也可以用 <code>Git</code> 來做自己的文檔版本管理工具。
<code>Git</code> 不僅僅是個版本控制系統,它也是個内容管理系統(<code>CMS</code>),工作管理系統等。
如果你是一個具有使用 <code>SVN</code> 背景的人,你需要做一定的思想轉換,來适應 <code>Git</code> 提供的一些概念和特征。
<code>Git</code> 與 <code>SVN</code> 差別點:
<code>Git</code> 是分布式的,<code>SVN</code> 不是:這是 <code>Git</code> 和其它非分布式的版本控制系統,例如 <code>SVN</code>,<code>CVS</code> 等,最核心的差別。
<code>Git</code> 把内容按中繼資料方式存儲,而 <code>SVN</code> 是按檔案:所有的資源控制系統都是把檔案的元資訊隐藏在一個類似 <code>.svn</code>、<code>.cvs</code> 等的檔案夾裡。
<code>Git</code> 分支和 <code>SVN</code> 的分支不同:分支在 <code>SVN</code> 中一點都不特别,其實它就是版本庫中的另外一個目錄。
<code>Git</code> 沒有一個全局的版本号,而 <code>SVN</code> 有:目前為止這是跟 <code>SVN</code> 相比 <code>Git</code> 缺少的最大的一個特征。
<code>Git</code> 的内容完整性要優于 <code>SVN</code> :<code>Git</code> 的内容存儲使用的是 <code>SHA-1</code> 雜湊演算法。這能確定代碼内容的完整性,確定在遇到磁盤故障和網絡問題時降低對版本庫的破壞。
版本控制(<code>Revision control</code>)是一種在開發的過程中用于管理我們對檔案、目錄或工程等内容的修改曆史,友善檢視更改曆史記錄,備份以便恢複以前的版本的軟體工程技術。一句話就是用于管理多人協同開發項目的技術。
優點
實作跨區域多人協同開發;
追蹤和記載一個或者多個檔案的曆史記錄;
組織和保護你的源代碼和文檔;
統計工作量;
并行開發、提高開發效率;
跟蹤記錄整個軟體的開發過程;
減輕開發人員的負擔,節省時間,同時降低人為錯誤。
工作區:就是你在電腦裡能看到的目錄。
版本庫:工作區有一個隐藏目錄 <code>.git</code>,這個不算工作區,而是 <code>Git</code> 的版本庫。
暫存區:本地版本庫裡存了很多東西,其中最重要的就是稱為 <code>stage</code>(或者叫index)的暫存區。
下面這個圖展示了工作區、版本庫中的暫存區和版本庫之間的關系:

分支是為了将修改記錄的整個流程分開存儲,讓分開的分支不受其它分支的影響,是以在同一個資料庫裡可以同時進行多個不同的修改。
主分支(Master)
是 Git 為我們自動建立的第一個分支,也叫主分支,其它分支開發完成後都要合并到 master
分支合并(Merge)
将某分支上的更改聯接到此主幹或同為主幹的另一個分支。
合并沖突(Conflict)
多人對同一檔案的工作副本進行更改,并将這些更改送出到倉庫。
标簽是用于标記特定的點或送出的曆史,通常會用來标記釋出版本的名稱或版本号(如:<code>publish/0.0.1</code>),雖然标簽看起來有點像分支,但打上标簽的送出是固定的,不能随意的改動。
頭是一個象征性的參考,最常用以指向目前選擇的分支。
程式員進行開發改動的地方,是你目前看到的,也是最新的;
平常我們開發就是拷貝遠端倉庫中的一個分支,基于該分支進行開發。在開發過程中就是對工作區的操作。
<code>.git</code> 目錄下的 <code>index</code> 檔案, 暫存區會記錄 <code>git add</code> 添加檔案的相關資訊(檔案名、大小、<code>timestamp</code>...),不儲存檔案實體, 通過 <code>id</code> 指向每個檔案實體。可以使用 <code>git status</code> 檢視暫存區的狀态。暫存區标記了你目前工作區中,哪些内容是被 <code>Git</code> 管理的;
當你完成某個需求或功能後需要送出到遠端倉庫,那麼第一步就是通過<code>git add</code> 先送出到暫存區,被 <code>Git</code> 管理。
儲存了對象被送出 過的各個版本,比起工作區和暫存區的内容,它要更舊一些;
<code>git commit</code> 後同步 <code>index</code> 的目錄樹到本地倉庫,友善從下一步通過 <code>git push</code> 同步本地倉庫與遠端倉庫的同步。
遠端倉庫的内容可能被分布在多個地點的處于協作關系的本地倉庫修改,是以它可能與本地倉庫同步,也可能不同步,但是它的内容是最舊的。
任何對象都是在工作區中誕生和被修改;
任何修改都是從進入 index 區才開始被版本控制;
隻有把修改送出到本地倉庫,該修改才能在倉庫中留下痕迹;
與協作者分享本地的修改,可以把它們 push 到遠端倉庫來共享。
版本控制就是對檔案的版本控制:首先要知道檔案目前在什麼狀态,然後才能對檔案進行修改、送出等操作,不然可能會送出了現在還不想送出的檔案。
<code>Untracked</code>: 未跟蹤, 此檔案在檔案夾中, 但并沒有加入到 <code>Git</code> 庫, 不參與版本控制.通過 <code>git add</code> 狀态變為 <code>Staged</code>;
<code>Unmodify</code>: 檔案已經入庫, 未修改, 即版本庫中的檔案快照内容與檔案夾中完全一緻. 這種類型的檔案有兩種去處, 如果它被修改, 而變為 <code>Modified.</code> 如果使用 <code>git rm</code> 移出版本庫, 則成為 <code>Untracked</code> 檔案;
<code>Modified</code>: 檔案已修改, 僅僅是修改, 并沒有進行其他的操作. 這個檔案也有兩個去處,通過 <code>git add</code> 可進入暫存 <code>staged</code> 狀态, 使用 <code>git checkout</code>則丢棄修改過, 傳回到 <code>unmodify</code> 狀态, 這個 <code>git checkout</code> 即從庫中取出檔案, 覆寫目前修改;
<code>Staged</code>: 暫存狀态.執行 <code>git commit</code> 則将修改同步到庫中, 這時庫中的檔案和本地檔案又變為一緻, 檔案為 <code>Unmodify</code> 狀态. 執行 <code>git reset HEAD filename</code> 取消暫存, 檔案狀态為 <code>Modified</code>。
此外,還有以下兩個常用指令:
使用情景
該檔案已經存在倉庫中,工作區已經對其進行修改過了,如果想撤銷修改,可以使用 <code>checkout</code>。
檢出指令git checkout 是 git 最常用的指令之一,同時也是一個很危險的指令,因為折騰指令會重寫工作區。
通過 <code>add</code> 隻是将檔案或者目錄添加到 <code>index</code> 即暫存區,使用 <code>commit</code> 可以實作将暫存區的檔案送出到本地倉庫。
撤銷暫存區更新
撤銷本地倉庫更新
放棄工作區和暫存區的改動,同時 <code>HEAD</code> 指針指向前一個 <code>commit</code> 對象:
<code>Git</code> 配置檔案有三個級别,分别是系統級别、全局級别以及倉庫級别。下面的表格展示了各個級别的配置的具體資訊:
配置級别
檔案位置
配置指令
優先級别
系統
Git 安裝目錄\etc\gitconfig
git config --system
低
全局
使用者檔案夾.gitconfig
git config --global
中
倉庫
倉庫檔案夾.git\config
git config --local
高
對全局的 <code>Git</code> 使用者名和郵箱進行配置
檢視所有配置或某一項配置:
系統和目前項目的指令同上,僅需将<code>global</code>改為<code>system</code>/<code>local</code>即可。
建立本地倉庫的方法有兩種:一種是建立全新的倉庫,另一種是克隆遠端倉庫。
使用目前目錄作為 <code>Git</code> 倉庫
隻需使它初始化:<code>git init</code> ;執行後可以看到,僅僅在項目目錄多出了一個<code>.git</code> 目錄;
使用指定目錄作為 <code>Git</code> 倉庫
使用如下指令,可以把建立目錄與倉庫一起完成:
将遠端伺服器上的倉庫完全鏡像一份至本地,而不是取某一個特定版本,是以用 <code>clone</code> 而不是 <code>checkout</code>,文法格式為:
例如:我們要從克隆的遠端倉庫托管在 <code>Github</code> 上,首先,我們先前往 <code>Github</code> 上拷貝位址如:
https://github.com/vanDusty/Java-Note,然後執行:
這個初始化後的倉庫,當建立完分支 <code>dev-branch</code>,并 <code>push</code> 後的目錄結構:
<code>branches</code> 目錄
一種不常用的存儲速記方式,用于指定 <code>git fetch</code> ,<code>git pull</code> 和 <code>git push</code> 的 <code>URL</code> ,目前已基本不用。
<code>COMMIT_EDITMSG</code> 檔案
<code>commit</code> 編輯資訊,僅記錄最近一次送出的 <code>commit</code> 編輯資訊。
<code>config</code> 檔案
存儲目前倉庫的配置資訊
<code>description</code> 檔案
用于在 <code>GitWeb</code> 中展示項目的描述資訊。
<code>HEAD</code> 檔案
存儲 HEAD 指針,指向目前分支,即:記錄目前活動分支。
<code>hooks</code> 目錄
目錄下存儲了許多鈎子檔案(一些腳本),這些檔案是各種 <code>Git</code> 指令使用的自定義腳本,可以在 <code>Git</code> 特定階段自動執行。
<code>index</code> 檔案
暫存區(<code>stage</code>),二進制檔案。
<code>info</code> 目錄
存儲庫的其他資訊将記錄在此目錄中。
<code>logs</code> 目錄
儲存所有更新的引用記錄。
<code>objects</code> 目錄
簡單了解就是:<code>objects</code> 目錄是 <code>Git</code> 的資料庫,存儲所有資料内容。
<code>refs</code> 目錄
(1)<code>heads</code> 目錄
目錄有以各個本地分支名命名的檔案,儲存對應分支最新送出的 <code>ID</code>,是通過 <code>SHA1</code> 算法計算的一個字元串。
(2)<code>remotes</code> 目錄
目錄有以各個遠端分支名命名的檔案,儲存對應分支最新送出的 <code>ID</code>,和 <code>heads</code> 目錄一個原理。
(3)<code>tags</code> 目錄
存儲在開發過程中打的标簽,裡面的檔案以标簽名指令,檔案内容為對應的 <code>ID</code> 。
Git 是分布式版本控制系統,同一個 <code>Git</code> 倉庫,可以分布到不同的機器上,即釋出到不同的遠端倉庫上。
GitHub
對,就是那個“全世界最大同性交友網站”。https://github.com
絕大多數好的開源項目都來自 GitHub,但是 GitHub 隻能建立公開的 Git 倉庫,私有倉庫要收費,有時候通路比較卡,如果你做的是一個開源項目,可以首選 GitHub。
Gitlab
提到 GitHub 就會自然的想到 Gitlab,Gitlab 支援無限的公有項目和私有項目。https://about.gitlab.com
Bitbucket
Bitbucket免費支援 5 個開發成員的團隊建立無限私有代碼托管庫。https://bitbucket.org
Gitee 碼雲
前面說的都是國外的,下面來說幾個國内的。碼雲,個人開發者可免費建立 1000 個項目(不限公有、私有),提供最多 5G 的免費代碼存儲空間。http://git.oschina.net,
Coding.net
談到 Coding.net,首先必須提的是速度快,同樣一個賬号最多可以建立 1000 個項目(5 個私有),也支援任務的建立等。https://coding.net
申請到了 <code>Git</code> 遠端倉庫的帳号并建立了一個空的遠端倉庫現在我們就可以結合本地的倉庫與遠端倉庫一起協同工作了,多人協同開發,這也是我們工作時的情形,這裡我們全部使用指令完成(實際開發中很多開發工具例如:<code>IDEA</code> 等,無需指令操作)。
克隆項目
遠端操作的第一步,通常是從遠端主機克隆一個版本庫,這時就要用到 <code>git clone</code> 指令,例如:
該指令會在本地主機生成一個目錄,與遠端主機的版本庫同名。如果要指定不同的目錄名,可以将目錄名作為 <code>git clone</code> 指令的第二個參數。
git clone 支援多種協定 除了 <code>HTTP(s)</code>以外,還支援 <code>SSH</code>、<code>Git</code>、本地檔案協定等。通常來說,<code>Git</code> 協定下載下傳速度最快,<code>SSH</code> 協定用于需要使用者認證的場合。各種協定優劣的詳細讨論請參考官方文檔。
<code>git remote</code>
為了便于管理,<code>Git</code> 要求每個遠端主機都必須指定一個主機名。<code>git remote</code> 指令就用于管理主機名。
不帶選項的時候, <code>git remote</code> 指令列出所有遠端主機名。
結果表示,目前隻有一台遠端主機,叫做 <code>origin</code>,以及它的網址。
克隆版本庫的時候,所使用的遠端主機自動被 <code>Git</code> 命名為 <code>origin</code> 。如果想用其他的主機名,需要用 <code>git clone</code> 指令的 <code>-o</code> 選項指定:
上面指令表示,克隆的時候,指定遠端主機叫做 <code>dusty</code>
更多指令如下:
<code>git fetch</code>
一旦遠端主機的版本庫有了更新,需要将這些更新取回本地,這時就要用到該指令。
所取回的更新,在本地主機上要用"遠端主機名/分支名"的形式讀取。比如 <code>origin</code> 主機的 <code>master</code>,就要用 <code>origin/master</code> 讀取。
也可以使用 <code>git merge</code> 指令或者 <code>git rebase</code> 指令,在本地分支上合并遠端分支。
<code>git pull</code>
<code>git pull</code> 指令的作用是,取回遠端主機某個分支的更新,再與本地的指定分支合并。它的完整格式稍稍有點複雜。
示例:取回 <code>origin</code> 主機的 <code>master</code> 分支,與本地的 <code>develop</code> 分支合并:
如果遠端分支( <code>master</code>)要與目前分支合并,則冒号後面的部分可以省略。可以簡寫為:
上面指令表示,取回 <code>origin/master</code> 分支,再與目前分支合并。實質上,這等同于先做 <code>git fetch</code> ,再做 <code>git merge</code> 。
<code>git fetch</code> 和 <code>git pull</code> 的差別
偷個懶,發現一個很全的【Git常用指令參考手冊】