一篇文章,教你學會Git
在日常工作中,經常會用到 Git 操作。但是對於新人來講,剛上來對 Git 很陌生,操作起來也很懵逼。本篇文章主要針對剛開始接觸 Git 的新人,理解 Git 的基本原理,掌握常用的一些命令。
一、Git 工作流程
以上包括一些簡單而常用的命令,但是先不關心這些,先來了解下面這 4 個專有名詞。
- Workspace:工作區
- Index / Stage:暫存區
- Repository:倉庫區(或本地倉庫)
- Remote:遠端倉庫
工作區
程式設計師進行開發改動的地方,是你當前看到的,也是最新的。
平常我們開發就是拷貝遠端倉庫中的一個分支,基於該分支進行開發。在開發過程中就是對工作區的操作。
暫存區
.git 目錄下的 index 檔案, 暫存區會記錄git add
新增檔案的相關資訊 (檔名、大小、timestamp...),不儲存檔案實體, 通過 id 指向每個檔案實體。可以使用git status
檢視暫存區的狀態。暫存區標記了你當前工作區中,哪些內容是被 git 管理的。
當你完成某個需求或功能後需要提交到遠端倉庫,那麼第一步就是通過git add
先提交到暫存區,被 git 管理。
本地倉庫
儲存了物件被提交 過的各個版本,比起工作區和暫存區的內容,它要更舊一些。
git commit
後同步 index 的目錄樹到本地倉庫,方便從下一步通過git push
同步本地倉庫與遠端倉庫的同步。
遠端倉庫
遠端倉庫的內容可能被分佈在多個地點的處於協作關係的本地倉庫修改,因此它可能與本地倉庫同步,也可能不同步,但是它的內容是最舊的。
小結
- 任何物件都是在工作區中誕生和被修改;
- 任何修改都是從進入 index 區才開始被版本控制;
- 只有把修改提交到本地倉庫,該修改才能在倉庫中留下痕跡;
- 與協作者分享本地的修改,可以把它們 push 到遠端倉庫來共享。
下面這幅圖更加直接闡述了四個區域之間的關係,可能有些命令不太清楚,沒關係,下部分會詳細介紹。
二、常用 Git 命令
上找了個圖,別人整理的一張圖,很全很好,借來用下。下面詳細解釋一些常用命令。
HEAD
在掌握具體命令前,先理解下 HEAD。
HEAD,它始終指向當前所處分支的最新的提交點。你所處的分支變化了,或者產生了新的提交點,HEAD 就會跟著改變。
add
add 相關命令很簡單,主要實現將工作區修改的內容提交到暫存區,交由 git 管理。
git add . |
添加當前目錄的所有檔案到暫存區 |
---|---|
git add <dir> |
新增指定目錄到暫存區,包括子目錄 |
git add <file1> |
新增指定檔案到暫存區 |
commit
commit 相關命令也很簡單,主要實現將暫存區的內容提交到本地倉庫,並使得當前分支的 HEAD 向後移動一個提交點。
git commit -m <message> |
提交暫存區到本地倉庫, message 代表說明資訊 |
---|---|
git commit <file1> -m <message> |
提交暫存區的指定檔案到本地倉庫 |
git commit --amend -m <message> |
使用一次新的 commit,替代上一次提交 |
branch
涉及到協作,自然會涉及到分支,關於分支,大概有展示分支,切換分支,建立分支,刪除分支這四種操作。
git branch |
列出所有本地分支 |
---|---|
git branch -r |
列出所有遠端分支 |
git branch -a |
列出所有本地分支和遠端分支 |
git branch <branch-name> |
新建一個分支,但依然停留在當前分支 |
git checkout -b <branch-name> |
新建一個分支,並切換到該分支 |
git branch --track <branch><remote-branch> |
新建一個分支,與指定的遠端分支建立追蹤關係 |
git checkout <branch-name> |
切換到指定分支,並更新工作區 |
git branch -d <branch-name> |
刪除分支 |
git push origin --delete <branch-name> |
刪除遠端分支 |
關於分支的操作雖然比較多,但都比較簡單好記。
merge
merge 命令把不同的分支合併起來。如上圖,在實際開放中,我們可能從 master 分支中切出一個分支,然後進行開發完成需求,中間經過 R3,R4,R5 的 commit 記錄,最後開發完成需要合入 master 中,這便用到了 merge。
git fetch <remote> |
merge 之前先拉一下遠端倉庫最新程式碼 |
---|---|
git merge <branch> |
合併指定分支到當前分支 |
一般在 merge 之後,會出現 conflict,需要針對衝突情況,手動解除衝突。主要是因為兩個使用者修改了同一檔案的同一塊區域。如下圖所示,需要手動解除。
rebase
rebase 又稱為衍合,是合併的另外一種選擇。
在開始階段,我們處於 new 分支上,執行git rebase dev
,那麼 new 分支上新的 commit 都在 master 分支上重演一遍,最後 checkout 切換回到 new 分支。這一點與 merge 是一樣的,合併前後所處的分支並沒有改變。git rebase dev
,通俗的解釋就是 new 分支想站在 dev 的肩膀上繼續下去。rebase 也需要手動解決衝突。
rebase 與 merge 的區別
現在我們有這樣的兩個分支, test 和 master,提交如下:
D---E test
/
A---B---C---F master
在 master 執行git merge test
, 然後會得到如下結果:
D--------E
/
A---B---C---F----G test, master
在 master 執行git rebase test
,然後得到如下結果:
A---B---D---E---C'---F' test, master
可以看到,merge 操作會生成一個新的節點,之前的提交分開顯示。而 rebase 操作不會生成新的節點,是將兩個分支融合成一個線性的提交。
如果你想要一個乾淨的,沒有 merge commit 的線性歷史樹,那麼你應該選擇 git rebase 如果你想保留完整的歷史記錄,並且想要避免重寫 commit history 的風險,你應該選擇使用 git merge
reset
reset 命令把當前分支指向另一個位置,並且相應的變動工作區和暫存區。
git reset —soft <commit> |
只改變提交點,暫存區和工作目錄的內容都不改變 |
---|---|
git reset —mixed <commit> |
改變提交點,同時改變暫存區的內容 |
git reset —hard <commit> |
暫存區、工作區的內容都會被修改到與提交點完全一致的狀態 |
git reset --hard HEAD |
讓工作區回到上次提交時的狀態 |
revert
git revert 用一個新提交來消除一個歷史提交所做的任何修改。
revert 與 reset 的區別
- git revert 是用一次新的 commit 來回滾之前的 commit,git reset 是直接刪除指定的 commit。
- 在回滾這一操作上看,效果差不多。但是在日後繼續 merge 以前的老版本時有區別。因為 git revert 是用一次逆向的 commit“中和” 之前的提交,因此日後合併老的 branch 時,導致這部分改變不會再次出現,減少衝突。但是 git reset 是之間把某些 commit 在某個 branch 上刪除,因而和老的 branch 再次 merge 時,這些被回滾的 commit 應該還會被引入,產生很多衝突。關於這一點,不太理解的可以看這篇文章。
- git reset 是把 HEAD 向後移動了一下,而 git revert 是 HEAD 繼續前進,只是新的 commit 的內容和要 revert 的內容正好相反,能夠抵消要被 revert 的內容。
push
上傳本地倉庫分支到遠端倉庫分支,實現同步。
git push <remote><branch> |
上傳本地指定分支到遠端倉庫 |
---|---|
git push <remote> --force |
強行推送當前分支到遠端倉庫,即使有衝突 |
git push <remote> --all |
推送所有分支到遠端倉庫 |
其他命令
git status |
顯示有變更的檔案 |
---|---|
git log |
顯示當前分支的版本歷史 |
git diff |
顯示暫存區和工作區的差異 |
git diff HEAD |
顯示工作區與當前分支最新 commit 之間的差異 |
git cherry-pick <commit> |
選擇一個 commit,合併進當前分支 |
以上就是關於 Git 的一些常用命令及詳細闡述,相信能對 Git 有一個初步的認識。