我在工做中是如何使用 git 的

這是第 103 篇不摻水的原創,想獲取更多原創好文,請搜索公衆號關注咱們吧~ 本文首發於政採雲前端博客:我在工做中是如何使用 git 的html

奕承.png

image

前言

最近在網上有個真實發生的案例比較火,說的是一個新入職的員工,不會用 Git 拉代碼,次日被開除。由此,可見 Git 對咱們工做的重要性,不管是前端後端,都是離不開 Git 的,下面就讓咱們一探究竟吧。前端

上面的案例引伸出一個問題,入職一家新公司,你的 leader 給你分配了倉庫的權限後,如何配置本地的 Git 環境並拉取代碼?莫慌,按照下面我講的四個步驟走,保證你能夠順利使用 Git 進行拉取代碼!ios

  1. 下載 Git 下載地址 ,選擇本身系統對應的版本下載便可。git

  2. 在你的電腦上生成 ssh 祕鑰,打開終端,執行 ssh-keygen -t rsa -C "你公司內部郵箱地址",若是執行成功,切換到 ~/.ssh 目錄下,此時目錄應該以下所示。複製 id_rsa.pub 的內容。程序員

    image-20210519163921819.png

  3. 這裏以 Github 爲例,以下圖所示,進入 settings -> SSH and GPG keys 經過 cat 命令查看文件 id_rsa.pub 的內容,而後複製過來,點擊 add ssh key,這一步等於說把你的公鑰放到了 Github 上進行託管。shell

    image-20210519164643069.png

  4. 全局配置 Git 的用戶名和郵箱axios

git config --global user.name "xxx"
git config --global user.email "xxx@xx.com"
複製代碼

完成以上四步,你就能夠愉快 pull 代碼開發了。和 https 拉取方式不一樣的是,https 方式須要每次提交前都手動輸入用戶名和密碼,ssh 的方式配置完畢後 Git 都會使用你本地的私鑰和遠程倉庫的公鑰進行驗證是不是一對祕鑰,從而簡化了操做流程。vim

Git簡介

在介紹 Git 的相關操做前,我以爲很是有必要了解 Git 的由來,以及 Git 是用來解決什麼問題的。Git(讀音爲/gɪt/)是一個開源的分佈式版本控制系統,能夠有效、高速地處理從很小到很是大的項目版本管理。 Linus Torvalds ,這我的我相信你們都知道吧,開源 Linux 系統的發明人。現在,你看到的大部分服務器其實都是運行在 Linux 系統上,使人感到稱歎的是,這位大神級別的程序員不只創造了 Linux 系統。那 Linux 的代碼是如何管理的呢?2002年以前,世界各地的志願者把源代碼文件經過 diff 的方式發給 Linus,而後由 Linus 本人經過手工方式合併代碼!要知道,當時的 Linux 的代碼量已經很大了,經過人工管理的方式,一是容易出錯,二是效率低。因而 Linus 選擇了一個商業的版本控制系統 BitKeeper,BitKeeper 的東家 BitMover 公司出於人道主義精神,受權 Linux 社區無償使用這個版本控制系統。最後,出於某種緣由,BitMover 公司收回了 Linux 社區的無償使用權,因而 Linus 花了兩週時間本身用 C 語言 寫了一個分佈式版本控制系統,這就是 Git 的由來了。後端

img

Git 的工做區域和流程

要想弄懂 Git 是怎麼對咱們的代碼進行管理的,那首當其衝的是瞭解 Git 的工做區域是如何構成的。由於,只有完全弄懂了 Git 工做區域的構成,你才能夠在適當的區域使用合適的命令。以下圖所示,此圖包含了 Git 的4個工做區和一些常見的操做。緩存

git

Workspace:工做區,就是平時進行開發改動的地方,是當前看到最新的內容,在開發的過程也就是對工做區的操做

