Git高階使用教程
Git 與 SVN 區別
Git是一個開源的分散式版本控制系統,用於敏捷高效地處理任何或小或大的專案。Git 是 Linus Torvalds 為了幫助管理 Linux 核心開發而開發的一個開放原始碼的版本控制軟體。Git 與常用的版本控制工具 CVS, Subversion 等不同,它採用了分散式版本庫的方式,不必伺服器端軟體支援。
GIT不僅僅是個版本控制系統,它也是個內容管理系統(CMS),工作管理系統等。如果你是一個具有使用SVN背景的人,你需要做一定的思想轉換,來適應GIT提供的一些概念和特徵。Git 與 SVN 區別點:
1、GIT是分散式的,SVN不是:這是GIT和其它非分散式的版本控制系統,例如SVN,CVS等,最核心的區別。
2、GIT把內容按元資料方式儲存,而SVN是按檔案:所有的資源控制系統都是把檔案的元資訊隱藏在一個類似.svn,.cvs等的資料夾裡。
3、GIT分支和SVN的分支不同:分支在SVN中一點不特別,就是版本庫中的另外的一個目錄。
4、GIT沒有一個全域性的版本號,而SVN有:目前為止這是跟SVN相比GIT缺少的最大的一個特徵。
5、GIT的內容完整性要優於SVN:GIT的內容儲存使用的是SHA-1雜湊演算法。這能確保程式碼內容的完整性,確保在遇到磁碟故障和網路問題時降低對版本庫的破壞。
Git工作原理
Git工作流程可以分一下步驟:
- 克隆 Git 資源作為工作目錄;
- 在克隆的資源上新增或修改檔案;
- 如果其他人修改了,你可以更新資源;
- 在提交前檢視修改。提交修改;
- 在修改完成後,如果發現錯誤,可以撤回提交併再次修改並提交;
Git 工作區、暫存區和版本庫:
- 工作區:就是你在電腦裡能看到的目錄。
- 暫存區:英文叫stage, 或index。一般存放在"git目錄"下的index檔案(.git/index)中,所以我們把暫存區有時也叫作索引(index)。
- 版本庫:工作區有一個隱藏目錄.git,這個不算工作區,而是Git的版本庫。
常見操作
全域性配置使用者資訊
git config --global user.name "smyhvae" git config --global user.email "[email protected]"
Git 建立倉庫
git init repository
如果當前目錄下有幾個檔案想要納入版本控制,需要先用 git add 命令告訴 Git 開始對這些檔案進行跟蹤,然後提交:
$ git add *.c
$ git add README
$ git commit -m 'initial project version'
從現有倉庫克隆
$ git clone git://github.com/test/test.git
Git基本操作命令
git init
建立專案命令,在目錄中建立新的 Git 倉庫。 你可以在任何時候、任何目錄中這麼做,完全是本地化的。在目錄中執行 git init,就可以建立一個 Git 倉庫。
$ mkdir test
$ cd test
$ git init
git clone
使用 git clone 拷貝一個 Git 倉庫到本地,讓自己能夠檢視該專案,或者進行修改。
$ git clone git://github.com/test/test.git
gitpush
其作用是將本地分支的更新推送到遠端主機
$ git push <遠端主機名> <本地分支名>:<遠端分支名>
gitpull
其作用是將遠端主機更新到本地分支
$ git pull <遠端主機名> <本地分支名>:<遠端分支名>
git add
git add 命令可將該檔案新增到快取,如我們新增以下兩個檔案:
$ touch README
$ touch hello.php
$ ls
README hello.php
$ git status -s
?? README
?? hello.php
$
git status
命令用於檢視專案的當前狀態
$ git add README hello.php
$ git status -s
A README
A hello.php
$
git diff
git diff 命令顯示已寫入快取與已修改但尚未寫入快取的改動的區別。git diff 有兩個主要的應用場景:
尚未快取的改動:git diff
檢視已快取的改動: git diff --cached
檢視已快取的與未快取的所有改動:git diff HEAD
顯示摘要而非整個 diff:git diff --stat
$ git status -s
A README
AM hello.php
$ git diff
diff --git a/hello.php b/hello.php
git commit
使用 git add 命令將想要快照的內容寫入了快取, 而執行 git commit 記錄快取區的快照。Git 為你的每一個提交都記錄你的名字與電子郵箱地址,所以第一步需要配置使用者名稱和郵箱地址。
$ git config --global user.name 'admin'
$ git config --global user.email [email protected]
$ git add hello.php
$ git status -s
A README
A hello.php
$ git commit -m 'test comment from test.cn'
[master (root-commit) 85fc7e7] test comment from test.cn
2 files changed, 4 insertions(+)
create mode 100644 README
create mode 100644 hello.php
現在我們已經記錄了快照。如果我們再執行 git status:
$ git status
# On branch master
nothing to commit (working directory clean)
git log
檢視歷史提交記錄
$ git log
commit 88afe0e02adcdfea6844bb627de97da21eb10af1
Merge: 14b4dca d7e7346
Author: admin
Date: Sun Mar 1 15:03:42 2020 +0800
Merge branch 'change_site'
Conflicts:
test.txt
commit 14b4dcadbdc847207651d5a9fae0d315057f346e
Author: admin
Date: Sun Mar 1 14:53:15 2015 +0800
git tag
可以使用 git tag 給打上標籤
git reset HEAD
命令用於取消快取已快取的內容。
$ git status -s
M README
M hello.php
$ git add .
$ git status -s
M README
M hello.pp
$ git reset HEAD -- hello.php
Unstaged changes after reset:
M hello.php
$ git status -s
M README
M hello.php
git rm
將檔案從快取區中移除。
$ git rm hello.php
rm 'hello.php'
$ ls
README
git mv
命令做得所有事情就是 git rm --cached, 重新命名磁碟上的檔案,然後再執行 git add 把新檔案新增到快取區。因此,雖然有 git mv 命令,但它有點多餘 。
分支的合併
場景:基於master分支的程式碼,開發一個新的特性
如果你直接在master分支上開發這個新特性,是不好的,萬一你在開發特性1
的時候,領導突然又要叫你去開發特性2
,就不好處理了。難道開發的兩個特性都提交到master?一會兒提交特性1的commit,一會兒提交特性2的commit?這會導致commit記錄很混亂。
所以,我給你的建議做法是:給每個特性都單獨建一個的新的分支。
比如說,我專門給特性1
建一個分支feature_item_recommend
。具體做法如下:
(1)基於master分支,建立一個新的分支,起名為feature_item_recommend
:
$ git checkout -b feature_item_recommend
Switched to a new branch 'feature_item_recommend'
上面這行命令,相當於:
$ git branch feature_item_recommend // 建立新的分支
$ git checkout feature_item_recommend //切換到新的分支
(2)在新的分支feature_item_recommend
上,完成開發工作,並 commit 、push。
(3)將分支feature_item_recommend
上的開發進度合併到master分支:
$ git checkout master //切換到master分支
$ git merge feature_item_recommend //將分支 feature_item_recommend 的開發進度合併到 master 分支
合併之後,master
分支和feature_item_recommend
分支會指向同一個位置。
(3)刪除分支feature_item_recommend
:
既然 特性1 開發完了,也放心地提交到master了,那我們就可以將這個分支刪除了。
git branch -d feature_item_recommend
注意,我們當前是處於master
分支的位置,來刪除feature_item_recommend
分支。如果當前是處於feature_item_recommend
分支,是沒辦法刪除它自己的。
同理,當我轉身去開發特性2
的時候,也是採用同樣的步驟。
合併分支時,如果存在分叉
比如說上面這張圖中,最早的時候,master分支是位於C2
節點。我基於C2
節點,new出一個新的分支iss53
,我在iss53
上提交了好幾個commit。
現在,我準備把iss53
上的幾個commit合併到master上,此時發現,master分支已經前進到C4了。那該怎麼合併呢?
合併的命令仍然是:
$ git checkout master
$ git merge iss53
解釋:
這次合併的實現,並不同於簡單的併入方式。這一次,我的開發歷史是從更早的地方開始分叉的。
由於當前 master 分支所指向的commit (C4)並非想要併入分支(iss53)的直接祖先,Git 不得不進行一些處理。就此例而言,Git 會用兩個分支的末端(C4 和C5)和它們的共同祖先(C2)進行一次簡單的三方合併計算。
Git 沒有簡單地把分支指標右移,而是對三方合併的結果作一新的快照,並自動建立一個指向它的commit(C6)(如下圖所示)。我們把這個特殊的commit 稱作合併提交(mergecommit),因為它的祖先不止一個。
值得一提的是Git 可以自己裁決哪個共同祖先才是最佳合併基礎;這和CVS 或Subversion(1.5 以後的版本)不同,它們需要開發者手工指定合併基礎。所以此特性讓Git 的合併操作比其他系統都要簡單不少。
解決合併時發生的衝突
如果 feature1和feature2修改的是同一個檔案中程式碼的同一個位置,那麼,把feature1合併到feature2時,就會產生衝突。這個衝突需要人工解決。步驟如下:
(1)手動修改檔案:手動修改衝突的那個檔案,決定到底要用哪個分支的程式碼。
(2)git add:解決好衝突後,輸入git status
,會提示Unmerged paths
。這個時候,輸入git add
即可,表示:修改衝突成功,加入暫存區。
(3)git commit 提交。
然後,我們可以繼續把 feature1 分支合併到 master分支,最後刪除feature1、feature2。
注意:兩個分支的同一個檔案的不同地方合併時,git會自動合併,不會產生衝突。
比如分支feture1對index.html原來的第二行之前加入了一段程式碼。
分支feature2對index.html在原來的最後一行的後面加入了一段程式碼。
這個時候在對兩個分支合併,git不會產生衝突,因為兩個分支是修改同一檔案的不同位置。
git自動合併成功。不管是git自動合併成功,還是在人工解決衝突下合併成功,提交之前,都要對程式碼進行測試。
日常操作積累
修改密碼(曲線救國)
網上查了很久,沒找到答案。最終,在cld童鞋的提示下,採取如下方式進行曲線救國。
# 設定當前倉庫的使用者名稱為空
git config user.name ""
然後,當我們再輸入git pull
等命令列時,就會被要求重新輸入新的賬號密碼。此時,密碼就可以修改成功了。最後,我們還要輸入如下命令,還原當前倉庫的使用者名稱:
git config user.name "smyhvae"
修改已經push的某次commit的作者資訊
已經push的記錄,如果要修改作者資訊的話,只能 通過--force命令。
將 branch1
的某個commit1
合併到branch2
當中
切換到branch2中,然後執行如下命令:
git cherry-pick commit1
20200118-修改GitHub已提交的使用者名稱和郵箱
在執行./email.sh
後,如果出現permission denied
的錯誤,可以先執行chmod 777 email.sh
,修改檔案的許可權。
20200520-將Git 專案遷移到另一個倉庫
我們假設舊倉庫的專案名稱叫old-repository
,新倉庫的專案名稱叫new-repository
。操作如下:
(1)建立舊倉庫的裸克隆:
git clone --bare https://github.com/exampleuser/old-repository.git
執行上述命令後,會在本地生成一個名叫 old-repository.git
的資料夾。
(2)遷移到新倉庫:
cd old-repository.git
git push --mirror https://github.com/exampleuser/new-repository.git
這樣的話,專案就已經遷移到新倉庫了。
注意,我們不需要手動新建一個空的新倉庫,當我們執行上述命令之後,新倉庫就已經自動建立好了。
參考連結:
Git 伺服器搭建
我們將以 Centos 為例搭建 Git 伺服器。
1、安裝Git
$ yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel perl-devel
$ yum install git
建立一個git使用者組和使用者,用來執行git服務:
$ groupadd git
$ adduser git -g git
2、建立證書登入
收集所有需要登入的使用者的公鑰,公鑰位於id_rsa.pub檔案中,把我們的公鑰匯入到/home/git/.ssh/authorized_keys檔案裡,一行一個。如果沒有該檔案建立它:
$ cd /home/git/
$ mkdir .ssh
$ chmod 700 .ssh
$ touch .ssh/authorized_keys
$ chmod 600 .ssh/authorized_keys
3、初始化Git倉庫
首先我們選定一個目錄作為Git倉庫,假定是/home/gitrepo/hello.git,在/home/gitrepo目錄下輸入命令:
$ cd /home
$ mkdir gitrepo
$ chown git:git gitrepo/
$ cd gitrepo
$ git init --bare hello.git
Initialized empty Git repository in /home/gitrepo/hello.git/
以上命令Git建立一個空倉庫,伺服器上的Git倉庫通常都以.git結尾。然後,把倉庫所屬使用者改為git:
$ chown -R git:git w3cschoolcn.git
4、克隆倉庫
$ git clone [email protected]:/home/gitrepo/w3cschoolcn.git
Cloning into 'w3cschoolcn'...
warning: You appear to have cloned an empty repository.
Checking connectivity... done.
192.168.45.4 為 Git 所在伺服器 ip ,你需要將其修改為你自己的 Git 服務 ip。這樣我們的 Git 伺服器安裝就完成了,接下來我們可以禁用 git 使用者通過shell登入,可以通過編輯/etc/passwd檔案完成。找到類似下面的一行:
git:x:503:503::/home/git:/bin/bash
改為:git:x:503:503::/home/git:/sbin/nologin
Git客戶端推薦
TortoiseGit
對這隻小烏龜估計沒有開發人員會不認識,SVN的超廣泛使用也使得這個超好用的Svn客戶端成了幾乎每個開發人員的桌面必備軟體。小烏龜只提供Windows版本,提供中文版支援的,對於中國的開發者來說者絕對是福音。
小烏龜的檔案管理器右鍵選單的操作方式對於新手來說非常的容易上手,而且容易理解。
TortoiseGit(git客戶端工具)
Sublime Merge for Mac(git客戶端工具)
擁有簡潔的介面,三向合併工具,強大搜索功能,語法突出顯示等特點,Sublime Merge for Mac是一款Git客戶端工具,完成了Sublime。與Sublime Text的製造商會面。一個快速的使用者介面,三向合併工具,並排差異,語法高亮等等。Stage Files,iSwiftHunks和Lines沒有等待 – Sublime Merge真的非常非常快。
Sublime Merge for Mac(git客戶端工具)
GitHub for Desktop
全球開發人員交友俱樂部提供的強大工具,功能完善,使用方便。對於使用GitHub的開發人員來說是非常便捷的工具。介面乾淨,用起來非常順手,上面的這條timeline非常漂亮,也可以直接提交PR。
唯一讓我失望的是GitHub for Desktop不帶三方合併工具,你必須自己手動解決衝突才可以。– 免費
– 同時支援 Windows 和 Mac:對於需要經常在不同的作業系統間切換的開發人員來說非常方便。
– 漂亮的介面:作為每天盯著看的工具,顏值是非常重要的
– 支援Pull Request:直接從客戶端提交PR,很方便
– Timeline 支援:直接在時間線上顯示每次提交的時間點和大小
– 支援git LFS:儲存大檔案更加節省空間和高效
– 不支援三方合併:需要藉助第三方工具才行
Source Tree
SourceTree是老牌的Git GUI管理工具了,也號稱是最好用的Git GUI工具。我的體驗是確實強大,功能豐富,基本操作和高階操作都設計得非常流暢,適合初學者上手。
這個工具很有特色的一個功能就是支援Git Flow,你可以一鍵建立Git Flow的工作流。Git Flow是非常高效的團隊協作模型和流程,Git的一大特色就是靈活輕量的分支,但如何在自己的團隊中用好這個功能來匹配自己的研發流程是個問題。內建Git Flow讓那些不太熟悉的開發人員也可以很快上手,並且將研發的業務流程固化在工具中,可以說是非常貼心的設計。
SmartGit:
商業用途收費, 個人使用者免費:
推薦書籍
- 《pro.git中文版》