你可能不知道的Git使用方法

使用Git已有很長一段時間,遇到一些痛點問題,而且大都是網上難以直接查到的,故總結于此。

1.兩幅重要的圖

基礎構成
命令原理

以上兩幅圖對理解Git的原理十分重要。

2.基礎命令

首先是一些基礎命令,這些命令經常使用,而少為人知。

  • git add -Agit add --all 把包括修改、增加、刪除都全部加入暫存區。等同于 git add .git add -u兩個命令。

  • git add -p 一段段地把修改提交到暫存區,每一個修處改都會提示你是否加入暫存區。可以按照想要的方式把所有修改分成多個commit。

  • git commit -am 把已經加入暫存區(Stage)的文件的更改提交到本地版本庫,無論這些更改是否已經加入暫存區。與git commit -m的區別在于后者只能向本地版本庫提交已經加入暫存區的更改。如果只是改動某些代碼,而沒有增加或者刪除文件,使用git commit -am一個命令就可以替代git add --allgit commit -m兩個命令。

  • git commit --amend 修改最后一次commit的提交信息。注意,是最后一次,也就是HEAD指向的commit。

  • git branch -vv 顯示本地分支與遠程分支的對應關系。執行git push(沒有帶分支參數)時代碼被提交到對應遠程分支,就是依據該對應關系。這里需要注意Git的simple和matching模式,后者會一次性提交所有的對應關系的分支的代碼到遠程分支,前者只會提交當前所在分支。

  • git stashgit statsh pop 主要用來暫存當前的工作。如果需要git pull又不想把當前的修改提交commit,則可以先使用git stash把修改暫存。該命令運行完后工作區是干凈的,此時再使用git pull拉新代碼。完事了后使用git statsh pop恢復之前的工作狀態。

  • git reflog 顯示曾經的commit。如果我們使用git reset將HEAD指向某個過去的commit了,此時要想回到最開始的commit,使用git log是無法查到最開始的commit的。但是也不要慌,git reflog能給你回到最開始的commit的機會,它會顯示所有的提交記錄。

3.使用場景

根據一些常見的場景給出我自己的解決方法。

3.1 基于遠程分支建立本地分支

你可能剛入職。你的新同事突然丟過來一個地址A,讓你git clone一下代碼。接著他又丟過來一個分支名dev0.1,讓你基于該分支進行開發。如果之前只會在master上git pullgit push,此時就可能有點不知所措了。

你可能首先想到如何把遠程的dev0.1分支clone下來,因為執行git clone A之后,你再用git branch查一下,發現本地只有master分支。

這里需要糾正一個問題。git clone A實際上把所有的分支都從遠程拉下來了,但是git branch只顯示那些與遠程保持了追蹤(tracked)的分支。并且git clone A還會創建本地master分支并將其與遠程(origin)的master建立追蹤(tracked)關系。于是我們最開始使用git branch就只顯示master了。

那么,問題來了。既然所有分支都已經拉下來了,我們如何切入dev0.1分支并進行開發呢?其實很簡單:

git checkout dev0.1

這個命令的含義是將dev0.1分支從本地版本庫取到工作區來(參考上面的兩幅圖中的第二幅),并將工作區切換到該分支。此時一個本地名為dev0.1的分支與遠程(origin)的dev0.1分支就建立了追蹤關系。我們就可以基于dev0.1進行開發了。試試git branch看看會不會顯示出dev0.1

假如遠程分支中并沒有一個叫dev0.1的分支,我們運行以上命令,就會發現這樣的錯誤提示:

error: pathspec 'dev0.1' did not match any file(s) known to git.

此時我們可以看看到底有哪些遠程分支,請使用git branch -r。當然git branch -a顯示的信息就多一些,它顯示全部本地分支和遠程分支。

但我通常并不這樣做。而是用以下命令:

git checkout -b dev origin/dev0.1

