Git操作手冊|命令速查表

BestEden發表於2016-09-22

本文轉載自:http://www.ezlippi.com/blog/2016/02/git-guide.html#more

這篇文章主要介紹Git分散式版本管理與集中式管理的一些差異,總結下Git常用命令作為日後的速查表,最後介紹Git進階的一些案例。
本文分為以下幾個部分:

  1. Git與SVN差異
  2. Git常用命令
  3. Git進階指南

Git與SVN差異

Git的第一個版本是Linux之父Linus Torvalds親手操刀設計和實現的,Git 基於 DAG 結構 (Directed Acyclic Graph),其執行起來相當的快,它已經是現在的主流。

Git 和 SVN 思想最大的差別有四個:

  • 去中心化
  • 直接記錄快照,而非差異
  • 不一樣的分支概念
  • 三個檔案狀態

去中心化

Git是一個DVCS(分散式版本管理系統),在技術層面上並不存在一個像中心倉庫這樣的東西 , 所有的資料都在本地,不存在誰是中心

這裡寫圖片描述

圖中每個開發者拉取(pull)並推送(push)到origin。但除了這種集中式的推送拉取關係,每個開發者也可能會從其他的開發者處拉取程式碼的變更,從技術上講,這意味著Alice定義了一個名為bob的Git的remote,它指向了Bob的軟體倉庫。反之亦然。

直接記錄快照,而非差異

Git每一個版本都是直接記錄快照,而非檔案的差異。 下面兩個對比圖在網上是廣為流傳大家應該熟悉:

SVN:

這裡寫圖片描述

Git:

這裡寫圖片描述

Git使用SHA-1演算法計算資料的校驗和,通過檔案的內容或目錄計算出SHA-1雜湊值,作為指紋字串,每個Version 都是一個快照。

不一樣的分支概念

Git的分支本質是一個指向提交快照的指標,是從某個提交快照往回看的歷史。當建立/切換分支的時候,只是變換了指標指向而已.而SVN建立一個分支, 是的的確確的複製了一份檔案。

三個檔案狀態

在Git中檔案有三種狀態:

  • 已提交(committed):該檔案被安全地儲存在了本地資料庫
  • 已修改(modified):修改了某個檔案,但還沒有儲存
  • 已暫存(staged):把已修改的檔案放下下次儲存的清單中

Git常用命令

建立

複製一個已建立的倉庫:

$ git clone ssh://user@domain.com/repo.git

建立一個新的本地倉庫:

$ git init

本地修改

顯示工作路徑下已修改的檔案:

$ git status

顯示與上次提交版本檔案的不同:

$ git diff

把當前所有修改新增到下次提交中:

$ git add

把對某個檔案的修改新增到下次提交中:

$ git add -p <file>

提交本地的所有修改:

$ git commit -a

提交之前已標記的變化:

$ git commit

附加訊息提交:

$ git commit -m 'message here'

提交,並將提交時間設定為之前的某個日期:

git commit --date="`date --date='n day ago'`" -am "Commit Message"

修改上次提交

請勿修改已釋出的提交記錄!

$ git commit --amend

把當前分支中未提交的修改移動到其他分支

git stash
git checkout branch2
git stash pop

搜尋

從當前目錄的所有檔案中查詢文字內容:

$ git grep "Hello"

在某一版本中搜尋文字:

$ git grep "Hello" v2.5

提交歷史

從最新提交開始,顯示所有的提交記錄(顯示hash, 作者資訊,提交的標題和時間):

$ git log

顯示所有提交(僅顯示提交的hash和message):

$ git log --oneline

顯示某個使用者的所有提交:

$ git log --author="username"

顯示某個檔案的所有修改:

$ git log -p <file>

誰,在什麼時間,修改了檔案的什麼內容:

$ git blame <file>

分支與標籤

列出所有的分支:

$ git branch

切換分支:

$ git checkout <branch>

建立並切換到新分支:

$ git checkout -b <branch>

基於當前分支建立新分支:

$ git branch <new-branch>

