git各命令的原理和初級使用,順手玩下git鉤子

該文章是在閱讀猴子也懂的git入門拋物線大神的git原理和使用小冊子,額,須要一點點零花錢以後總結的,估摸着不適合新手...html

TL;DR

  • 核心概念:暫存區(索引),數據庫(repository)是每一個commit組成的,HEAD/branch/tag都指向某個commit
  • 遠程倉庫實際上和本地倉庫沒啥不一樣,純粹爲了7x24小時開機並交換你們的修改。
  • 沒事經常git statusgit lg,沒寫錯,配置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執行某條命令的時候執行腳本,就用到鉤子
  • 搭建遠程倉庫

git概念理解

  • 沒有git的時候,想要保存文件的狀態只能備份備份再備份,若是放到服務器上指不定還被誰不當心的覆蓋了。用git管理文件的時候,更新的歷史會保存在git裏,也不會輕易被覆蓋。
  • 文件更新的歷史保存git的數據庫(repository)。有本地的數據庫還有遠程數據庫,能夠本身新建,也能夠複製遠程的。
  • 若要把文件或目錄的添加和變動保存到數據庫,就須要進行提交,執行提交後,數據庫中會生成上次提交的狀態與當前狀態的差別記錄(也被稱爲revision),系統根據修改的內容計算出40位數字和英文生成版本號,俗稱某個commit或者某個版本
  • 實際操做的目錄稱爲工做樹(working tree),在數據庫和工做樹之間有索引,索引是爲了向數據庫提交作準備的區域。沒有索引的文件是不能提交到數據庫的~。索引不少時候又被稱爲stage,暫存區。工做樹的內容跟着HEAD走。一旦HEAD指向新的版本,工做樹的內容也會變成那個版本,形同備份~
  • branch、tag、HEAD都是某個版本的引用,能夠想象,數據庫是一條橫着的線,每次提交就是一個點,每一個點有本身的id,點上面可能有branch、tag、HEAD這幾個指向

git命令的本質

  • git clone url [projectName]複製url的遠程數據庫到本地,git會將這個遠程數據庫命名爲origin,projectName可選,省略的話文件夾名字同遠程數據庫的,寫的話就重命名。這裏HEAD指向master分支的最新的版本,天然工做區也跟着HEAD。
    圖片是拋物線大神的
  • git add file/.,將工做樹的某些文件建立索引的,.表示全部文件,注意,add添加的不是文件名字,而是文件改動的內容。新文件必須經過這個才讓git追蹤這個文件。否則git不知道該文件的存在。
  • git commit -m"認真寫改了啥",將索引添加到本地數據庫,能夠想象成橫線多了一個點,又長了些。HEAD自動更新到新的commit,且HEAD會拖着當前的分支,讓其也指向新的commit。
  • git pull [origin] [master],將遠程數據庫的某個分支的內容更新到本地數據庫的相應分支,pull 的內部操做實際上是把遠程倉庫取到本地後(使用的是 fetch),再用一次 merge 來把遠端倉庫的新 commits 合併到本地。後面兩項是指哪一個遠程倉庫的哪一個分支,省略的話是origin,而後當前目錄所在的分支。這裏注意,執行這個操做的時候,可能遠程數據庫和本地數據庫合併的時候,有衝突,解決掉就好,而後git add .;git commit本地的數據庫從分叉的地方開始插入到遠程數據庫裏更新的後面,有衝突的話將會生成多生成一個commit。能夠git log看看
  • git push [origin] [master],將本地的數據庫添加到遠程數據庫哪一個分支,若是老是想省略(我是省略重度依賴者。。),git config --global push.default current,這樣是處在哪一個分支就會更新origin的哪一個分支。若是實在master分支,這個操做會讓origin/HEAD,origin/master指向最新的commit,也就是遠程倉庫的HEAD和master指針。
  • git checkout [-b] branch,將 HEAD 指向branch ,工做目錄的文件內容跟着HEAD,變成這個版本的內容 ,俗稱切換分支,固然後面的參數能夠是任意的commitID,須要注意的是,當前目錄所在分支儘可能clean,若是有須要提交的可能會切換失敗,若是切換成功,默認爲在新的分支下作了這些變動。-b通常是建立新分支且切換到新分支的意思。
  • git stash -u,暫存當前分支的改動,工做區恢復到最新的commit版本,通常經常使用於緊急切換分支,又不想盲目提交commit,想要恢復改動的內容git stash pop-u是將新建的文件一併暫存。
  • git merge branch,從目標 commit 和當前 commit (即 HEAD 所指向的 commit)分叉的位置起,把目標 commit 的路徑上的全部 commit 的內容一併應用到當前 commit,而後自動生成一個新的 commit。merge會自動合併,若是同一個文件上修改可能會合並失敗,解決完衝突以後git add 文件;git commit就能夠了。放棄merge的話git merget --abort,merge後面能夠是branch,也能夠是通常的commit。是否是感受和pull很像,固然!!!pull就是fetch和merge的合體~~~
    拋物線大神的圖
  • git branch [newbranch] [-d]省略後面的,會顯示全部分支,加上後面的表示建立分支,刪除分支的話-d,強制刪除-D
  • git tag tagName,tag 是一個和 branch 很是類似的概念,它和 branch 最大的區別是:tag 不能移動。因此在不少團隊中,tag 被用來在關鍵版本處打標記用。多用在master分支上。
  • git revert commitId,將某commit取反,也就是放棄某次的修改,這個命令會生成新的commit。
  • git reset commitId --hard,將HEAD以及當前的branch指向移動到目標commit,工做區的內容隨着HEAD一塊兒變化,有時候想丟棄某些commits用這個命令。常常用這個git reset HEAD --hard放棄本地全部的修改,恢復到上一次的commit狀態。
  • git remote name url,添加一個遠程數據庫,而且起一個名字,感受用的很少