它的含義是新建一個本地分支dev,且讓這個分支與遠程dev0.1分支保持追蹤關系。這樣做的好處在于可以自己取一個本地分支名。

3.2 分支開發模式同步Master分支代碼

你可能基于本地的dev0.1分支寫了一些代碼,測試后并提交到本地倉庫中了。你們團隊代碼主干分支是master,且基于這個分支進行發布。這就面臨著一個問題,你的新寫的代碼如何提交到主干分支上。

1.如果的本地dev0.1分支與遠程(origin)dev0.1分支保持了追蹤關系,且如果你們團隊使用類似github/gitlab這樣的git倉庫托管服務,則可以直接在本地dev0.1分支上操作:

  • git pull origin dev0.1拉下遠程代碼,以防有更新。 如果git是simple模式,則可以直接使用git pull[目前git2.0及以上版本都默認為simple模式]。
  • 如果有更新則會自動合并,合并如果失敗,則會要求手動處理沖突。處理完后將這次修改提交到本地倉庫。
  • 使用git push origin dev0.1向遠程倉庫dev0.1分支提交代碼。git 2.0及以上版本直接git push即可。
  • 在github/gitlab的界面上操作,由dev0.1分支向master分支提交merge請求。負責master分支維護的同事合并你的分支代碼到master即可。

2.如果本地dev0.1分支是基于master分支新建的,即在本地master上使用git checkout -b dev0.1命令---它會創建一個dev0.1的本地分支,并切換到該分支,但它不會設置與遠程分支的追蹤關系。這時候如何將該分支的新代碼合并到master分支呢?

  • 首先dev0.1分支要合并到本地master上去。先使用git checkout master切換到主干分支,在主干分支上操作。
  • 合并dev0.1分支。使用git merge dev0.1 --no-ffgit merge dev0.1命令。這兩者的區別可用以下圖片說明:
兩個命令的區別

前者帶有分支記錄,后者沒有。

  • 然后將master分支的代碼提交到遠程master:git pull拉新代碼,解決沖突,git push推到遠程。
  • 如果dev0.1分支沒用處了,就可以直接刪掉:git branch -d dev0.1
3.3 將工作區恢復成干凈的狀態

如果開發了一陣子,修改了一些代碼,但沒控制好,把工作區搞成了一堆亂麻。這時候就想,要是能把工作區恢復成最開始的樣子就好了。

  • 首先確定要恢復成的最初狀態。一般來講就是將工作區恢復成當前本地倉庫中HEAD所指向的commit。不過如果你之前提交到本地的一些commit你也不想要了,那么先用git log查一下你要恢復到的commitID,復制下來。

  • 使用git reset --hard HEAD/commitID命令。運行完畢之后,用git status查一下狀態。一般狀態下會顯示

nothing to commit, working directory clean

但是如果你最開始時新增了一些文件,且沒有將其加入暫存區,那么就不是這種提示了。你需要把你新增的那些文件刪掉,git status才會恢復成以上狀態。主要原因是git reset無法重置那些沒有加入暫存區的更改。

如果你只是需要把某個文件B恢復成倉庫里上一次提交的狀態,那么有以下兩種可能:1.這個文件沒有任何修改提交到暫存區;2.這個文件有一部分修改提交到暫存區了,但是想把暫存區的修改也恢復成HEAD指向的版本。

  • 1情況下直接使用git checkout B恢復工作區的文件B。
  • 2情況下先使用git reset HEAD B撤銷暫存區里面對B的修改,再使用git checkout B恢復工作區中的修改。
3.4 修改某次的提交信息

這個場景并不常見,而有的時候又一定用的到。例如你開發一段時間了,卻發現公司的gitlab要求你push的時候必須使用公司的郵箱,而你之前的commit都用的是你自己的郵箱。我之前就遇到過這個問題,在這兒記錄一下解決方案。

