首頁 > 軟體

Git命令和設定技巧

2020-06-16 17:02:22

此文主要介紹一切開發中常用的git命令和一些設定技巧(諸如git別名設定,log列印技巧,版本回退以及分支管理等)。

1.簡介


Git與svn相比而言,Git的好處自然不用多說,Git完全分散式檔案管理系統,加上其簡單速度,可以高效管理類似 Linux 核心一樣的超大規模專案。完全分散式的系統,讓你可以在公交車上,火車上,家中,甚至在廁所都可以敲程式碼。何時何地你都可以敲程式碼,甚至不需要網路。好不好使,開不開心?換是SVN,SVN伺服器掛了,全部人停止敲程式碼,停下來八卦去吧。

Git 和其他版本控制系統的主要差別在於,Git 只關心檔案資料的整體是否發生變化,而大多數其他系統則只關心檔案內容的具體差異。這類系統(CVS,Subversion,Perforce,Bazaar 等等)每次記錄有哪些檔案作了更新,以及都更新了哪些行的什麼內容。如同下圖所示:

但是,Git 並不儲存這些前後變化的差異資料。實際上,Git 更像是把變化的檔案作快照後,記錄在一個微型的檔案系統中。每次提交更新時,它會縱覽一遍所有檔案的指紋資訊並對檔案作一快照,然後儲存一個指向這次快 照的索引。為提高效能,若檔案沒有變化,Git 不會再次儲存,而只對上次儲存的快照作一連線。工作方式類似下圖:

對比可以發現,Git高效也在情理之中。
現在再簡單介紹一下Git管理下檔案的三種狀態。對於任何一個檔案,只要在Git管理下,那麼該檔案只有三種狀態:已修改(modified),已暫存(staged)和已提交 (committed)。
已修改(modified): 檔案被修改,但是還沒有提交儲存(也就是沒有使用git add,此時使用git status顯示為紅色)。
已暫存(staged): 已修改的檔案放入下次要提交的清單中(使用了git add後的狀態,此時使用git status顯示為綠色)。
已提交(committed): 該檔案已經被安全地儲存在本地資料庫中(使用了git commit後,此時使用git status已經不存在該檔案的任何資訊)。
具體可以參考下面兩幅圖來理解。

2.設定使用者資訊


user和email,--global引數全域性設定,當然你也可以不加此引數,不同的專案用不同的使用者名稱和郵箱。

git config --global user.name Super
git config --global user.email 1342449****@163.com

3.設定全域性別名


此設定在開發中相當重要,尤其是對於使用Terminal,習慣使用命令列的朋友,由於git不支援tab自動補全,每次想要看下工作目錄 狀態都要git status,相當耗時。除非你能確定你敲兩個字母比六個字母用時少。

git config --global alias.st "status -s"
git config --global alias.ci "commit -m"
git config --global alias.aci "commit -a -m" // 跳過使用暫緩區,直接將git add和git commit合併為一條命令
git config --global alias.lg "log --color --pretty=format:'%Cred%h - %Cgreen%an %C(yellow)| %ad | %Creset%s' --graph" (自定義log)

第一條:git status是開發中使用最多最頻繁的,至於-s 是簡潔輸入(Give the output in the short-format)
第二條:此條也使用頻繁,但是我在開發中直接使用第三條跳過。
第三條:設定git aci 因為這樣直接跳過使用暫存區域,對於已經跟蹤的檔案,我不要再此次使用git add加入暫緩區,然後再git commit提交到本地資料庫,為了方便省事,直接將兩條命令合併為一條,使用git aci "提交說明" 即可。省不省事,用下自然知道。
第四條:這裡是我自定義的log資訊,當然,一會看完本文你也可以自己格式化成自己喜歡的log格式。可以先看下效果,下圖所示:


以後直接使用"git lg"即可,非常方便,顯示簡潔明瞭。

4.分支管理