Index:暫存區,當執行 git add 的命令後,工做區的文件就會被移入暫存區,暫存區標記了當前工做區中那些內容是被 Git 管理的,當完成某個需求或者功能後須要提交代碼,第一步就是經過 git add 先提交到暫存區。

Repository:本地倉庫,位於本身的電腦上,經過 git commit 提交暫存區的內容,會進入本地倉庫。

Remote:遠程倉庫,用來託管代碼的服務器,遠程倉庫的內容可以被分佈在多個地點的處於協做關係的本地倉庫修改,本地倉庫修改完代碼後經過 git push 命令同步代碼到遠程倉庫。

通常來講,Git 的工做流程分爲如下幾步

1.在工做區開發,添加,修改文件。
2.將修改後的文件放入暫存區。
3.將暫存區域的文件提交到本地倉庫。
4.將本地倉庫的修改推送到遠程倉庫。
複製代碼

Git 基本操做

git add

添加文件到暫存區

# 添加某個文件到暫存區,後面能夠跟多個文件,以空格區分
git add xxx
# 添加當前更改的全部文件到暫存區。
git add .
複製代碼

git commit

# 提交暫存的更改,會新開編輯器進行編輯
git commit 
# 提交暫存的更改,並記錄下備註
git commit -m "you message"
# 等同於 git add . && git commit -m
git commit -am
# 對最近一次的提交的信息進行修改,此操做會修改commit的hash值
git commit --amend
複製代碼

git pull

# 從遠程倉庫拉取代碼併合併到本地,可簡寫爲 git pull 等同於 git fetch && git merge 
git pull <遠程主機名> <遠程分支名>:<本地分支名>
# 使用rebase的模式進行合併
git pull --rebase <遠程主機名> <遠程分支名>:<本地分支名>
複製代碼

git fetch

git pull 不一樣的是 git fetch 操做僅僅只會拉取遠程的更改,不會自動進行 merge 操做。對你當前的代碼沒有影響

# 獲取遠程倉庫特定分支的更新
git fetch <遠程主機名> <分支名>
# 獲取遠程倉庫全部分支的更新
git fetch --all
複製代碼

git branch

# 新建本地分支,但不切換
git branch <branch-name> 
# 查看本地分支
git branch
# 查看遠程分支
git branch -r
# 查看本地和遠程分支
git branch -a
# 刪除本地分支
git branch -D <branch-nane>
# 從新命名分支
git branch -m <old-branch-name> <new-branch-name>
複製代碼

工做中使用 Git 解決問題的場景

git rebase 讓你的提交記錄更加清晰可讀

git rebase 的使用

rebase 翻譯爲變基,他的做用和 merge 很類似,用於把一個分支的修改合併到當前分支上。

以下圖所示,下圖介紹了通過 rebase 後提交歷史的變化狀況。

WechatIMG2.png

如今咱們來用一個例子來解釋一下上面的過程。

假設咱們如今有2條分支,一個爲 master,一個爲 feature/1,他們都基於初始的一個提交 add readme 進行檢出分支,以後,master 分支增長了 3.js 和 4.js 的文件,分別進行了2次提交,feature/1 也增長了 1.js 和 2.js 的文件,分別對應如下2條提交記錄。

此時,對應分支的提交記錄以下。

master 分支以下圖:

image-20210531144909187.png

feature/1 分支以下圖

image-20210531145504071.png

結合起來看是這樣的

image-20210531145553107.png

此時,切換到 feature/1 分支下,執行 git rebase master,成功以後,經過 git log 查看記錄。

以下圖所示:能夠看到先是逐個應用了 mater 分支的更改,而後以 master 分支最後的提交做爲基點,再逐個應用 feature/1 的每一個更改。

image-20210531150719965.png

因此,咱們的提交記錄就會很是清晰,沒有分叉,上面演示的是比較順利的狀況,可是大部分狀況下,rebase 的過程當中會產生衝突的,此時,就須要手動解決衝突,而後使用依次 git add git rebase --continue 的方式來處理衝突,完成 rebase 的過程,若是不想要某次 rebase 的結果,那麼須要使用 git rebase --skip 來跳過此次 rebase 操做。