git的查找和配置

  • git log,查看日誌,git log --patch查看詳細的日誌,git log --stat查看簡要的日誌,想要切回到某個版本的時候會用到
  • git show [commitID] [某文件],看某一個版本的日誌。省略commit表示當前的commit,省略某文件表示全部文件。
  • git diff commitID,將工做區的內容和目標commit作一個對比。
  • git status,查看當前的狀態,隨時會用
  • git config,對git的一系列配置。屬於「一次付出,終身受用」的高性價比內容。global參數針對全局git,不加那隻針對當前的倉庫起做用。全局配置在用戶主目錄下的一個隱藏文件~/.gitconfig中,本地配置在倉庫根目錄的.git/config。查看配置git config --global --list。如下是經常使用的配置: 好比配置別名,git config --global alias.co checkout;git config --global alias.ci commit;git config --global alias.br branch也就是能夠git co xxbranch;git ci -m"xx";git br
    好比配置不容易的命令,git config --global alias.unstage 'reset HEAD'下次git unstage file就表示將暫存區的修改撤銷掉,回到工做樹那邊。git config --global alias.back 'reset HEAD --hard'git back表示放棄全部修改,工做區返回到上一次的commit。git config --global alias.last 'log -1'顯示最後一次提交的信息。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顯示日誌,特別好用!!!強烈推薦!!!
    好比上面配置push。

分支的應用

公司中多數是這樣開發的:git

  • master分支通常只管理髮布狀態,在提交的時候使用標籤記錄發佈版本號
  • develop分支是發佈的平常開發分支
  • 任何新的功能(feature)或 bug 修復全都新建一個 branch 來寫,新分支可能feature-xxx,hotfix-xxx,feature表示功能開發,hotfix發佈的產品有緊急bug,修改完以後合併
  • branch 寫完後,合併到 master,而後刪掉這個 branch。固然也能夠藉助pull requests

HEAD、master與branch

每一個commit就是每一個版本,每一個記錄的意思。稱呼不同。web

  • git log執行後,通常第一行的 commit 後面括號裏的 HEAD -> master, origin/master, origin/HEAD,是幾個指向這個 commit 的引用。
  • 在 Git 的使用中,常常會須要對指定的 commit 進行操做。每個 commit 都有一個它惟一的指定方式也就是上圖中每一個黃色的 commit 右邊的那一長串字符。兩個 SHA-1 值的重複機率極低,因此你可使用這個 SHA-1 值來指代 commit,也能夠只使用它的前幾位來指代它(例如第一個 78bb0ab7d541…16b77,你使用 78bb0ab 甚至 78bb 來指代它一般也能夠),
  • 但畢竟這種沒有任何含義的字符串是很難記憶的,因此 Git 提供了「引用」的機制:使用固定的字符串做爲引用,指向某個 commit,做爲操做 commit 時的快捷方式。

HEAD

  • HEAD 是 Git 中一個獨特的引用,它是惟一的。
  • HEAD是當前工做目錄所對應的commit。
  • 當有新的commit的時候(commit或者pull的時候),工做目錄會與最新的commit對應,HEAD也就指向最新的commit。
  • 當使用checkout、reset等指令手動改變工做目錄的commit時,HEAD也會跟過去
  • 當前目錄的commit在哪,HEAD就在哪,永遠指向當前目錄的commit,也就是能夠用HEAD操做當前目錄的commit

branch

  • Git 還有一種引用,叫作 branch(分支)
  • HEAD 除了能夠指向 commit,還能夠指向一個 branch,當它指向某個 branch 的時候,會經過這個 branch 來間接地指向某個 commit;另外,當 HEAD 在提交時自動向前移動的時候,它會像一個拖鉤同樣帶着它所指向的 branch 一塊兒移動。
    圖片是拋物線大神的
  • branch能夠理解爲是指向commit的一個引用,也能夠理解爲從第一個commit到branch指向的commit之間全部的commits的一個串