git checkout -b dev origin/dev // 拉取遠端開發分支到本地並且切換到開發分支
git push dev origin/dev
git branch new   // 建立新分支
git push origin new // 將new分支推播到遠端(git push [remote-name] [branch-name])
git push origin :new   // 刪除遠端分支,注意冒號位置
git brach -d new // 刪除本地分支,如果有沒有merge的資訊,確保該分支的確不用merge,直接使用-D強行刪除
git merge dev   //  將dev分支合併到當前分支
git checkout master // 切換到主分支
// 其他不再一一列出

關於實際開發中,獨立開發的話其實兩個分支完全夠用,一個主分支,一個開發分支。多人的話就按功能模組和人員來具體新建分支即可。由於這邊由我一人負責整個專案,那麼分支的話,我就建立了一個develop分支。發布版本時放到主分支處理即可。平時都在develop分支開發,如果此時發現線上版本有bug,那麼只需要切換到master分支,修改bug,然後封版即可。處理好後繼續回到開發分支開發就可以了。當然最好還是把剛才修改bug的程式碼merge到開發分支上。

還有一點使用技巧,也就是git stash的靈活使用。當我們正在當前分支編寫程式碼,突然某人中斷你的思路,提出某功能需修改且比較緊急,更煩人的是當前的程式碼已經開始編寫,而且動用了好多檔案,重要的是不想中途進行git commit提交。此時git stash就發揮作用了。

git stash // 暫時隱藏,之後就可以正常切換分支了,當前的修改內容只是儲存並且隱藏起來
git stash pop // 回復到之前的工作狀態,預設pop的是最近的一條,這樣就可以愉快的繼續編寫當時被中斷的程式碼了

git stash可以執行多次,我們可以使用git stash list命令來檢視清單。當然還有好多命令,可以使用"git stash --help"來檢視。

// git stash --help
usage: git stash list [<options>]
   or: git stash show [<stash>]
   or: git stash drop [-q|--quiet] [<stash>]
   or: git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]
   or: git stash branch <branchname> [<stash>]
   or: git stash [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]
               [-u|--include-untracked] [-a|--all] [<message>]]
   or: git stash clear

其實關於git stash還有一個使用技巧,那就是如果當前改了眾多檔案,突然又不想改了,想恢復到原來的樣子。那麼可能你會使用"git checkout ."命令來取消所有的更改,但是有種情況並不好使,那就是你除了修改檔案,還新增了一些檔案或則拖入了一些檔案到工程目錄下,此時使用"git checkout ."然後再使用"git status"檢視的時候,會發現工作區多出了尚未識別的檔案(處於等待add的狀態)。在這個時候,使用git stash是再好不過了,因為這樣將所有git控制下的檔案,包括之前的目錄,全部還原到之前的狀態(也就是說git stash把新增的檔案也暫時隱藏起來)。如果想徹底刪掉,那就再把所有stash的列表清空吧,直接"git stash list"看下,然後"git stash clear"。

還有一點,關於在Git伺服器上刪除分支,本地使用"git branch -a"依舊可以看到被刪除問題。好比你的程式碼託管到了開源中國(OSChina),你通過網站,線上刪除分支,就會出現這種問題,稍微有點強迫症的自然受不了。此時可以使用 "git fetch -p"使fetch之後刪除沒有與遠端分支對應的本地分支。 當然也可以通過檢視遠端分支。使用命令"git remote show origin"顯示如下:

YJTSuper:yjtim super$ git remote show origin 
* remote origin
  Fetch URL: git@git.oschina.net:lingsui/yjtim.git
  Push  URL: git@git.oschina.net:lingsui/yjtim.git
  HEAD branch: master
  Remote branches:
    dev                      tracked
    im                       tracked
    master                   tracked
    proV2.3.0                tracked
    refs/remotes/origin/test stale (use 'git remote prune' to remove)
  Local branches configured for 'git pull':
    master merges with remote master
    show   merges with remote master
  Local refs configured for 'git push':
    dev       pushes to dev       (up to date)
    im        pushes to im        (fast-forwardable)
    master    pushes to master    (up to date)
    proV2.3.0 pushes to proV2.3.0 (up to date)

我們可以看到分支origin/test 已經過期(stale),可以使用命令"git remote prune origin"同樣可以處理。

5.遠端地址切換