git merge 和 git rebase 的區別

不一樣於 git rebase 的是,git merge 在不是 fast-forward(快速合併)的狀況下,會產生一條額外的合併記錄,相似 Merge branch 'xxx' into 'xxx' 的一條提交信息。

image-20210531151838328.png

另外,在解決衝突的時候,用 merge 只須要解決一次衝突便可,簡單粗暴,而用 rebase 的時候 ,須要依次解決每次的衝突,才能夠提交。

git rebase 交互模式

在開發中,常會遇到在一個分支上產生了不少的無效的提交,這種狀況下使用 rebase 的交互式模式能夠把已經發生的屢次提交壓縮成一次提交,獲得了一個乾淨的提交歷史,例如某個分支的提交歷史狀況以下:

image-20210518211345258.png

進入交互式模式的方式是執行:

git rebase -i <base-commit>
複製代碼

參數 base-commit 就是指明操做的基點提交對象,基於這個基點進行 rebase 的操做,對於上述提交歷史的例子,咱們要把最後的一個提交對象( ac18084 )以前的提交壓縮成一次提交,咱們須要執行的命令格式是:

git rebase -i ac18084
複製代碼

此時會進入一個 vim 的交互式頁面,編輯器列出的信息像下列這樣。

image-20210518212036198.png

想要合併這一堆更改,咱們要使用 Squash 策略進行合併,即把當前的 commit 和它的上一個 commit 內容進行合併, 大概能夠表示爲下面這樣,在交互模式的 rebase 下,至少保留一個 pick,不然命令會執行失敗。

pick  ... ...
s     ... ... 
s     ... ... 
s     ... ... 
複製代碼

修改文件後 按下 : 而後 wq 保存退出,此時又會彈出一個編輯頁面,這個頁面是用來編輯提交的信息,修改成 feat: 更正,最後保存一下,接着使用 git branch 查看提交的 commit 信息,rebase 後的提交記錄以下圖所示,是否是清爽了不少?rebase 操做可讓咱們的提交歷史變得更加清晰。

image-20210518212812000.png

特別注意,只能在本身使用的 feature 分支上進行 rebase 操做,不容許在集成分支上進行 rebase,由於這種操做會修改集成分支的歷史記錄。

使用 git cherry-pick 獲取指定的 commit

git cherry-pick 能夠理解爲」挑揀」提交,和 merge 合併一個分支的全部提交不一樣的是,它會獲取某一個分支的單筆提交,並做爲一個新的提交引入到你當前分支上。當咱們須要在本地合入其餘分支的提交時,若是咱們不想對整個分支進行合併,而是隻想將某一次提交合入到本地當前分支上,那麼就要使用 git cherry-pick 了。

以下場景,如下有三條分支,feature/cherry-pick1 和 feature/cherry-pick2 都是基於 master 檢出的兩條功能性分支,對應的分支 log 記錄以下

image-20210518221001432.png

image-20210518221010458.png

master 分支的提交以下 image-20210518221051734.png

如今 master 只須要 feature/cherry-pick1 和 feature/cherry-pick2 有關 change 的修改,並不關心有關 fix 內容的修改。此時就能夠用 cherry-pick 指令了。

語法: git cherry-pick [commit-hash]

commit-hash 表示的是某次 commit 的 hash 值。如今,依次執行如下兩條指令 git cherry-pick e0bb7f3git cherry-pick c9a3101,過程當中,若是出現衝突,解決衝突後 進行 git add ,接着執行 git cherry-pick --continue,最後,master 上的提交以下

image-20210518235707190.png