master

  • 默認的branch,建立新倉庫的時候,第一條commit建立,master會指向它,HEAD指向master
  • git clone的時候,除了從遠程倉庫把 .git 這個倉庫目錄下載到工做目錄中,還會 checkout (簽出) master(checkout 的意思就是把某個 commit 做爲當前 commit,把 HEAD 移動過去,並把工做目錄的文件內容替換成這個 commit 所對應的內容)。
    圖片是拋物線大神的
  • origin/HEAD,origin/master是遠程倉庫的鏡像引用

「引用」的本質

所謂「引用」(reference),其實就是一個個的字符串。這個字符串能夠是一個 commit 的 SHA-1 碼(例:c08de9a4d8771144cd23986f9f76c4ed729e69b0),也能夠是一個 branch(例:ref: refs/heads/feature3)。shell

Git 中的 HEAD 和每個 branch 以及其餘的引用,都是以文本文件的形式存儲在本地倉庫 .git 目錄中,而 Git 在工做的時候,就是經過這些文本文件的內容來判斷這些所謂的「引用」是指向誰的。數據庫

git的高級(難一點)的命令

這部分不具體寫命令了,若是有需求,再進行查閱吧。json

  • rebase的意思是,給你的 commit 序列從新設置基礎點(也就是父 commit)。展開來講就是,從目標 commit 和當前 commit (即 HEAD 所指向的 commit)分叉的位置起,以目標 commit 爲基礎,依次從新提交分叉以後全部 commit 的內容,這話聽着彆扭,就是把當前所在分支的分叉的全部commits,都複製一份放在參數branch後面
  • 指定amend選項執行提交的話,能夠修改所在分支最新的提交,git add 笑聲.txt;git commit --amend,其實至關於此次的提交直接覆蓋掉上次的提交。
  • 在cherry-pick,您能夠從其餘分支複製指定的提交,而後導入到如今的分支。
  • 在rebase指定i選項,您能夠改寫、替換、刪除或合併提交。
  • merge的特殊選項:squash,用這個選項指定分支的合併,就能夠把全部匯合的提交添加到分支上。

示例

# 查看狀態
git status
# 添加索引
git add file
# 添加數據庫,將HEAD自動更新到新的commit,且HEAD會拖着當前的分支,讓其也指向新的commit
git commit -m"msg"
# 將遠程數據庫的內容更新到本地數據庫,默認的遠程數據庫和分支名字是 origin master
git pull origin master
# 將本地數據庫添加到遠程數據庫。你用不加參數的 git push 只能上傳那些以前從遠端 clone 下來或者 pull 下來的分支,而若是須要 push 你本地的本身建立的分支,則須要手動指定目標倉庫和目標分支(而且目標分支的名稱必須和本地分支徹底相同),就像上面這樣。全部分支均可以用 git push 來直接 push,目標自動指向 origin 倉庫的同名分支,經過 git config 指令來設置 push.default 的值爲:current
git push origin master
# 添加遠程數據庫而且將遠程數據庫起個名字,通常起origin
git remote origin http://xxxxx
# 複製遠程數據庫,默認的新目錄的名字同項目名,git會將這個地址命名爲origin
git clone http://xxxx projectName
# 查看數據庫
git log
# 切換到某一版本,或者分支
git checkout xxxx
# 須要暫存修改,stash是臨時保存文件修改內容的區域
git stash
# 釋放
git stash pop
# 查看分支
git branch
# 建立分支 hotfix- feature- release- develop master,其實只是將當前commit建立了一個引用,HEAD指針並無指向新分支,若是須要,git checkout xxx
git branch xxx
# 建立並切換到新分支,建立新引用,且將HEAD指向這個新引用
git checkout -b xxx
# 刪除分支,所謂的刪除,只是刪除這個commit的引用,能夠從git log那找到這個commit,未合併到master的分支會刪除失敗,但能夠強制刪除,-d改爲-D
git branch -d xxx


# issue1分支須要合併到master上,rebase的歷史記錄更少

# merge
git checkout master;git pull;git merge issue1;

# rebase
git checkout issue1;git pull;git rebase master;git checkout master;git merge issue1


# 查看標籤,想要看註解加上 -n
git tag
# 打標籤
git tag tagnamexxxx
# 打註解標籤
git tag -am "註釋信息" tagnamexxx
# 看包含標籤的歷史記錄
git log --decorate
# 刪除標籤
git tag -d tagnamexxxx
複製代碼

git鉤子的簡單使用

一個新需求下來了,一般本身建個分支開始完成功能,等到完成的時候,本身測得也差很少了,就會合併到develop分支,而後部署到服務器,讓測試來測。每次這樣嫌費勁,就想着push到develop的時候,部署自動操做,這樣省了不少麻煩吖。。。安全

