Git 是世界上最好用的程式碼版本控制工具,沒有之一;那麼作為走在前沿的 ML 開發者,豈能不擅長高階大氣上檔次的 Git?
本文介紹了七十多種常用的 Git 命令與技巧,專案作者削微寒在開源工作上也做了非常多的貢獻。目前 Git 奇技淫巧專案已經獲得了 6.8K 的 Star,他還構建了另一個 1.1W+ 的開源專案集錦 HellowGitHub。
HelloGitHub 專案地址:https://github.com/521xueweihan/HelloGitHub
Git 是一個「分散式版本管理工具」,簡單的理解版本管理工具:大家在寫東西的時候都用過「回撤」這個功能,但是回撤只能回撤幾步,假如想要找回我三天之前的修改,光用「回撤」是找不回來的。而「版本管理工具」能記錄每次的修改,只要提交到版本倉庫,你就可以找到之前任何時刻的狀態(文字狀態)。
對於 ML 開發者而言,版本控制也是必不可少的。如果我們寫了個初版模型,並上傳至 GitHub 私人或公共倉庫,那麼每當我們有一些修改,都可以通過 Git 上傳,它會自動控制這些歷史版本。如果說後面發現前面的某些超引數或結構非常好,那麼檢視歷史版本也是很好的。
對於其它開源工作的管理,Git 就更好用了。因為它是一種分散式版本控制系統,並沒有一個真正的「中心伺服器」,所以不同的電腦間有相同的版本庫,本地版本庫損壞了就直接從其它完好的版本庫複製。這種 Git,才是協作開發程式碼的最優方法,因此基於 Git 的 GitHub 才成為開源世界中不可獲取的部分。
下面的內容就是列舉了常用的 Git 命令和一些小技巧,讀者可以在原 GitHub 專案上進行 "頁面內查詢",也可以在微信文章頁面上選擇 "搜尋頁面內容"。
開卷必讀
如果之前未使用過 Git,可以學習 Git 小白教程入門:http://rogerdudler.github.io/git-guide/index.zh.html。
1. 一定要先測試命令的效果後,再用於工作環境中,以防造成不能彌補的後果!
2. 所有的命令都在 git version 2.7.4 (Apple Git-66) 下測試通過
3. 統一概念:
工作區:改動(增刪檔案和內容)
暫存區:輸入命令:git add 改動的檔名,此次改動就放到了 『暫存區』
本地倉庫 (簡稱:本地):輸入命令:git commit 此次修改的描述,此次改動就放到了 』本地倉庫』,每個 commit,我叫它為一個 『版本』。
遠端倉庫 (簡稱:遠端):輸入命令:git push 遠端倉庫,此次改動就放到了 『遠端倉庫』(GitHub 等)
commit-id:輸出命令:git log,最上面那行 commit xxxxxx,後面的字串就是 commit-id
4. 如果喜歡這個專案,歡迎 Star、提交 Pr、反饋問題
先給一張各種命令的詳解圖,更詳細的內容可查閱後文的命令解釋:
為了方便查閱,這裡先以目錄的形式列舉各種操作的列表:
展示幫助資訊
回到遠端倉庫的狀態
重設第一個 commit
展示工作區和暫存區的不同
展示暫存區和最近版本的不同
展示暫存區、工作區和最近版本的不同
快速切換到上一個分支
刪除已經合併到 master 的分支
展示本地分支關聯遠端倉庫的情況
關聯遠端分支
列出所有遠端分支
列出本地和遠端分支
建立並切換到本地分支
從遠端分支中建立並切換到本地分支
刪除本地分支
刪除遠端分支
重新命名本地分支
檢視標籤
檢視標籤詳細資訊
本地建立標籤
推送標籤到遠端倉庫
刪除本地標籤
刪除遠端標籤
切回到某個標籤
放棄工作區的修改
恢復刪除的檔案
以新增一個 commit 的方式還原某一個 commit 的修改
回到某個 commit 的狀態,並刪除後面的 commit
修改上一個 commit 的描述
檢視 commit 歷史
顯示本地更新過 HEAD 的 git 命令記錄
修改作者名
修改遠端倉庫的 url
增加遠端倉庫
列出所有遠端倉庫
檢視兩個星期內的改動
把 A 分支的某一個 commit,放到 B 分支上
給 git 命令起別名
儲存當前的修改,但不用提交 commit
儲存當前狀態,包括 untracked 的檔案
展示所有 stashes
回到某個 stash 的狀態
回到最後一個 stash 的狀態,並刪除這個 stash
刪除所有的 stash
從 stash 中拿出某個檔案的修改
展示所有 tracked 的檔案
展示所有 untracked 的檔案
展示所有忽略的檔案
強制刪除 untracked 的檔案
強制刪除 untracked 的目錄
展示簡化的 commit 歷史
檢視某段程式碼是誰寫的
把某一個分支到匯出成一個檔案
從包中匯入分支
執行 rebase 之前自動 stash
從遠端倉庫根據 ID,拉下某一狀態,到本地分支
詳細展示一行中的修改
清除 .gitignore 檔案中記錄的檔案
展示所有 alias 和 configs
展示忽略的檔案
commit 歷史中顯示 Branch1 有的,但是 Branch2 沒有 commit
在 commit log 中顯示 GPG 簽名
刪除全域性設定
新建並切換到新分支上,同時這個分支沒有任何 commit
展示任意分支某一檔案的內容
clone 下來指定的單一分支
忽略某個檔案的改動
忽略檔案的許可權變化
以最後提交的順序列出所有 Git 分支
在 commit log 中查詢相關內容
把暫存區的指定 file 放到工作區中
強制推送
詳解 Git 奇技淫巧
展示幫助資訊
git help -g
輸出如下:
The common Git guides are:
attributes Defining attributes per path
cli Git command-line interface and conventions
core-tutorial A Git core tutorial for developers
cvs-migration Git for CVS users
diffcore Tweaking diff output
everyday A useful minimum set of commands for Everyday Git
glossary A Git Glossary
hooks Hooks used by Git
ignore Specifies intentionally untracked files to ignore
modules Defining submodule properties
namespaces Git namespaces
repository-layout Git Repository Layout
revisions Specifying revisions and ranges for Git
tutorial A tutorial introduction to Git
tutorial-2 A tutorial introduction to Git: part two
workflows An overview of recommended workflows with Git
'git help -a' and 'git help -g' list available subcommands and some concept guides. See 'git help <command>' or 'git help <concept>' to read about a specific subcommand or concept.
回到遠端倉庫的狀態
拋棄本地所有的修改,回到遠端倉庫的狀態。
git fetch --all && git reset --hard origin/master
重設第一個 commit
也就是把所有的改動都重新放回工作區,並清空所有的 commit,這樣就可以重新提交第一個 commit 了。
git update-ref -d HEAD
展示工作區和暫存區的不同
輸出工作區和暫存區的 different (不同)。
git diff
還可以展示本地倉庫中任意兩個 commit 之間的檔案變動:
git diff <commit-id> <commit-id>
展示暫存區和最近版本的不同
輸出暫存區和本地最近的版本 (commit) 的 different(不同)。
git diff --cached
展示暫存區、工作區和最近版本的不同
輸出工作區、暫存區 和本地最近的版本 (commit) 的 different (不同)。
git diff HEAD
快速切換到上一個分支
git checkout -
刪除已經合併到 master 的分支
git branch --merged master | grep -v '^\*\| master' | xargs -n 1 git branch -d
展示本地分支關聯遠端倉庫的情況
git branch -vv
關聯遠端分支
關聯之後,git branch -vv 就可以展示關聯的遠端分支名了,同時推送到遠端倉庫直接:git push,不需要指定遠端倉庫了。
git branch -u origin/mybranch
或者在 push 時加上 -u 引數
git push origin/mybranch -u
列出所有遠端分支
-r 引數相當於:remote
git branch -r
列出本地和遠端分支
-a 引數相當於:all
git branch -a
建立並切換到本地分支
git checkout -b <branch-name>
從遠端分支中建立並切換到本地分支
git checkout -b <branch-name> origin/<branch-name>
刪除本地分支
git branch -d <local-branchname>
刪除遠端分支
git push origin --delete <remote-branchname>
或者
git push origin :<remote-branchname>
重新命名本地分支
git branch -m <new-branch-name>
檢視標籤
git tag
展示當前分支的最近的 tag
git describe --tags --abbrev=0
檢視標籤詳細資訊
git tag -ln
本地建立標籤
git tag <version-number>
預設 tag 是打在最近的一次 commit 上,如果需要指定 commit 打 tag:
$ git tag -a <version-number> -m "v1.0 釋出 (描述)" <commit-id>
推送標籤到遠端倉庫
首先要保證本地建立好了標籤才可以推送標籤到遠端倉庫:
git push origin <local-version-number>
一次性推送所有標籤,同步到遠端倉庫:
git push origin --tags
刪除本地標籤
git tag -d <tag-name>
刪除遠端標籤
刪除遠端標籤需要先刪除本地標籤,再執行下面的命令:
git push origin :refs/tags/<tag-name>
切回到某個標籤
一般上線之前都會打 tag,就是為了防止上線後出現問題,方便快速回退到上一版本。下面的命令是回到某一標籤下的狀態:
git checkout -b branch_name tag_name
放棄工作區的修改
git checkout <file-name>
放棄所有修改:
git checkout .
恢復刪除的檔案
git rev-list -n 1 HEAD -- <file_path> # 得到 deleting_commit
git checkout <deleting_commit>^ -- <file_path> # 回到刪除檔案 deleting_commit 之前的狀態
以新增一個 commit 的方式還原某一個 commit 的修改
git revert <commit-id>
回到某個 commit 的狀態,並刪除後面的 commit
和 revert 的區別:reset 命令會抹去某個 commit id 之後的所有 commit
git reset <commit-id> # 預設就是-mixed 引數。
git reset –mixed HEAD^ # 回退至上個版本,它將重置 HEAD 到另外一個 commit, 並且重置暫存區以便和 HEAD 相匹配,但是也到此為止。工作區不會被更改。
git reset –soft HEAD~3 # 回退至三個版本之前,只回退了 commit 的資訊,暫存區和工作區與回退之前保持一致。如果還要提交,直接 commit 即可
git reset –hard <commit-id> # 徹底回退到指定 commit-id 的狀態,暫存區和工作區也會變為指定 commit-id 版本的內容
修改上一個 commit 的描述
如果暫存區有改動,同時也會將暫存區的改動提交到上一個 commit
git commit --amend
檢視 commit 歷史
git log
檢視某段程式碼是誰寫的
blame 的意思為『責怪』,你懂的。
git blame <file-name>
顯示本地更新過 HEAD 的 git 命令記錄
每次更新了 HEAD 的 git 命令比如 commint、amend、cherry-pick、reset、revert 等都會被記錄下來(不限分支),就像 shell 的 history 一樣。這樣你可以 reset 到任何一次更新了 HEAD 的操作之後,而不僅僅是回到當前分支下的某個 commit 之後的狀態。
git reflog
修改作者名
git commit --amend --author='Author Name <email@address.com>'
修改遠端倉庫的 url
git remote set-url origin <URL>
增加遠端倉庫
git remote add origin <remote-url>
列出所有遠端倉庫
git remote
檢視兩個星期內的改動
git whatchanged --since='2 weeks ago'
把 A 分支的某一個 commit,放到 B 分支上
這個過程需要 cherry-pick 命令,參考:http://sg552.iteye.com/blog/1300713#bc2367928
git checkout <branch-name> && git cherry-pick <commit-id>
給 git 命令起別名
簡化命令
git config --global alias.<handle> <command>
比如:git status 改成 git st,這樣可以簡化命令
git config --global alias.st status
儲存當前的修改,但不用提交 commit
詳解可以參考廖雪峰老師的 git 教程 (http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/00137602359178794d966923e5c4134bc8bf98dfb03aea3000)
git stash
儲存當前狀態,包括 untracked 的檔案
untracked 檔案:新建的檔案
git stash -u
展示所有 stashes
git stash list
回到某個 stash 的狀態
git stash apply <stash@{n}>
回到最後一個 stash 的狀態,並刪除這個 stash
git stash pop
刪除所有的 stash
git stash clear
從 stash 中拿出某個檔案的修改
git checkout <stash@{n}> -- <file-path>
展示所有 tracked 的檔案
git ls-files -t
展示所有 untracked 的檔案
git ls-files --others
展示所有忽略的檔案
git ls-files --others -i --exclude-standard
強制刪除 untracked 的檔案
可以用來刪除新建的檔案。如果不指定檔案檔名,則清空所有工作的 untracked 檔案。clean 命令,注意兩點:
1. clean 後,刪除的檔案無法找回
2. 不會影響 tracked 的檔案的改動,只會刪除 untracked 的檔案
git clean <file-name> -f
強制刪除 untracked 的目錄
可以用來刪除新建的目錄,注意:這個命令也可以用來刪除 untracked 的檔案。詳情見上一條。
git clean <directory-name> -df
展示簡化的 commit 歷史
git log --pretty=oneline --graph --decorate --all
把某一個分支匯出成一個檔案
git bundle create <file> <branch-name>
從包中匯入分支
新建一個分支,分支內容就是上面 git bundle create 命令匯出的內容
git clone repo.bundle <repo-dir> -b <branch-name>
執行 rebase 之前自動 stash
git rebase --autostash
從遠端倉庫根據 ID,拉下某一狀態,到本地分支
git fetch origin pull/<id>/head:<branch-name>
詳細展示一行中的修改
git diff --word-diff
清除 gitignore 檔案中記錄的檔案
git clean -X -f
展示所有 alias 和 configs
注意:config 分為:當前目錄(local)和全域性(golbal)的 config,預設為當前目錄的 config
git config --local --list (當前目錄)
git config --global --list (全域性)
展示忽略的檔案
git status --ignored
commit 歷史中顯示 Branch1 有的,但是 Branch2 沒有 commit
git log Branch1 ^Branch2
在 commit log 中顯示 GPG 簽名
git log --show-signature
刪除全域性設定
git config --global --unset <entry-name>
新建並切換到新分支上,同時這個分支沒有任何 commit
相當於儲存修改,但是重寫 commit 歷史
git checkout --orphan <branch-name>
展示任意分支某一檔案的內容
git show <branch-name>:<file-name>
clone 下來指定的單一分支
git clone -b <branch-name> --single-branch https://github.com/user/repo.git
忽略某個檔案的改動
關閉 track 指定檔案的改動,也就是 Git 將不會在記錄這個檔案的改動
git update-index --assume-unchanged path/to/file
恢復 track 指定檔案的改動
git update-index --no-assume-unchanged path/to/file
忽略檔案的許可權變化
不再將檔案的許可權變化視作改動
git config core.fileMode false
以最後提交的順序列出所有 Git 分支
最新的放在最上面
git for-each-ref --sort=-committerdate --format='%(refname:short)' refs/heads/
在 commit log 中查詢相關內容
通過 grep 查詢,given-text:所需要查詢的欄位
git log --all --grep='<given-text>'
把暫存區的指定 file 放到工作區中
不新增引數,預設是 -mixed
git reset <file-name>
強制推送
git push -f <remote-name> <branch-name>