此時,master 分支上應用了須要的提交,就達到了咱們想要的效果。若是須要多個 cherry-pick 須要同步到目標分支,能夠簡寫爲 git cherry-pick <first-commit-id>...<last-commit-id>,這是一個左開右閉的區間,也就時說 first-commit-id 提交帶來的代碼的改動不會被合併過去,若是須要合併過去,可使用 git cherry-pick <first-commit-id>^...<last-commit-id>,它表示包含 first-commit-idlast-commit-id 在內的提交都會被合併過去。

使用 git revert 回滾某次的提交

想象這麼一個場景,你的項目最近有2個版本要上線,這兩個版本還伴隨着以前遺留的 bug 的修復,一開始的時候,你將 bug 修復在了第一個版本的 release 分支上,忽然在發版前一天,測試那邊反饋,須要把第一個版本修復 bug 的內容改在第二個版本上,這個時候,第一個版本的集成分支的提交應該包括了第一個版本的功能內容,遺留 bug 修復的提交和其餘同事提交的內容,想要經過 reset 的方式粗暴摘除以前的關於 bug 修復的 commit 確定是不行的,同時,這種作法比較危險,此時,咱們既不想破壞以前的提交記錄,又想撤回咱們遺留 bug 的 commit 記錄應該怎麼作呢?git revert 就派上了用場。

git revert 撤銷某次操做,此操做不會修改本來的提交記錄,而是會新增一條提交記錄來抵消某次操做。

語法: git revert <commit-id> 針對普通 commit

git revert <commit-id> -m 針對 merge 的 commit

下面就用一個案例來理解一下這個命令,以下圖所示,假設被紅框框起來的地方是會引發 bug 的一次提交,在他的提交以後,又進行了2次提交,其中包含了其它同事的提交。

image-20210519142702752.png

此時想把引發提交的 bug 的幹掉,執行 git revert 1121932,執行操做後,再打開查看日誌,以下圖所示,能夠看到是新增了一條 commit 記錄,這個 commit 的產生的 msg 是自動生成的,Revert 開頭,後面跟撤回的 commit-msg 信息 以前的 commit 記錄並無消失,此時也達到了代碼回退的效果

image-20210519142824836.png

此外 git revert 也能夠回滾屢次的提交

語法:git revert [commit-id1] [commit-id2] ... 注意這是一個前開後閉區間,即不包括 commit1 ,但包括 commit2 。

回滾咱們的提交有二種方式,一種是上文提到的git revert命令外,還可使用 git reset 命令,那麼它們二者有什麼區別呢?

git revert 會新建一條 commit 信息,來撤回以前的修改。

git reset 會直接將提交記錄退回到指定的 commit 上。

對於我的的 feature 分支而言,可使用 git reset 來回退歷史記錄,以後使用 git push --force 進行推送到遠程,可是若是是在多人協做的集成分支上,不推薦直接使用 git reset 命令,而是使用更加安全的 git revert 命令進行撤回提交。這樣,提交的歷史記錄不會被抹去,能夠安全的進行撤回。

使用 git stash 來暫存文件

會有這麼一個場景,如今你正在用你的 feature 分支上開發新功能。這時,生產環境上出現了一個 bug 須要緊急修復,可是你這部分代碼還沒開發完,不想提交,怎麼辦?這個時候能夠用 git stash 命令先把工做區已經修改的文件暫存起來,而後切換到 hotfix 分支上進行 bug 的修復,修復完成後,切換回 feature 分支,從堆棧中恢復剛剛保存的內容。

基本命令以下

git stash //把本地的改動暫存起來
git stash save "message" 執行存儲時,添加備註,方便查找。
git stash pop // 應用最近一次暫存的修改,並刪除暫存的記錄
git stash apply  // 應用某個存儲,但不會把存儲從存儲列表中刪除,默認使用第一個存儲,即 stash@{0},若是要使用其餘個,git stash apply stash@{$num} 。
git stash list // 查看 stash 有哪些存儲
git stash clear // 刪除全部緩存的 stash
複製代碼

下面經過幾幅圖對 stash 的命令作進一步瞭解。