基於遠端分支建立新的可追溯的分支:

$ git branch --track <new-branch> <remote-branch>

刪除本地分支:

$ git branch -d <branch>

給當前版本打標籤:

$ git tag <tag-name>

更新與釋出

列出當前配置的遠端端:

$ git remote -v

顯示遠端端的資訊:

$ git remote show <remote>

新增新的遠端端:

$ git remote add <remote> <url>

下載遠端端版本,但不合併到HEAD中:

$ git fetch <remote>

下載遠端端版本,並自動與HEAD版本合併:

$ git remote pull <remote> <url>

將遠端端版本合併到本地版本中:

$ git pull origin master

將本地版本釋出到遠端端:

$ git push remote <remote> <branch>

刪除遠端端分支:

$ git push <remote> :<branch> (since Git v1.5.0)
或
git push <remote> --delete <branch> (since Git v1.7.0)

釋出標籤:

$ git push --tags

合併與重置

將分支合併到當前HEAD中:

$ git merge <branch>

將當前HEAD版本重置到分支中:
請勿重置已釋出的提交!

$ git rebase <branch>

退出重置:

$ git rebase --abort

解決衝突後繼續重置:

$ git rebase --continue

使用配置好的merge tool 解決衝突:

$ git mergetool

在編輯器中手動解決衝突後,標記檔案為已解決衝突

$ git add <resolved-file>
$ git rm <resolved-file>

撤銷

放棄工作目錄下的所有修改:

$ git reset --hard HEAD

移除快取區的所有檔案(i.e. 撤銷上次git add):

$ git reset HEAD

放棄某個檔案的所有本地修改:

$ git checkout HEAD <file>

重置一個提交(通過建立一個截然不同的新提交)

$ git revert <commit>

將HEAD重置到指定的版本,並拋棄該版本之後的所有修改:

$ git reset --hard <commit>

將HEAD重置到上一次提交的版本,並將之後的修改標記為未新增到快取區的修改:

$ git reset <commit>

將HEAD重置到上一次提交的版本,並保留未提交的本地修改:

$ git reset --keep <commit>

Git進階指南

問:如何修改 origin 倉庫資訊?

1、新增 origin 倉庫資訊

git remote add origin <git倉庫地址>

2、檢視 origin 倉庫資訊

# 以下三種方式均可
git config get --remote.origin.url
git remote -v
git remote show origin

3、刪除 origin 倉庫資訊

 git remote rm origin

問:如何配置 git ssh keys ?

在本地生成 ssh 私鑰 / 公鑰 檔案
將「公鑰」新增到 git 服務(github、gitlab、coding.net 等)網站後臺
測試 git ssh 連線是否成功
接下來以新增 github ssh keys 為例,請注意替換 github 檔名。

注:如果對金鑰機制不熟悉,建議不要指定 -f 引數,直接使用預設的 id_rsa 檔名。

# 執行以下命令,一直回車,檔名可隨意指定
ssh-keygen -t rsa -b 4096 -C "kaiye@macbook" -f ~/.ssh/github

# 如果不是預設金鑰 id_rsa ,則需要以下命令註冊金鑰檔案,-K 引數將金鑰存入 Mac Keychain
ssh-add -K ~/.ssh/github

# 將 pub 公鑰的內容貼上到線上網站的後臺
cat ~/.ssh/github.pub

# 測試 git ssh 是否連線成功
ssh -T git@github.com

問:如何撤銷修改?

修改包含四種情況,需單獨區分。

1、新建的檔案和目錄,且從未提交至版本庫

此類檔案的狀態為 Untracked files ,撤銷方法如下:

git clean -fd .

其中,. 表示當前目錄及所有子目錄中的檔案,也可以直接指定對應的檔案路徑,以下其他情況類似。

2、提交過版本庫,但未提交至暫存區的檔案(未執行 git add)

此類檔案的狀態為Changes not staged for commit,撤銷方法:

 git checkout .

3、已提交至暫存區的檔案

此類檔案的狀態為 Changes to be committed,撤銷方法:

git reset .

執行之後檔案將會回到以上的 1 或者 2 狀態,可繼續按以上步驟執行撤銷,若 git reset 同時加上 –hard 引數,將會把修改過的檔案也還原成版本庫中的版本。

4、已提交至版本庫(執行了 git commit)

每次提交都會生成一個 hash 版本號,通過以下命令可查閱版本號並將其回滾:

git log
git reset <版本號>

如果需要「回滾至上一次提交」,可直接使用以下命令:

git reset head~1

執行之後,再按照 1 或者 2 狀態進行處理即可,如果回滾之後的程式碼同時需要提交至 origin 倉庫(即回滾 origin 線上倉庫的程式碼),需要使用 -f 強制提交引數,且當前使用者需要具備「強制提交的許可權」。

5、如果回滾了之後又不想回滾了怎麼辦?

如果是以上的情況 1 或者 2,只能歇屁了,因為修改沒入過版本庫,無法回滾。

如果是情況 4,回滾之後通過 git log 將看不到回滾之前的版本號,但可通過 git reflog 命令(所有使用過的版本號)找到回滾之前的版本號,然後 git reset <版本號> 。

問:遇到衝突了怎麼解決?

兩個分支進行合併時(通常是 git pull 時),可能會遇到衝突,同時被修改的檔案會進入 Unmerged 狀態,需要解決衝突。

1、最快的辦法

大部分時候,「最快解決衝突」的辦法是:使用當前 HEAD 的版本(ours),或使用合併進來的分支版本(theirs)。

# 使用當前分支 HEAD 版本,通常是衝突原始檔的 <<<<<<< 標記部分,======= 的上方
git checkout --ours <檔名>

 # 使用合併分支版本,通常是源衝突檔案的 >>>>>>> 標記部分
 git checkout --theirs <檔名>

# 標記為解決狀態加入暫存區
git add <檔名>

2、最通用的辦法

用編輯器開啟衝突的原始檔進行修改,可能會發生遺留,且體驗不好,通常需要藉助 git mergetool 命令。

在 Mac 系統下,執行 git mergetool <檔名> 可以開啟配置的第三方工具進行 merge,預設的是 FileMerge 應用程式,還可以配置成 Meld 或 kdiff3,體驗更佳。

3、最好的習慣

有三個好的習慣,可以減少程式碼的衝突:
在開始修改程式碼前先 git pull 一下;
將業務程式碼進行劃分,儘量不要多個人在同一時間段修改同一檔案;
通過Gitflow 工作流也可以提升 git流程效率,減少發生衝突的可能性。

4、最複雜的情況

如果你的專案週期比較長,還應該養成「定期 rebase 的習慣」,git pull –rebase 可以讓分支的程式碼和 origin 倉庫的程式碼保持相容,同時還不會破壞線上程式碼的可靠性。

它的大概原理是,先將 origin 倉庫的程式碼按 origin 的時間流在本地分支中提交,再將本地分支的修改記錄追加到 origin 分支上。如果發生衝突,則可以即時的發現問題並解決,否則到專案上線時再解決衝突,可能會發生額外的風險。

rebase 大概的操作步驟如下:

# 將當前分支的版本追加到從遠端 pull 回來的節點之後
git pull --rebase

# 若發生衝突,則按以上其他方法進行解決,解決後繼續
git rebase --continue

# 直到所有衝突得以解決,待專案最後上線前再執行
git push origin

# 若多次提交修改了同一檔案,可能需要直接跳過後續提交,按提示操作即可
git rebase --skip

問:如何在不提交修改的前提下,執行 pull / merge 等操作?

有些修改沒有完全完成之前,可能不需要提交到版本庫,圡方法是將修改的檔案 copy 到 git 倉庫之外的目錄臨時存放,pull / merge 操作完成之後,再 copy 回來。

這樣的做法一個是效率不高,另外一個可能會遺漏潛在的衝突。此類需求最好是通過 git stash 命令來完成,它可以將當前工作狀態(WIP,work in progress)臨時存放在 stash 佇列中,待操作完成後再從 stash 佇列中重新應用這些修改。

