做者: Escape
來源: https://www.escapelife.site/p...html
只有在遇到問題的時候,才體會到技巧帶來的好處!java
主要介紹,企業中經常使用的 Git 工做流程!git
總結平常工做中應該遵循的 Git 使用方式和方法!github
平常使用只要記住 6 個命令就能夠了。面試
# 工做區 -> 暫存區$ git add <file/dir># 暫存區 -> 本地倉庫$ git commit -m "some info"# 本地倉庫 -> 遠程倉庫$ git push origin master # 本地master分支推送到遠程origin倉庫 # 工做區 <- 暫存區 $ git checkout -- <file> # 暫存區文件內容覆蓋工做區文件內容 # 暫存區 <- 本地倉庫 $ git reset HEAD <file> # 本地倉庫文件內容覆蓋暫存區文件內容 # 本地倉庫 <- 遠程倉庫 $ git clone <git_url> # 克隆遠程倉庫 $ git fetch upstream master # 拉取遠程代碼到本地但不該用在當前分支 $ git pull upstream master # 拉取遠程代碼到本地但應用在當前分支 $ git pull --rebase upstream master # 若是平時使用rebase合併代碼則加上 # 工做區 <- 本地倉庫 $ git reset <commit> # 本地倉庫覆蓋到工做區(保存回退文件內容修改) $ git reset --mixed <commit> # 本地倉庫覆蓋到工做區(保存回退文件內容修改) $ git reset --soft <commit> # 本地倉庫覆蓋到工做區(保留修改並加到暫存區) $ git reset --hard <commit> # 本地倉庫覆蓋到工做區(不保留修改直接刪除掉)
雖然配置比較簡單,可是很是有用!spring
# 用戶信息 $ git config --global user.name "your_name" $ git config --global user.email "your_email" # 文本編輯器 $ git config --global core.editor "nvim" # 分頁器 $ git config --global core.pager "more" # 別名 $ git config --global alias.gs "git status" # 糾錯 $ git config --global help.autocorrect 1
# 不加--global參數的話,則爲我的配置 $ git config --list $ git config user.name $ git config user.name "your_name" # 若是在項目中設置,則保存在.git/config文件裏面 $ cat .git/config [user] name = "your_name" ......
到底何時使用 merge 操做,何時使用 rebase 操做呢?vim
支持使用 merge 的開發者,他們認爲倉庫的提交歷史就是記錄實際發生過什麼,它是針對於歷史的一個文檔,自己實際上是有價值的,咱們不該該隨意修改。咱們改變歷史的話,就至關於使用「謊話」來掩蓋實際發生過的事情,而這些痕跡是應該被保留的。可能,這樣並非很好。bash
# 3rd的兩個分支的commit修改相同內容 * 62a322d - (HEAD->master) Merge branch 'hotfix3' into master |\ | * 6fa8f4a - (hotfix3) 3rd commit in hotfix3 * | 548d681 - 3rd commit in master |/ * 6ba4a08 - 2nd commit * 22afcc1 - 1st commit
支持使用 rebase 的開發者,他們認爲提交歷史是項目過程當中發生過的事情,須要項目的主幹很是的乾淨。而使用 merge 操做會生成一個 merge 的 commit 對象,讓提交歷史多了一些很是多餘的內容。服務器
當咱們後期,使用 log 命令參看提交歷史的話,會發現主幹的提交歷史很是的尷尬。好比,一樣的修改內容重複提交了兩次,這顯然是分支合併致使的問題。網絡
# 3rd的兩個分支的commit修改相同內容 * 697167e - (HEAD -> master, hotfix) 3rd commit * 6ba4a08 - 2nd commit (2 minutes ago) * 22afcc1 - 1st commit (3 minutes ago)
總的原則就是,只對還沒有推送或分享給其餘人的本地修改執行變基操做清理歷史,從不對已經推送到倉庫的提交記錄執行變基操做,這樣,你纔可能享受到兩種方式帶來的便利。
Git 提供了一些工具,能夠幫助咱們完善版本庫中的提交內容,好比:
平常開發中,咱們爲了完成一個功能或者特性,提交不少個 commit 記錄。可是在最後,提交 PR 以前,通常狀況下,咱們是應該整理下這些提交記錄的。有些 commit 須要合併起來,或者須要將其刪除掉,等等。
# 調整最近五次的提交記錄 $ git rebase -i HEAD~5 $ git rebase -i 5af4zd35 # 往前第六次的commit值 reword c2aeb6e 3rd commit squash 25a3122 4th commit pick 5d36f1d 5th commit fixup bd5d32f 6th commit drop 581e96d 7th commit # 查看提交歷史記錄 $ git log * ce813eb - (HEAD -> master) 5th commit * aa2f043 - 3rd commit -> modified * 6c5418f - 2nd commit * c8f7dea - 1st commit
有時候提交以後,咱們才發現提交的歷史記錄中存在這一些問題,而這個時候咱們又不想新生成一個 commit 記錄,且達到一個修改的目錄。即,修改以前的 commit 提交記錄。
# 不使用分頁器 $ git --no-pager log --oneline -1 d5e96d9 (HEAD -> master) say file # 改變提交信息並加入暫存區 $ echo "hello" > say.txt $ git add -u # 改變當前最新一次提交記錄 $ git commit --amend # 改變且息不改變提交信 $ git commit --amend --no-edit # 改變當前最新一次提交記錄並修改信息 $ git commit --amend -m "some_info" # 不使用分頁器 $ git --no-pager log --oneline -1 9e1e0eb (HEAD -> master) say file
咱們開發了一個功能,而在上線的時候,產品經理說這個功能的部分特性已經不須要了,即相關特性的提交記錄和內容就能夠忽略/刪除掉了。
# 回滾操做(可屢次執行回滾操做) # 完全上次提交記錄;也但是PR的提交記錄 # 默認會生成一個類型爲reverts的新commit對象 $ git revert 3zj5sldl [4] 合併某些特定的 commit 提交 咱們不但願合併整個分支,而是須要合併該分支的某些提交記錄就能夠了。 bash # 摘櫻桃 $ git cherry-pick -x z562e23d
如何找回咱們丟失的內容和記錄?
咱們以前說過,使用下面命令回退內容、強制推送代碼、刪除本地分支,都是很是危險的操做,由於重置以後咱們就沒有辦法在找到以前的修改內容了。
# 回退 $ git reset --hard <commit> # 推送 $ git push origin master -f # 分支 $ git branch -D <branch_name>
其實 Git 給咱們留了一個後門,就是使用 relflog 命令來找回以前的內容,只不過是相對來講麻煩一些。而原理也很簡答,就是在咱們使用 Git 命令操做倉庫的時候,Git 偷偷地幫助咱們把全部的操做記錄了下來。
# 查看日誌記錄 $ git --no-pager log --oneline -1 4bc8703 (HEAD -> master) hhhh # 回退到上次提交 $ git reset --hard HEAD~1 # 查看引用日誌記錄 $ git reflog 6a89f1b (HEAD -> master) HEAD@{0}: reset: moving to HEAD~1 4bc8703 HEAD@{1}: commit (amend): hhhh # 找回內容 $ git cherry-pick 4bc8703
批量修改歷史提交雖然不經常使用,可是理解的話能夠省下不少時間!
以前咱們學習到的命令都是針對於一個或者多個 commit 提交信息進行修改的,若是咱們須要全局修改歷史提交呢?固然,Git 中也是支持全局修改歷史提交的,好比全局修改郵箱地址,或者將一個文件從全局歷史中刪除或修改。
這裏咱們可使用 filter-brach 的方式進行修改,可是建議在使用以前,新建一個分支,在上面進行測試沒有問題以後,再在主幹上操做,防止出現問題,背個大鍋在身上。
# 建立分支 $ git branch -b testing # 修改郵箱地址 $ git filter-branch --commit-filter ' if [ "$GIT_AUTHOR_EMAIL" == "escape@escapelife.site" ]; then GIT_AUTHOR_NAME="escape"; GIT_AUTHOR_EMAIL="escape@gmail.com"; git commit-tree "$@" else git commit-tree "$@" fi' HEAD
主要介紹.git/hooks 目錄下面的示例鉤子函數!
在 Git 裏面有兩類,分別對應客戶端和服務端鉤子函數。客戶端的鉤子函數,是在執行提交和合並之類的操做時調用的。而服務端鉤子函數,就是當服務端收到代碼提交以後,能夠出發代碼檢查和持續集成的步驟。做爲開發者咱們並不會搭建 Git 服務器,因此基本不會涉及。
下面就是 Git 自帶的鉤子腳本,可是自帶的都以 .sample 做爲後綴,表示並無啓用,表示爲一個示例。若是須要啓用的話,將 .sample 做爲後綴刪除掉,便可。而其鉤子腳本的對應內容,都是使用 Shell 語法進行編寫的。
➜ ll .git/hooks total 112 -rwxr-xr-x applypatch-msg.sample -rwxr-xr-x commit-msg.sample -rwxr-xr-x fsmonitor-watchman.sample -rwxr-xr-x post-update.sample -rwxr-xr-x pre-applypatch.sample -rwxr-xr-x pre-commit.sample -rwxr-xr-x pre-merge-commit.sample -rwxr-xr-x pre-push.sample # 不會推送包含WIP的commit提交 -rwxr-xr-x pre-rebase.sample -rwxr-xr-x pre-receive.sample -rwxr-xr-x prepare-commit-msg.sample -rwxr-xr-x update.sample
其實,鉤子腳本使用任何語言編寫都是能夠的,只要你讓程序返回對應的退出碼就能夠了。
正常的代碼合入流程就是,咱們本地修改以後,提一個 PR 請求並經過 Github 的 CI 檢查,接下來進行代碼評審,最後被合併入主幹。可是,好的一個習慣就是,在代碼提交以前就應該保證代碼不會出現語法錯誤等基礎問題,好比經過 flake8 和 PEP8 標準等。
這個時候咱們就可使用 pre-commit 這個 Github 的開源項目了,其本質就是給項目添加鉤子函數的一個腳本,能夠保證咱們在提交代碼或者推送代碼以前,先檢查代碼的質量。
而 pre-commit-hooks 這個項目裏面包含的就是,如今所支持的鉤子腳本,即開箱即用的鉤子腳本集合。而其鉤子腳本的對應內容,都是使用 Python 語法進行編寫的。
# 安裝方式 $ pip install pre-commit # 指定hook類型(即在哪裏檢查) $ pre-commit install -f --hook-type pre-push # 配置須要執行的檢查 $ cat .pre-commit-config.yaml repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v2.9.2 hooks: - id: trailing-whitespace - id: flake8 # 執行push操做時檢查 $ git push origin master
在大項目中工做中,拉取代碼很是佔時間!
咱們若是想爲 Linux 或 Python 這樣的大型項目貢獻提交的時候,首先遇到的問題就是,若是快速的 clone 該項目到本地。由於改項目提交歷史超多且倉庫巨大,加了國內網絡的問題,可能等項目徹底拉下來的時候,咱們的熱情都消減下去了。
好在 Git 也幫咱們想到了這樣的問題,咱們可使用 --depth 參數值拉取遠程倉庫上面最新一次的提交歷史,並不包含項目歷史記錄,即 .git/objects/ 目錄下的對象只是本地的,並不包含以前的屢次修改產生的對象。
# 克隆不包含以前歷史 $ git clone http://xxx.xx.xxx/xxx --depth=1 可是,有時間咱們可能會須要 clone 倉庫中的某個 tag 版本對應下的內容。若是咱們直接使用 clone 命令是沒法作到的,須要執行以下操做,便可完美解決。 # 克隆特定版本代碼 $ git init xxx-15-0-1 $ git remote add origin http://xxx.xx.xxx/xxx $ git -c protocol.version=2 fetch origin 15.0.1 --depth=1 $ git checkout FETCH_HEAD
上面的效果已經基本能夠知足咱們平常使用需求了,可是不幸的是,你如今接受了一個機器學習的項目,裏面包含了大量的 lfs 文件,如今 clone 又會變得很是慢。可使用以下操做來避免,Git 工具主動拉去 lfs 文件,來達到目錄。
# 克隆不包含LFS數據 $ GIT_LFS_SKIP_SMUDGE=1 git clone http://xxx.xx.xxx/xxx
若是在多路運轉的時候,還可以高效的進行開發!
好比,咱們如今正在一個分支爲項目添加一個小的功能,此時,產品經理找到你說是線上環境如今有一個 bug 須要讓你來修復下。可是,此時咱們添加的小功能並無完成。
若是此時,咱們直接切換到主幹分支的話,會將以前分支沒有來得及提交的內容所有都帶到了主幹分支上來,這是咱們不想看到的狀況。此時,咱們須要保存上個分支的工做狀態,在咱們修改完成線上 bug 以後,再繼續工做。
好在 Git 也幫咱們想到了這樣的問題,咱們可使用 stash 子命令幫助咱們將當前工做區、暫存區當中的修改都保存到堆棧之中。等到須要處理的時候,再彈出堆棧中的內容,咱們再次進行開發。
➜ git stash -h usage: git stash list [<options>] or: git stash show [<options>] [<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 clear or: git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet] [-u|--include-untracked] [-a|--all] [-m|--message <message>] [--pathspec-from-file=<file> [--pathspec-file-nul]] [--] [<pathspec>...]] or: git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet] [-u|--include-untracked] [-a|--all] [<message>] # 存儲當前的修改但不用提交commit $ git stash # 保存當前狀態包括untracked的文件 $ git stash -u # 展現全部stashes信息 $ git stash list # 回到某個stash狀態 $ git stash apply <stash@{n}> # 刪除儲藏區 $ git stash drop <stash@{n}> # 回到最後一個stash的狀態並刪除這個stash信息 $ git stash pop # 刪除全部的stash信息 $ git stash clear # 從stash中拿出某個文件的修改 $ git checkout <stash@{n}> -- <file-path>
其實比較保險的作法就是,將當前的全部修改進行 push 並保存到遠程倉庫裏面。這樣的好處在於,能夠遠端備份咱們的修改,不會懼怕本地文件丟失等問題。等到咱們須要繼續開發的時候,拉下對應內容,再想辦法進行補救,好比使用 --amend 或者 reset 命令。
# 將工做區和暫存區覆蓋最近一次提交 $ git commit --amend $ git commit --amend -m "some_info" # 回退到指定版本並記錄修改內容(--mixed) # 本地倉庫覆蓋到工做區(保存回退文件內容修改) $ git reset a87f328 $ git reset HEAD~ $ git reset HEAD~2 $ git reset <tag>~2 $ git reset --mixed <commit/reference> # 本地倉庫覆蓋到工做區(不保留修改直接刪除掉) $ git reset --soft <commit/reference> # 本地倉庫覆蓋到工做區(保留修改並加到暫存區) $ git reset --hard <commit/reference>
近期熱文推薦:
1.600+ 道 Java面試題及答案整理(2021最新版)
2.終於靠開源項目弄到 IntelliJ IDEA 激活碼了,真香!
3.阿里 Mock 工具正式開源,幹掉市面上全部 Mock 工具!
4.Spring Cloud 2020.0.0 正式發佈,全新顛覆性版本!
以爲不錯,別忘了隨手點贊+轉發哦!