如果想要切換遠端地址,千萬不要重新再初始化一個git程式碼倉庫,使用git add重新新增。這樣的好處只有一點,所有歷史提交資訊全部清空,不再保留,"git clone"時檔案變小,理所當然,歷史記錄全部清空了麼。如果確定不保留,也建議這樣做,關鍵時,誰寫的程式碼更改了哪些東西很重要呀,還是選擇保留吧。使用下面的方法,一行程式碼搞定,並且保留了所有的commit記錄。

git remote -v  // 檢視遠端地址
git remote set-url origin https://git.oschina.net/HaiShengHuo/xxx.git // 更換遠端地址, 新建一個專案不新增任何檔案  在本地直接push即可

6.檢視某次提交修改的具體檔案


方法一

git reflog 列出最新修改記錄 也可以 git log --oneline
git log 00788a04 --name-status 找到對應版本號 執行

commit 00788a04f8d6dd834723c3479a0b5cdcfad8694a
Author: ZhiChao <13424490552@163.com>
Date:   Thu Mar 30 11:04:46 2017 +0800

    最後一條訊息顯示來源人

M       yjtim/IM/Chat/Controller/ConversationListController.m

commit a4b9129f1728dc10d5f6ab8c77c1b20ef7bb3d12
Author: ZhiChao <13424490552@163.com>
Date:   Wed Mar 29 17:49:44 2017 +0800

    隱藏被入群彈框

M       yjtim/IM/Chat/Controller/ChatDemoHelper.m

commit 1910008369d4ab264e7610997135a54d27fe22c7
Author: ZhiChao <13424490552@163.com>
Date:   Wed Mar 29 17:40:56 2017 +0800

    99+

M       yjtim/IM/EaseUI/EMUIKit/Views/conversation/toolbar/EaseImageView.m

git diff HEAD@{79} HEAD@{78} 具體某次修改的內容(具體某次內容和上次的內容進行比較)
git diff a4b9129f 00788a04 當然也可以使用版本號

這樣假如之前修改過具體某些內容,以後還需要修改的話,找起來真的很方便.好比某些bug好久之後才發現,又要回頭去修改,而修改總要找到對應的程式碼進行修改吧,這樣幾行命令就定位到具體檔案和位置了,方便多了,節省很多時間.找程式碼有技巧,但是"找"終究還是很浪費時間.這也告訴我們,commit 提交命令很重要,需要認真寫,不可為了省事而亂寫

diff --git a/yjtim/IM/Chat/Controller/ConversationListController.m b/yjtim/IM/Chat/Controller/ConversationListController.m
index df0555e5..71822638 100644
--- a/yjtim/IM/Chat/Controller/ConversationListController.m
+++ b/yjtim/IM/Chat/Controller/ConversationListController.m
@@ -347,7 +347,7 @@ - (NSAttributedString *)conversationListViewController:(EaseConversationListView
             [attributedStr setAttributes:@{NSForegroundColorAttributeName : [UIColor colorWithRed:1.0 green:.0 blue:.0 alpha:0.5]} range:NSMakeRange(0, NSLocalizedString(@"group.atMe", @"[Somebody @ me]").length)];
         }
         else {
-            attributedStr = [[NSMutableAttributedString alloc] initWithString:latestMessageTitle];
+            attributedStr = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@:%@",[[YJTAddressList shareAddressList].userNameDict objectForKey:lastMessage.from],latestMessageTitle]];
         }
     }
     

方法二

直接使用git log 6b81a31033 -p 或則 git log -p 6b81a31033 其中6b81a31033為版本雜湊值

commit 6b81a31033074ef279049e9cbf5944e3158d7510
Author: ZhiChao <13424490552@163.com>
Date:   Fri Apr 14 13:57:22 2017 +0800

    綜合評價fixbug

diff --git a/yjtim/Sections/Apps/NewEvaluation/Controller/YJTEvaDetailVC.m b/yjtim/Sections/Apps/NewEvaluation/Controller/YJTEvaDetailVC.m
index 10ff4b31..cef73191 100644
--- a/yjtim/Sections/Apps/NewEvaluation/Controller/YJTEvaDetailVC.m
+++ b/yjtim/Sections/Apps/NewEvaluation/Controller/YJTEvaDetailVC.m
@@ -28,7 +28,7 @@ @interface YJTEvaDetailVC ()<YJTEvaDateSelectVCDelegate>
 @property (nonatomic, strong) NSArray *catListArray;
 @property (nonatomic, strong) YJTEvaSchoolYearModel *evaSchoolYearModel;
 