以下是 git stash 常用命令:

# 檢視 stash 佇列中已暫存了多少 WIP
git stash list

# 恢復上一次的 WIP 狀態,並從佇列中移除
git stash pop

# 新增當前 WIP,注意:未提交到版本庫的檔案會自動忽略,只要不執行 git clean -fd . 就不會丟失
git stash

# 恢復指定編號的 WIP,同時從佇列中移除
git stash pop stash@{num}

# 恢復指定編號的 WIP,但不從佇列中移除
git stash apply stash@{num}

問:如何在 git log 中檢視修改的檔案列表?

預設的 git log 會顯示較全的資訊,且不包含檔案列表。使用 –name-status 可以看到修改的檔案列表,使用 –oneline 可以將引數簡化成一行。

git log --name-status --oneline

每次手動加上引數很麻煩,可以通過自定義快捷命令的方式來簡化操作:

git config --global alias.ls 'log --name-status --oneline --graph'

執行以上配置後,可通過 git ls 命令來實現「自定義 git log」效果,通過該方法也可以建立 git st 、 git ci 等一系列命令,以便沿用 svn 命令列習慣。

git config --global alias.st 'status --porcelain'

更多 git log 引數,可通過 git help log 檢視手冊。

如果是看上一次提交的版本日誌,直接執行 git show 即可。

此外,如果你的 Mac 安裝了zsh(參考《全新Mac安裝指南(程式設計篇),那麼可以直接使用 gst、glog 等一系列快捷命令,詳情見此列表:Plugin:git 。

問:git submodule update 時出錯怎麼解決?

例如,在執行 git submodule update 時有以下錯誤資訊:

fatal: reference is not a tree:
f869da471c5d8a185cd110bbe4842d6757b002f5
Unable to checkout
‘f869da471c5d8a185cd110bbe4842d6757b002f5’ in submodule
path ‘source/i18n-php-server’

在此例中,發生以上錯誤是因為 i18n-php-server 子倉庫在某電腦 A 的「本地」commit 了新的版本 「f869da471c5d8a185cd110bbe4842d6757b002f5」,且該次 commit 未 push origin。但其父級倉庫 i18n-www 中引用了該子倉庫的版本號,且將引用記錄 push origin,導致其他客戶機無法 update 。

解決方法,在電腦 A 上將 i18n-php-server 版本庫 push origin 後,在其他客戶機上執行 git submodule update 。或者用以上提到的 git reset 方法,將子倉庫的引用版本號還原成 origin 上存在的最新版本號。

其他問題

設定本地分支與遠端分支保持同步,在第一次 git push 的時候帶上 -u 引數即可

git push origin master -u 

支援中文目錄與檔名的顯示(git 預設將非 ASCII 編碼的目錄與檔名以八進位制編碼展示)

git config core.quotepath off

常用的打 tag 操作,更多請檢視《Git 基礎 - 打標籤》

# 列出所有本地 tag
git tag   

# 本地新增一個 tag,推送至 origin 伺服器
git tag -a v1.0.0 -m 'tag description'
git push origin v1.0.0

# 刪除本地與 origin tag
git tag -d v1.0.0
git push origin --delete v1.0.0

使用 git GUI 客戶端(如,SoureTree、Github Desktop)能極大的提升分支管理效率。分支合併操作通常只有兩種情況:從 origin merge 到本地,使用 git pull 即可;從另外一個本地分支 merge 到當前分支,使用 git merge <分支名>,以下是常用命令:

# 新建分支 branch1,並切換過去
git checkout -b branch1

# 檢視所有本地與遠端分支
git branch -a

# 修改完成後,切換回 master 分支,將 branch1 分支合併進來
git checkout master
git merge branch1

# 刪除已完成合並的分支 branch1
git branch -d branch1

參考資料

  1. Pro Git 簡體中文版
  2. Git權威指南
  3. 命令列man手冊

相關文章