原標題:教你打通 Git 任督二脈

【編者按】Git是一個開源的分佈式版本控制系統,是目前世界上最快、最簡單、也是最流行的版本控制工具,它可以有效、高速的管理從很小到非常大的項目版本。本文主要爲剛接觸Git的新人提供常用的操作。

作者 | 狼王 責編 | 歐陽姝黎

在日常工作中,經常會用到Git操作。但是對於很多人來講,剛上來對Git很陌生,操作起來也很懵逼。本篇文章主要針對剛開始接觸Git的新人,理解Git的基本原理,掌握常用的一些命令。

關於版本控制

什麼是 版本控制?我真的需要嗎? 版本控制是一種記錄若干文件內容變化,以便將來查閱特定版本修訂情況的系統。

什麼是分佈式版本控制系統

分佈式版本控制系統( Distributed Version Control System,簡稱 DVCS )。

在這類系統中,像 Git,Mercurial,Bazaar 以及 Darcs 等,客戶端並不只提取最新版本的文件快照,而是把原始的代碼倉庫完整地鏡像下來。這麼一來,任何一處協同工作用的服務器發生故障,事後都可以用任何一個鏡 像出來的本地倉庫恢復。因爲每一次的提取操作,實際上都是一次對代碼倉庫的完整備份。

更進一步,許多這類系統都可以指定和若干不同的遠端代碼倉庫進行交互。藉此,你就可以在同一個項目中,分別和不同工作小組的人相互協作。你可以根據需要設定不同的協作流程,比如層次模型式的工作流,而這在以前的集中式系統中是無法實現的。

Git工作流程

以上包括一些簡單而常用的命令,但是先不關心這些,先來了解下面這4個專有名詞。

  1. Workspace:工作區
  2. Index / Stage:暫存區
  3. Repository:倉庫區(或本地倉庫)
  4. Remote:遠程倉庫

工作區

指的是在PC中能看得到的創建的一個管理倉庫的目錄,比如我的test文件夾就是一個工作區:如下圖:

暫存區

.git目錄下的index文件, 暫存區會記錄git add添加文件的相關信息(文件名、大小、timestamp...),不保存文件實體, 通過id指向每個文件實體。可以使用git status查看暫存區的狀態。暫存區標記了你當前工作區中,哪些內容是被git管理的。

當你完成某個需求或功能後需要提交到遠程倉庫,那麼第一步就是通過git add先提交到暫存區,被git管理。

本地倉庫

保存了對象被提交 過的各個版本,比起工作區和暫存區的內容,它要更舊一些。

git commit後同步index的目錄樹到本地倉庫,方便從下一步通過git push同步本地倉庫與遠程倉庫的同步。

遠程倉庫

遠程倉庫的內容可能被分佈在多個地點的處於協作關係的本地倉庫修改,因此它可能與本地倉庫同步,也可能不同步,但是它的內容是最舊的。

小結

  1. 任何對象都是在工作區中誕生和被修改;
  2. 任何修改都是從進入index區纔開始被版本控制;
  3. 只有把修改提交到本地倉庫,該修改才能在倉庫中留下痕跡;
  4. 與協作者分享本地的修改,可以把它們push到遠程倉庫來共享。

下面這幅圖更加直接闡述了四個區域之間的關係,可能有些命令不太清楚,沒關係,下部分會詳細介紹。

常用Git命令

HEAD

在掌握具體命令前,先理解下HEAD。

這要從git的分支說起,git 中的分支,其實本質上僅僅是個指向 commit 對象的可變指針。git 是如何知道你當前在哪個分支上工作的呢?其實答案也很簡單,它保存着一個名爲 HEAD 的特別指針。在 git 中,它是一個指向你正在工作中的本地分支的指針,可以將 HEAD 想象爲當前分支的別名。

add

add相關命令很簡單,主要實現將工作區修改的內容提交到暫存區,交由git管理。

  1. git add . 添加當前目錄的所有文件到暫存區
  2. git add dir 添加指定目錄到暫存區,包括子目錄
  3. git add file 添加指定文件到暫存區

git add -A 和 git add . 和 git add -u 的區別

  1. git add -A : 把所有變化提交到索引庫,包含當前git倉庫的所有目錄
  2. git add -u : 提交被修改(modified)和被刪除(deleted)文件,不包括新文件(new)
  3. git add . : 該操作與git 的版本有關:
  4. -1.x 版本:提交新文件(new)和被修改(modified)文件,不包括被刪除(deleted)文件
  5. -2.x 版本:和git add -A一樣,提交所有變化

commit