此時,我正在開發一個新功能,修改了 1.js 文件裏的內容

image-20210519175036869.png

還沒開發完成,這個時候,我想切換到 hotfix 分支上修復 bug,得暫停下開發切換到 hotfix 分支,可是如今工做區還有內容,此時若是切換分支 Git 會報出下面的錯誤

error: Your local changes to the following files would be overwritten by checkout:
        1.js
Please commit your changes or stash them before you switch branches.
Aborting
複製代碼

上面那句話的意思就是說工做區有文件修改,不能提交,須要先進行 commit 或者 stash 操做,執行 git stash,結果以下

Saved working directory and index state WIP on stash: 22e561c feat: add 1.js
複製代碼

此時,咱們的工做區已經乾淨了,能夠切換到 hotfix 分支進行 bug 修復的工做,假設咱們如今 bug 修復完成了,繼續切回 feature 分支進行本來功能的開發,此時只須要執行 git stash pop,以前咱們暫存的修改就會恢復到工做區,以下圖所示。

image-20210519185011012.png

當咱們想要暫存文件,切換分支作某些事的時候,能夠用 git stash 這種機制幫助開發。

推薦在使用 stash 的相關命令時,每一次暫存的時候,不要直接使用 git stash 命令進行暫存下來,而是使用 git stash save "message..." 這種方式,給本次的提交作一個信息的記錄。這樣,想應用更改的時候,先經過 git stash list 查看一下全部的暫存列表。以後,推薦使用 git stash apply stash@${num} 的方式進行應用對應的 stash,這樣不會清空已有的 stash 的列表項,而且能應用到當前的工做區,不須要這個暫存的話,再手動清除就能夠了。

不一樣的工做區域撤銷更改

開發中,咱們常常須要回退代碼的操做,在不一樣的工做區域中,回退代碼的方式也是不相同的。以下圖所示,假設如今要在 feature/revoke 分支上進行開發,

首先經過 git status 查看下如今的狀態。

image-20210520115802579.png

目前咱們的工做區是很乾淨的,沒有任何修改的操做,此時,修改一下代碼再次查看狀態,能夠看到,1.js 這個文件被修改了。

image-20210520115934693.png

如今咱們想把 1.js 這個文件恢復到修改前的狀態,即撤回工做區的修改,就可使用 git checkout -- <filename> 的命令,若是要撤回多個文件的修改,文件之間使用空格隔開,以下圖所示,咱們撤回了 1.js 文件的修改,工做區也恢復乾淨了。

image-20210520120242475.png

若是說如今咱們對文件進行了修改,而且已經提交到暫存區了,這部分文件咱們不想要的話,那麼就能夠經過 git reset <filename> 的命令來對特定的文件進行撤銷,git reset 會撤回全部存在暫存區的文件,以下圖所示,查看先後的狀態可知,文件最後成功撤回到工做區了。

image-20210520141538130.png

配置 git alias 提高工做效率

通常咱們在工做中,接到開發任務後,須要新建立一個分支進行開發 此時須要 用到 git branchgit checkoutgit pull 等命令,在咱們一頓操做後,開發完成,到了提交代碼的階段,又要諸如此類 git addgit commitgit push 等命令,雖然簡單,可是輸入起來也是不夠簡潔,做爲一個程序員,開發程序就是爲了提升咱們的效率的,懶是人類進步的源泉,因此咱們能夠經過配置別名的方式,簡化這些命令。

它的基本用法是 git config --global alias.<簡化的字符> 原始命令

以下面的例子:

$ git config --global alias.co checkout
$ git config --global alias.ci commit
$ git config --global alias.br branch
複製代碼

這裏將 co 表示 checkout,ci 表示 commit,br 表示 branch,之後提交就能夠簡寫成

image-20210519152804390.png

--global 是全局參數,也就是配置一次後,這些命令能夠在這臺電腦下的全部倉庫都適用。這些命令實際上是更新你全局的 .gitconfig 文件,該文件用來保存全局的 git 配置,vim ~/.gitconfig,執行這段命令後,顯示以下,下圖展現了剛纔經過 git config --global alias 添加的 alias