這就用到鉤子了,這邊我沒怎麼研究,大約知道,就是在執行add commit push pull merge等操做的時候,能夠在相應的時機執行相應的腳本。bash

項目根目錄下.git/hooks下,有不少文件,去掉後綴.sample就能夠在相應的時機執行這個腳本。腳本的語言,本身開心就好~~服務器

本地倉庫的鉤子:app

  • pre-commit: 執行git commit命令時觸發,經常使用於檢查代碼風格

  • post-commit: 整個git commit完成後觸發,經常使用於郵件通知、提醒

  • post-merge: 成功完成一次 merge行爲後觸發

  • pre-push: 執行git push命令時觸發,可用於執行測試用例

  • pre-auto-gc: 執行垃圾回收前觸發

  • prepare-commit-msg: commit message編輯器呼起前default commit message建立後觸發,經常使用於生成默認的標準化的提交說明

  • commit-msg: 開發者編寫完並確認commit message後觸發,經常使用於校驗提交說明是否標準

  • applypatch-msg: 執行git am命令時觸發,經常使用於檢查命令提取出來的提交信息是否符合特定格式

  • pre-applypatch: git am提取出補丁並應用於當前分支後,準備提交前觸發,經常使用於執行測試用例或檢查緩衝區代碼

  • post-applypatch: git am提交後觸發,經常使用於通知、或補丁郵件回覆(此鉤子不能中止git am過程)

  • pre-rebase: 執行git rebase命令時觸發

  • post-rewrite: 執行會替換commit的命令時觸發,好比git rebase或git commit --amend

  • post-checkout: 執行git checkout命令成功後觸發,可用於生成特定文檔,處理大二進制文件等

遠程倉庫用的鉤子,通常咱們就是要在服務端更新代碼以後運行腳步,因此咱們要修改的就是post-update或者post-receive。

  • pre-receive: 當服務端收到一個push操做請求時觸發,可用於檢測push的內容
  • update: 與pre-receive類似,但當一次push想更新多個分支時,pre-receive只執行一次,而此鉤子會爲每一分支都執行一次
  • post-receive: 當整個push操做完成時觸發,經常使用於服務側同步、通知

拿我爲例,我用的,這裏說下,最好是在服務器端執行git pull,但由於此項目是另一個團隊開發,我臨時負責一個功能,也不知道服務器那邊爲啥不用git,我獲得的信息是隻能用複製替換

# .git/.hooks 新建pre-push

##!/bin/sh
# 拿到分支名
NAME=$(git branch | grep '*' | sed 's/* //')

echo "正在上傳到服務器 $NAME"
# 在develop上push的時候主動將代碼複製到服務器上面
if [ "$NAME" = "develop" ]
then
  scp  -r /Users/creen  root@10.2.2.156:/newoackend
fi

複製代碼

搭建git服務器

我以爲買服務器的時候,估計就用到,因此怕忘了,索性記一筆,大段引用廖雪峯大神的git教程。 遠程倉庫實際上和本地倉庫沒啥不一樣,純粹爲了7x24小時開機並交換你們的修改。GitHub就是一個免費託管開源代碼的遠程倉庫。但通常公司須要本身搭建。

Ubuntu或Debian系統完成git安裝須要如下幾步:

# 安裝git
sudo apt-get install git
# 建立一個git用戶,用來運行git服務
sudo adduser git
# 建立證書登陸,其實就是將全部須要登陸的用戶的id_rsa.pub文件,導入到服務器的/home/git/.ssh/authorized_keys文件裏,一行一個。mac用戶的公鑰位置`~/.ssh/id_rsa.pub`
# 初始化Git倉庫,先選定一個目錄做爲Git倉庫,假定是/srv/sample.git,在/srv目錄下輸入命令,Git就會建立一個裸倉庫,裸倉庫沒有工做區,由於服務器上的Git倉庫純粹是爲了共享,因此不讓用戶直接登陸到服務器上去改工做區,而且服務器上的Git倉庫一般都以.git結尾
cd /srv
sudo git init --bare sample.git
# 把owner改成git
sudo chown -R git:git sample.git
# 禁用shell登陸,出於安全考慮,第二步建立的git用戶不容許登陸shell,這能夠經過編輯/etc/passwd文件完成。找到相似git:x:1001:1001:,,,:/home/git:/bin/bash改成:git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell

複製代碼

git的用戶能夠在本地clone了

git clone git@server:/srv/sample.git
複製代碼

官方git文檔
猴子也懂的git入門
拋物線大神的git原理和使用小冊子,額,須要一點點零花錢
廖雪峯大神的git教程
巧用git鉤子
imweb的git鉤子,特別是能夠用package.json指定鉤子
拿到git分支的名字

相關文章
相關標籤/搜索