-
+@property (nonatomic, copy) NSString *formId;
  @property (nonatomic, copy) NSString *className;
  @property (nonatomic, copy) NSString *classId;
  @property (nonatomic, copy) NSString *tempClassId;
  @@ -262,6 +262,7 @@ - (void)rightBtnClick {
     editVC.evaListModel = self.evaListModel;
     editVC.catListArray = self.catListArray;
...

方法三

git log --stat 6b81a31033或者git log 6b81a31033 --stat 檢視簡潔檔案變化

commit 6b81a31033074ef279049e9cbf5944e3158d7510
Author: ZhiChao <13424490552@163.com>
Date:   Fri Apr 14 13:57:22 2017 +0800

    綜合評價fixbug

 yjtim/Sections/Apps/NewEvaluation/Controller/YJTEvaDetailVC.m | 5 +++--
 yjtim/Sections/Apps/NewEvaluation/Controller/YJTEvaEditVC.h   | 1 +
 yjtim/Sections/Apps/NewEvaluation/Controller/YJTEvaEditVC.m   | 2 +-
 3 files changed, 5 insertions(+), 3 deletions(-)

7.忽略跟蹤


git checkout .   清空所有更改
以下命令是我們在專案中已經新增了.gitignore  但是中途突然不想再跟蹤某檔案
此時發現簡單的在.gitignore檔案中新增要忽略的檔案是不起效的,因為該檔案已
經被track,我們還需要將其狀態改為 未track(其實只需刪除暫緩區檔案然後將操作體檢即可)
git rm --cached Podfile.lock  將Podfile.lock從暫緩區刪除,不再跟蹤

8.備份


備份的話好一些,每次新的版本打一次tag,檢視起來還是挺方便。不過不用也行。我不愛使用這個。

git tag -a WeChat1.0 -m "version 1.0" :給版本打上標籤
git tag : 檢視所有的標籤
git push origin WeChat1.0 : 將WeChat1.0 push 到預設分支

9.版本回退


git reset --hard HEAD // 沒有提交的情況下進行版本回退
git reset --hard HEAD^ // 回退到上一個版本
git reset --hard HEAD^^ // 回退到指定回退到某個版本
git reset --hard 版本號(至少前5位) // 回退到前幾個版本
git reset --hard~1
git revert c011eb3c20ba6fb38cc94fe5a8dda366a3990c61 // 注意該行命令 reset和revert有本質區別

注意:開發中一般受控代碼到遠端程式碼倉庫,比如Github或則OSChina,加入本地已經使用git push到遠端程式碼倉庫,在本地使用git reset回退再push明顯是不可行的。因為git reset直接回退到歷史中的某個Hash值,但是使用git revert就不一樣了。git revert將作為一次新提交(新的Hash值)而不是歷史中的某個Hash值,此時再push到遠端程式碼倉庫情理之中。

10.紀錄檔


想回顧下提交歷史,可以使用 git log 命令,其中有個--pretty 引數可以設定
git log --pretty=oneline
git log --pretty=format:"%h - %an, %ar : %s"
git log --pretty=format:"%h %s" --graph
git log --since=2.weeks
自己可以試一下,這裡附上引數說明,自己可以隨意設定,當然log字型顏色也都是可以修改的,不再細述。

選項說明
%H 提交物件(commit)的完整雜湊字串 %h 提交物件的簡短雜湊字串 .....................................................................................................
%T 樹物件(tree)的完整雜湊字串
%t 樹物件的簡短雜湊字串
%P 父物件(parent)的完整雜湊字串 %p 父物件的簡短雜湊字串
%an 作者(author)的名字
%ae 作者的電子郵件地址
%ad 作者修訂日期(可以用 -date= 選項客製化格式) %ar 作者修訂日期,按多久以前的方式顯示
%cn 提交者(committer)的名字
%ce 提交者的電子郵件地址
%cd 提交日期
%cr 提交日期,按多久以前的方式顯示 %s 提交說明

時間和提交者過濾

選項說明
-(n) 僅顯示最近的 n 條提交....................................................................................................................................................
--since, --after 僅顯示指定時間之後的提交。
--until, --before 僅顯示指定時間之前的提交。
--author 僅顯示指定作者相關的提交。
--committer 僅顯示指定提交者相關的提交。

你一定奇怪_作者(author)_和_提交者(committer)_之間究竟有何差別,其實作者指的是實際作出修改 的人,提交者指的是最後將此工作成果提交到倉庫的人。所以,當你為某個專案發去修補程式,然後某個核心成員將你的修補程式併入專案時,你就是作者,而那個核心成員就是提交者。我們會在第五章再詳細介紹兩者之間的細緻差別。

11.忽略某些檔案


檔案 .gitignore 的格式規範如下:
• 所有空行或者以注釋符號 # 開頭的行都會被 Git 忽略。
• 可以使用標準的 glob 模式匹配。
• 匹配模式最後跟反斜槓(/)說明要忽略的是目錄。
• 要忽略指定模式以外的檔案或目錄,可以在模式前加上驚嘆號(!)取反。
所謂的 glob 模式是指 shell 所使用的簡化了的正規表示式。星號(*)匹配零個或多個任意字元;[abc] 匹配 任何一個列在方括號中的字元(這個例子要麼匹配一個 a,要麼匹配一個 b,要麼匹配一個 c);問號(?) 只匹配一個任意字元;如果在方括號中使用短劃線分隔兩個字元,表示所有在這兩個字元範圍內的都可以匹配 (比如 [0-9] 表示匹配所有 0 到 9 的數位)。

# 此為註釋 – 將被 Git 忽略
*.[oa]  Git 忽略所有以 .o 或 .a 結尾的檔案。一般這類物件檔案和存檔檔案都是編譯過程中出現 的,我們用不著跟蹤它們的版本
*~  Git 忽略所有以波浪符(~)結尾的檔案,許多文字編輯軟體 (比如 Emacs)都用這樣的檔名儲存副本
*.a # 忽略所有 .a 結尾的檔案
!lib.a # 但 lib.a 除外
/TODO # 僅僅忽略專案根目錄下的 TODO 檔案,不包括 subdir/TODO build/ # 忽略 build/ 目錄下的所有檔案
doc/*.txt # 會忽略 doc/notes.txt 但不包括 doc/server/arch.txt

更多 Git 教學系列文章: 

GitHub 使用教學圖文詳解  http://www.linuxidc.com/Linux/2014-09/106230.htm 

Git使用圖文詳細教學  http://www.linuxidc.com/Linux/2016-11/136781.htm

Ubuntu Git安裝與使用 http://www.linuxidc.com/Linux/2016-11/136769.htm

Git 標籤管理???解 http://www.linuxidc.com/Linux/2014-09/106231.htm 

Git 分支管理詳解 http://www.linuxidc.com/Linux/2014-09/106232.htm 

Git 遠端倉庫詳解 http://www.linuxidc.com/Linux/2014-09/106233.htm 

Git 本地倉庫(Repository)詳解 http://www.linuxidc.com/Linux/2014-09/106234.htm 

Git 伺服器搭建與用戶端安裝  http://www.linuxidc.com/Linux/2014-05/101830.htm 

Git 概述 http://www.linuxidc.com/Linux/2014-05/101829.htm 

分享實用的GitHub 使用教學 http://www.linuxidc.com/Linux/2014-04/100556.htm 

Git從入門到學會 http://www.linuxidc.com/Linux/2016-10/135872.htm

Git基本操作詳解 http://www.linuxidc.com/Linux/2016-10/135691.htm

Git部署與常用基本命令詳解   http://www.linuxidc.com/Linux/2017-06/144961.htm

分散式版本控制系統 Git 詳細教學  http://www.linuxidc.com/Linux/2017-05/143747.htm


IT145.com E-mail:sddin#qq.com