首先,git commit --amend只能對最新提交的Comment內容或郵箱的修改,并不能對中間提交的Comment或者郵箱進行修改。如果只是修改最新提交的信息:

  • git commit --amend 直接進入修改提交信息的模式。
  • git commit --amend --author="chenyi <chenyi@xxx.com>" 可以修改作者信息。

如果需要修改中間某一次的提交信息,則需要按照一定的方法操作。以下是一個修改示列。

原始記錄

如上圖,第二個提交的郵箱同其他提交不一樣,我們需要將它修改成與其他一樣的。

  1. 先進入第二個提交:git rebase -i preCommitID,這里preCommitID就是第二個提交的下面的一個ID,即ff4e24

進入修改模式

我們可以看到,列表里面顯示了我們想要修改的commit的ID,即c1c6685。將其前面的pick更改為edit,保存并退出。

提示

當我們從第2步的編輯過程中退出后,git會提示我們可以用的兩個命令git commit --amendgit rebae --continue。這兩個命令在后面都會用到。

修改模式

我們目前已經處于c1c6685commit上了。此時我們只需要使用git commit --amend --author="chyoo <chyoo1991@gmail.com>"修改該提交的作者信息。上圖就是運行該命令后進入修改的界面。

退出之后的結果
退出第4步的修改模式之后,git給的提示信息。接下來我們只需要運行git rebase --continue繼續rebase就可以完成目標了。

3.5 將Commit記錄變成直線模式

通常很多人合作寫代碼時,希望將遠程master分支維護成直線的形式,這樣commit干凈明確,檢查問題時能省不少事。而一般合并最新代碼時用的git pull會將生成一個merge commit,這將導致推送到遠程分支的代碼也是各種分支交叉,一點也不干凈明確。

那么,該如何實現這個目的呢?

首先這里要上一份干貨,就是git mergegit rebase的區別,需要注意到git pull實際上是調用git merge進行代碼的合并。->干貨在此

從干貨文章中我們可以發現,能夠使用git rebase命令用打補丁的方式來實現commit保持直線的目的。我們這樣操作:

  1. git fetch origin master 用這個命令將遠程(origin)的master分支最新提交取到本地。

  2. git rebase origin/master 使用rebase 進行pack打補丁,將我們自己提交的本地代碼以補丁的方式放在最新代碼的后面。這個過程中可能會出現沖突,修改完了之后使用git rebase --continue繼續pack,直到完成rebase。如果出現無法解決的問題,想回到最開始,可以使用git rebase --abort

  3. git push提交代碼到遠程master分支。

這里要求開發協作的每一個人都用這種方式操作和提交代碼,這樣才能保持遠程master分支的干凈整潔和直線性。

->這一篇文章講了為什么這樣做的原理。

3.6 為一個本地倉庫設定多個遠程倉庫

這個看起來是有點奇怪的需求。不過前不久gitlab的員工刪除了它們的數據庫,導致很大部分項目受影響,這讓我們覺得如果能多一份代碼保障或許更好。

使用git clone時,會自動設定遠程地址,一般都是以origin指代。如果我們有特殊需求,需要將代碼提交到另一個遠程倉庫,這時就要設定新的遠程倉庫地址了。

git remote add hegel http://xxxx.git 這個命令就可以給當前的本地庫設置一個遠程倉庫hegel。以后我們想推拉代碼到這個遠程庫時,就需要用git push hegel mastergit pull hegel master了。

4.快捷設定

有一些比較有用的設定,能在寫命令時少了很多麻煩。

  1. 全局設置user和email
  • git config --global user.name "chenyi"
  • git config --global user.emali "chenyi@xxx.com"
  1. 給常用命令起一個簡單的名字
  • git config --global alias.co checkout
  • git config --global alias.st status
  • git config --global alias.br branch
  • git config --global alias.ci commit

后續就可以使用git co/git ci等命令了,是不是簡潔了很多?

3.更好看的git log

git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

配置了這個之后,使用git lg簡直眼前一亮。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容