image-20210519153624712.png

除了上面那種直接經過命令的方式外,也能夠經過修改這個文件的 alias 項來設置別名。

這裏分享一個我本身經常使用的別名設置,把如下配置替換到 .gitconfig 文件裏的 [alias] 所屬的區域,而後就能夠愉快的使用了~

[alias]
st = status -sb
co = checkout
br = branch
mg = merge
ci = commit
ds = diff --staged
dt = difftool
mt = mergetool
last = log -1 HEAD
latest = for-each-ref --sort=-committerdate --format=\"%(committername)@%(refname:short) [%(committerdate:short)] %(contents)\"
ls = log --pretty=format:\"%C(yellow)%h %C(blue)%ad %C(red)%d %C(reset)%s %C(green)[%cn]\" --decorate --date=short
hist = log --pretty=format:\"%C(yellow)%h %C(red)%d %C(reset)%s %C(green)[%an] %C(blue)%ad\" --topo-order --graph --date=short
type = cat-file -t
dump = cat-file -p
lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
複製代碼

這樣,咱們每次想查看 Git 的歷史記錄,就不用輸入那麼一長串命令 直接使用 git lg ,下圖是 axios 源碼裏的提交記錄,使用封裝後的 git lg 查看的效果圖

image-20210519162327693.png

分支之間的關係一眼就很明瞭,在哪一個 commit 上進行的 merge 操做也很清晰,能夠幫助咱們很好的追溯歷史的提交和解決問題。

總結

本文由淺入深的的講解了 Git 的環境搭建,基本用法,以及工做中使用較爲高頻的 Git 命令的用法,不管你是前端後端仍是其它端的開發,平常工做中少不了對 Git 的使用,咱們不只要會用,還要用的漂亮,用的靈活,用的穩健。這樣才能在和同事協做項目的時候更加駕輕就熟,學會了本文這些 Git 的使用技巧後,在平常工做中多多練習,相信會給你帶來很大的收穫!

參考文獻

阮一峯的git教程

Git merge和rebase分支合併命令的區別

推薦閱讀

v8 執行 js 的過程

手把手帶你入門Webpack Plugin

開源做品

  • 政採雲前端小報

開源地址 www.zoo.team/openweekly/ (小報官網首頁有微信交流羣)

招賢納士

政採雲前端團隊(ZooTeam),一個年輕富有激情和創造力的前端團隊,隸屬於政採雲產品研發部,Base 在風景如畫的杭州。團隊現有 40 餘個前端小夥伴,平均年齡 27 歲,近 3 成是全棧工程師,妥妥的青年風暴團。成員構成既有來自於阿里、網易的「老」兵,也有浙大、中科大、杭電等校的應屆新人。團隊在平常的業務對接以外,還在物料體系、工程平臺、搭建平臺、性能體驗、雲端應用、數據分析及可視化等方向進行技術探索和實戰,推進並落地了一系列的內部技術產品,持續探索前端技術體系的新邊界。

若是你想改變一直被事折騰,但願開始能折騰事;若是你想改變一直被告誡須要多些想法,卻無從破局;若是你想改變你有能力去作成那個結果,卻不須要你;若是你想改變你想作成的事須要一個團隊去支撐,但沒你帶人的位置;若是你想改變既定的節奏,將會是「5 年工做時間 3 年工做經驗」;若是你想改變原本悟性不錯,但老是有那一層窗戶紙的模糊… 若是你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的本身。若是你但願參與到隨着業務騰飛的過程,親手推進一個有着深刻的業務理解、完善的技術體系、技術創造價值、影響力外溢的前端團隊的成長曆程,我以爲咱們該聊聊。任什麼時候間,等着你寫點什麼,發給 ZooTeam@cai-inc.com

相關文章
相關標籤/搜索