git commit 主要是將暫存區裏的改動給提交到本地的版本庫。每次使用git commit 命令我們都會在本地版本庫生成一個40位的哈希值,這個哈希值也叫commit-id,commit-id在版本回退的時候是非常有用的,它相當於一個快照,可以在未來的任何時候通過與git reset的組合命令回到這裏.

  1. git commit -m message 提交暫存區到本地倉庫,message代表說明信息
  2. git commit file -m message 提交暫存區的指定文件到本地倉庫
  3. git commit --amend -m message 使用一次新的commit,替代上一次提交

branch

涉及到協作,自然會涉及到分支,關於分支,大概有展示分支,切換分支,創建分支,刪除分支這四種操作。

  1. git branch 列出所有本地分支
  2. git branch -r 列出所有遠程分支
  3. git branch -a 列出所有本地分支和遠程分支
  4. git branch branch-name 新建一個分支,但依然停留在當前分支
  5. git checkout -b branch-name 新建一個分支,並切換到該分支
  6. git branch --track branch remote-branch 新建一個分支,與指定的遠程分支建立追蹤關係
  7. git checkout branch-name 切換到指定分支,並更新工作區
  8. git branch -d branch-name 刪除分支
  9. git push origin --delete branch-name 刪除遠程分支

關於分支的操作雖然比較多,但都比較簡單好記。

merge

Git的git-merge是在Git中頻繁使用的一個命令,很多人都覺得git合併是一個非常麻煩的事情,一不小心就會遇到丟失代碼的問題,從而對git望而卻步。

merge命令把不同的分支合併起來。如上圖,在實際開放中,我們可能從master分支中切出一個分支,然後進行開發完成需求,中間經過R3,R4,R5的commit記錄,最後開發完成需要合入master中,這便用到了merge。

  1. git fetch remote merge之前先拉一下遠程倉庫最新代碼
  2. 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,提交如下:

  1. D---E test
  2. /
  3. A---B---C---F master

在master執行git merge test,然後會得到如下結果:

  1. D--------E
  2. / \
  3. 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

有時候,我們用Git的時候有可能commit提交代碼後,發現這一次commit的內容是有錯誤的,那麼有兩種處理方法:

  1. 修改錯誤內容,再次commit一次
  2. 使用git reset 命令撤銷這一次錯誤的commit

第一種方法比較直接,但會多次一次commit記錄。而我個人更傾向第二種方法,錯誤的commit沒必要保留下來。

reset命令把當前分支指向另一個位置,並且相應的變動工作區和暫存區

  1. git reset —soft commit 只改變提交點,暫存區和工作目錄的內容都不改變
  2. git reset —mixed commit 改變提交點,同時改變暫存區的內容
  3. git reset —hard commit 暫存區、工作區的內容都會被修改到與提交點完全一致的狀態
  4. git reset --hard HEAD 讓工作區回到上次提交時的狀態

revert

git revert用一個新提交來消除一個歷史提交所做的任何修改。

revert與reset的區別

  1. git revert是用一次新的commit來回滾之前的commit,git reset是直接刪除指定的commit。
  2. 在回滾這一操作上看,效果差不多。但是在日後繼續merge以前的老版本時有區別。因爲git revert是用一次逆向的commit“中和”之前的提交,因此日後合併老的branch時,導致這部分改變不會再次出現,減少衝突。但是git reset是之間把某些commit在某個branch上刪除,因而和老的branch再次merge時,這些被回滾的commit應該還會被引入,產生很多衝突。關於這一點,不太理解的可以看這篇文章。
  3. git reset 是把HEAD向後移動了一下,而git revert是HEAD繼續前進,只是新的commit的內容和要revert的內容正好相反,能夠抵消要被revert的內容。

push

git push的一般形式爲 git push <遠程主機名> <本地分支名> <遠程分支名> ,例如 git push origin master:refs/for/master ,即是將本地的master分支推送到遠程主機origin上的對應master分支, origin 是遠程主機名

  1. git push remote branch 上傳本地指定分支到遠程倉庫
  2. git push remote --force 強行推送當前分支到遠程倉庫,即使有衝突
  3. git push remote --all 推送所有分支到遠程倉庫

其他命令

  1. git status 顯示有變更的文件
  2. git log 顯示當前分支的版本歷史
  3. git diff 顯示暫存區和工作區的差異
  4. git diff HEAD 顯示工作區與當前分支最新commit之間的差異
  5. git cherry-pick commit 選擇一個commit,合併進當前分支

以上就是關於Git的一些常用命令及詳細闡述,相信能對Git有一個初步的認識。

鏈接:https://csdnnews.blog.csdn.net/article/details/115535236

相關文章