git 指令
git 是一個功能強大的程式碼管理工具 - Version Control System,以下簡單紀錄 git 指令的筆記,並推薦幾個不錯的教學網站。
具有視覺化、互動式學習的設計,內容由淺入深,相當值得學習:
Learn Git Branching
如果該網頁的顯示語言為英文,只要將網頁瀏覽器的語言改為中文為優先,則重新更新網頁內容後,網頁會自動以中文呈現。
如果對上述網站的內容覺得不夠,這個網站是屬於說明型的:
Git Tutorial
想知道更多的話,可以參考電子書:
Pro Git book
另一個中文版的教學網站:
Git
基本操作
HEAD 是一個象徵性的指標,通常會指向某個 branch 最近一次 commit 的內容。
git init => 在本機端, 初始化 git 環境
git status => 在本機端,顯示目前的檔案修改情況(包含新增及刪除)
git status -s => 以簡短的方式顯示 git status
git ls-files -m => 在本機端,顯示目前已追縱的檔案修改情況(不包含新增)
git log => 在本機端,顯示目前已經 commit 的所有修改內容,後續可以增加參數來進行過濾
git log --no-merges => 在本機端,顯示目前已經 commit 的所有修改內容,並剔除 merge 時所產生的額外訊息
git log --decorate => 在本機端,除了顯示目前已經 commit 的所有修改內容之外,還顯示相關的 branch
git log --name-status => 在本機端,顯示目前已經 commit 的修改內容的檔案名稱
git log --oneline => 在本機端,以第一行顯示目前已經 commit 的修改內容
git log origin/master..HEAD => 在本機端,顯示 HEAD 對於 origin/master 所新增的 commit 內容;此指令相等於 git log ^origin/master HEAD,也相等於 git log HEAD --not origin/master,指的是顯示只在 HEAD 中出現,而 origin/master 沒有的 commit 內容。
git log HEAD..origin/master => 在本機端,顯示 origin/master 對於 HEAD 所新增的 commit 內容
git log HEAD...origin/master => 在本機端,顯示 origin/master 與 HEAD 所有相異的 commit 內容
git log HEAD...origin/master --left-right => 在本機端,顯示 origin/master 與 HEAD 所有相異的 commit 內容,並加上方向性,指出那個 commit 是 HEAD 所有,還是 origin/master 所有
git show => 在本機端,顯示目前 branch 最新 commit 的修改內容
git show HEAD^ => 在本機端,顯示 HEAD 的前一個 commit 的修改內容
git show HEAD~3^2 => 在本機端,顯示 HEAD 的前三個 commit 中第二個 parent 的修改內容
git show {commit_hash} => 在本機端,顯示該 {commit_hash} 的修改內容
git show stash@{0} => 在本機端,回復由 git stash 所儲存的修改內容
設定檔: .gitignore => 設定讓 git 忽視的檔案
設定檔: .git/info/exclude => 也是設定讓 git 忽視的檔案
git clean -xf && git clean -xffd => 移除所有非 git 所追縱的檔案及資料夾
檔案管理
git diff => 在本機端,顯示目前在 working directory 的修改內容
git diff --staged => 在本機端,顯示目前在 staging area 的修改內容
git diff --cached => 效果同 git diff --staged
git diff HEAD => 效果同 git diff + git diff --staged,也就是顯示目前在 working directory 及 staging area 的修改內容
git diff Remote_Branch => 查看目前在 working directory 與遠端主機的 Remote_Branch 的修改內容
git diff --check => 在本機端,檢查修改內容的行尾是否有多餘的空白字元
git add {file_name} => 在本機端, 將修改的內容送到 staging area
git add -i {file_name} => 在本機端, 以 interactive 的方式作 git add,相同於 git add --interactive
git add -p {file_name} => 在本機端, 將修改的內容分成多次送到 git add,相同於 git add --patch
git add -A => 在本機端,將所有的修改內容送到 staging area,包含新增加的檔案
git add -u => 在本機端,只將 git 目前有追縱的檔案的修改內容送到 staging area
git add -f {file_name} => 在本機端,強制將 git ignore 的檔案的修改內容送到 staging area
git rm --cached {file_name} => 在本機端, 在 staged area 移除該檔案,但保留該檔案至 working directory
git mv {file_name} {new_file_name} => 在本機端, 將檔案重新命名、移動位置
git reset HEAD {file_name} => 在本機端,將該檔案的修改從 staging area 移到 working directory
git reset -p {file_name} => 在本機端, 將修改的內容分成多次作 git reset,相同於 git reset --patch
git reset reference~# => 在本機端,將 branch 的 commit 往回移動到 reference~#,但在 working directory 保留這些修改
git reset --soft reference~# => 在本機端,將 branch 的 commit 往回移動到 reference~#,但在 staging area 保留這些修改
git reset --hard reference~# => 在本機端,將 branch 的 commit 往回移動到 reference~#,且不保留這些修改
git clean (-n) -f (-x) => 移除未追縱也未忽略的檔案,加上 -n 選項為模擬移除,加上 -x 選項為連忽略的檔案也一併移除
git clean (-n) -f -d (-x) => 移除未追縱也未忽略的檔案及資料夾,加上 -n 選項為模擬移除,加上 -x 選項為連忽略的檔案也一併移除
git checkout . => 放棄已追縱檔案的所有修改
commit 管理
git commit => 在本機端,提交 staging area 所修改的內容至 local repo
git commit -m "message" => 在本機端,提交 staging area 所修改的內容至 local repo,並設定 commit message
git commit -a => 在本機端,提交所有的修改內容至 local repo,包含在 working directory 及 staging area 所作的修改
git commit --amend => 在本機端,將目前 staging area 的修改內容與上一次的 commit 內容合併,如果 staging area 的沒有修改內容,則為單純修改上一次的 commit 內容
git log --pretty=raw => 在本機端,顯示目前已經 commit 的所有修改內容,並增加 tree, parent ... 的欄位
git reflog => 在本機端,顯示所有有關 HEAD 的改變紀錄
git log -g => 在本機端,顯示目前已經 commit 的所有修改內容,並增加 reflog 的欄位
git cherry-pick {commit_hash} => 在本機端,將該 {commit_hash} 的內容複製到目前 branch
git rebase {branch_name} => 在本機端,以 {branch_name} 為 base,將目前 branch 的 commit 內容轉接過去
git rebase {branch_name} Target_Branch => 在本機端,以 {branch_name} 為 base,將 Target_Branch 的 commit 內容轉接到 {branch_name}
相同於 git checkout Target_Branch; git rebase {branch_name}
git rebase --onto {branch_name_1} {branch_name_2} Target_Branch => 在本機端,以 {branch_name_1} 為 base,將 Target_Branch 在以 {branch_name_2} 為基礎,所新增的 commit 內容,轉接到 {branch_name_1}
git rebase --skip => 作 git rebase 時,如果發生 conflict,選擇放棄 {branch_name_2} 的 patch
git rebase --abort => 作 git rebase 時,如果發生 conflict,選擇回到原本的 branch 並放棄此 rebase 及其修改
git rebase -i reference~# => 在本機端,透過編輯器 (vi) 重新挑選、排列、修改、分離、結合…,在 reference~# 之後的所有 commit 內容
branch 管理
git branch (-a) (-v(v)) => 顯示所有 branch, (包含遠端) (包含 last commit 訊息 (顯示 tracked branch))
git branch {branch_name} => 在本機端,建立一個指向目前 commit 的程式內容的 {branch_name}
git branch -f {branch_name} reference~# => 在本機端,將 {branch_name} 移動到 reference~#
git branch -d {branch_name} => 在本機端,刪除 {branch_name}
git checkout -- {file_name} => 在本機端,移除將該檔案在 working directory 的修改
git checkout -p {file_name} => 在本機端, 將修改的內容分成多次作 git checkout,相同於 git checkout --patch
git checkout {branch_name} => 在本機端,切換目前的 branch 到 {branch_name}
git checkout -b {branch_name} => 在本機端,建立一個指向目前 commit 的程式內容的 {branch_name},並切換目前的 branch 到 {branch_name},相同於:
git branch {branch_name}; git checkout {branch_name}
git checkout {commit_hash} => 在本機端,將 HEAD 指向 {commit_hash} 的內容
git merge {branch_name} => 在本機端,將 {branch_name} 的 commit 內容,結合到目前的 branch
git format-patch reference~# => 在本機端,產生目前位置與 reference~# 之間,每個 commit 之間的 patch 檔
git apply {patch_file_name} => 在本機端,利用 patch 檔來修改檔案
git am {patch_file_name} => 在本機端,利用 patch 檔來修改檔案,並自動 commit
除了利用 {commit_hash} 之外,也可以利用相對於 reference 的符號來表示,reference 可以是 {branch_name} ,也可以是 HEAD 本身:
git checkout reference^ => 在本機端,將 HEAD 指向該 reference 的 parent
git checkout reference~# => 在本機端,將 HEAD 指向該 reference 的前 # 個 parent
git revert reference~# => 在本機端,新增一個 commit,對 reference~# 的內容作回復
遠端主機
git clone <repo URL> => 在本機端,將遠端檔案庫的全部檔案複製一份下來
git clone <repo URL> -b <branch name> => 在本機端,將遠端檔案庫的指定 branch 複製一份下來
git clone <repo URL> -b <branch name> --depth 1 => 在本機端,將遠端檔案庫的指定 branch 複製一份下來,且不需要 git log
git clone <repo URL> <folder name/path> => 在本機端,將遠端檔案庫的全部檔案複製一份下來,並指定下載路徑
git clone <local project folder> <new local project folder> => 在本機端,將本機端的檔案庫作備份
git remote => 在本機端,顯示遠端檔案庫的名稱
git remote show Remote_Repository => 在本機端,顯示遠端檔案庫的詳細資訊
git remote -v => 在本機端,顯示 fetch, push 遠端檔案庫的資訊
git fetch => 將本機端所有的 origin/branch 更新與遠端主機的同名 remote branch 相同
在 git fetch 完之後,要和本機端的已經修改過程式碼作結合,可以有好幾種作法,例如:
git cherry-pick origin/master
git rebase origin/master
git merge origin/master
git pull => 在本機端,結合 git fetch 與 git merge origin/master 的效果
git pull --rebase => 在本機端,結合 git fetch 與 git rebase origin/master 的效果
git fetch origin Remote_Branch => 將本機端的同名 origin/branch 更新到與遠端主機的 Remote_Branch 相同
git fetch origin Remote_Branch:New_Local_Branch => 在本機端新增 New_Local_Branch,並將 New_Local_Branch 更新到與遠端主機的 Remote_Branch 相同
git fetch origin :{branch_name} => 在本機端,建立一個指向 origin/master 最近 commit 程式內容的 {branch_name}
git push => 將本機端目前所在的 branch 所作的修改上傳到遠端主機的同名 branch
git push origin Local_Branch => 將本機端 Local_Branch 所作的修改上傳到遠端主機的同名 branch
git push origin Local_Branch:Remote_Branch => 將本機端 Local_Branch 所作的修改上傳到遠端主機的 Remote_Branch
git push origin Local_Branch:New_Remote_Branch => 在遠端主機新增 New_Remote_Branch,並將本機端 Local_Branch 所作的修改上傳到新增的遠端主機的 New_Remote_Branch
git push origin :{branch_name} => 刪除遠端主機的 {branch_name}
git push origin --delete {branch_name} => 刪除遠端主機的 {branch_name}
git branch {branch_name} origin/master => 在本機端,建立一個追縱 origin/master 的 {branch_name}
git branch -u origin/master {branch_name} => 在本機端,將 {branch_name} 設定為追縱 origin/master
git branch -u origin/master => 在本機端,將目前的 branch 設定為追縱 origin/master
而 -u 也可以換成 --set-upstream-to
git branch --unset-upstream => 在本機端,將目前的 branch 取消追蹤遠端分支
git branch --unset-upstream {branch_name} => 在本機端,將 {branch_name} 取消追蹤遠端分支
git checkout -b {branch_name} origin/master => 在本機端,建立一個追縱 origin/master 的 {branch_name},並切換目前的 branch 到 {branch_name},相同於:
git branch {branch_name} origin/master; git checkout {branch_name}
其它
git stash => 在本機端,將還沒 commit 的修改部分,暫時儲存並移除,回復到最近 commit 的內容,相同於 git stash save
git stash --keep-index => 在本機端,將還沒移到 stage 的修改部分,暫時儲存並移除
git stash --patch => 在本機端,以 patch 的方式作 git stash
git stash -u => 在本機端,將還沒 commit 的修改部分以及未追縱的檔案,暫時儲存並移除,回復到最近 commit 的內容,相同於 git stash save -u
git stash save "message" => 在本機端,將還沒 commit 的修改部分,暫時儲存並移除,回復到最近 commit 的內容,並加上 message 描述此次的 stash 內容
git stash show => 在本機端,查看由 git stash 所儲存的修改檔案名稱
git stash list => 在本機端,查看由 git stash 所儲存的修改列表
git stash pop => 在本機端,回復由 git stash@{0} 所儲存的修改部分,並刪除 stash@{0}
git stash branch {new_branch_name} => 在本機端,新建立一個 branch,並在該 branch 作 git stash pop
git stash apply => 在本機端,回復由 git stash@{0} 所儲存的修改部分,但不刪除 stash@{0}
git stash apply --index => 在本機端,回復由 git stash 所儲存的修改部分,但不刪除 stash@{0} ,且分類為 staged 及 not staged
git tag {tag_name} {commit_hash} => 在本機端,為該 {commit_hash} 加上指向它的 {tag_name}
git show {tag_name} => 顯示 {tag_name} 的 commit 內容
git push origin {tag_name} => 將 {tag_name} 資訊上傳到遠端主機
git fetch origin {branch_name} --tags => 從遠端主機下載 {branch_name} 所有的 tag 資訊
git describe reference => 在本機端,顯示該 reference 相對於最近 annotated tag 的資訊
git grep (-n) {keyword} => 在 working directory 顯示包含 {keyword} 的行,-n 為顯示行號,等同於 git grep (--line-number) {keyword}
git grep -c {keyword} => 在 working directory 以檔案為單位計算 {keyword} 出現的次數,等同於 git grep --count {keyword}
git grep -p {keyword} => 在 working directory 顯示包含 {keyword} 的行及其函式名稱,等同於 git grep --show-function {keyword}
git grep -e {keyword_1} -e {keyword_2} => 在 working directory 顯示包含 {keyword_2} 或 {keyword_2} 的行
git grep (--heading) (--break) -e {keyword_1} --and -e {keyword_2} => 在 working directory 顯示包含 {keyword_1} 及 {keyword_2} 的行,--heading 為顯示檔案名稱,--break 為檔案與檔案之間隔開一行
git log -S {keyword} => 在 git log 中,顯示 {keyword} 出現的次數有變化的 commit
git log -G {keyword} => 在 git log 中,顯示 {keyword} 那行有修改的 commit
git log -L :{funcation_name}:{file_name} => 在 git log 中,顯示 {funcation_name} 在 {file_name} 的內容
git blame {file_name} => 顯示 {file_name} 中每一行最近一次修改的 commit hash、作者、時間
git remote prune origin (--dry-run) => 清除儲存在本機端但遠端已被刪除的遠端 branch,--dry-run 為模擬,只列出會被刪除的 branch
git filter-branch --tree-filter 'rm -f passwords.txt' HEAD => 在該 branch 的所有 commit 中,移除檔案 - passwords.txt
git filter-branch --subdirectory-filter trunk HEAD => 將資料夾 -trunk 的內容,作為目前 branch 的資料內容,並作相關修改
git filter-branch -f --commit-filter '
if [ "$GIT_AUTHOR_EMAIL" = "fake@fake.com" ];
then
GIT_AUTHOR_NAME="some";
GIT_AUTHOR_EMAIL="some@test.com";
git commit-tree "$@";
else
git commit-tree "$@";
fi' HEAD
=> 將該 branch 的 git log 中,所有 author email 為 "fake@fake.com" 的 commit,修改 author name 為 "some",author email 為 "some@test.com"
Example
將本地端的修改與主機端的修改作整合
利用 merge
在 master branch 上新增並切換到 bugFix branch:
git checkout -b bugFix
修改完後,作 commit:
git commit
切回 master branch,作更新:
git checkout master; git fetch; git merge origin/master
在 master branch 下,merge 在 bugFix branch 所作的修改:
git merge bugFix
回到 bugFix branch,與 master branch 作同步:
git checkout bugFix; git merge master
利用 rebase
在 master branch 上新增並切換到 bugFix branch:
git checkout -b bugFix
修改完後,作 commit:
git commit
切回 master branch,作更新:
git checkout master; git fetch; git rebase origin/master
在 master branch 下,rebase 在 bugFix branch 所作的修改:
git rebase bugFix
回到 bugFix branch,與 master branch 作同步:
git checkout bugFix ; git rebase master
觀念理解 reset
三個基本名詞的定義:
HEAD: | 象徵性指標,指向最近一次 commit 的內容 |
Index: | 下次 commit 的內容 |
Working Directory: | 目前的修改內容 |
在一個空資料夾下,初始化 git 之後 (git init):
HEAD(master) 未定義指向哪裡;HEAD(master) 為 HEAD 所指向的 master branch。
Index 為沒有內容。
Working Directory 同樣為沒有內容。
新增一個檔案 (touch file.txt):
HEAD(master) 未定義指向哪裡。
Index 為沒有內容。
Working Directory 的內容為 file.txt。
把檔案加到 staging area (git add file.txt):
HEAD(master) 未定義指向哪裡。
Index 的內容為 file.txt。
Working Directory 的內容為 file.txt。
把檔案加到 local repository (git commit):
HEAD(master) 的內容為 file.txt。
Index 的內容為 file.txt。
Working Directory 的內容為 file.txt。
要比較 Working vs. Index 的內容差異 或 Index vs. HEAD(master) 的內容差異 可以執行 git status:
如果 Working vs. Index 的內容有差異,則會紅字顯示 "Changes not staged for commit:" 的檔案。
如果 Index vs. HEAD(master) 的內容有差異,則會綠字顯示 "Changes to be committed:" 的檔案。
如果上述兩者都不成立,則不會顯示任何檔案。
要恢復到上一個 commit log 的狀態,可以執行 git reset HEAD~,其恢復的動作為:
- 回復檔案內容到 HEAD(master) 所指的上一個內容。
- 複製 HEAD(master) 的內容 到 Index。
- 複製 Index 的內容 到 Working Directory。
如果有指定參數 --soft,則作到步驟 1 就停止。 (git reset --soft HEAD~)
如果沒有指定參數 --hard,則作到步驟 2 就停止。(git reset HEAD~)
如果有指定參數 --hard,則作完全部步驟。(git reset --hard HEAD~)
要恢復某個特定檔案,可以執行 git reset with path(s):
- 複製 HEAD(master) 中該 path(s) 的內容 到 Index。
因為 git reset with path(s) 不允許指定 --soft 或 --hard 參數,所以只會執行該步驟。
reset vs. checkout
當執行 git reset 時,所操作的是 HEAD(master) 指標;而執行 git checkout 時,所操作的是 HEAD 指標。
舉例來說,如果目前是在 master branch,而 develop 是另一個 branch,則:
git reset develop: 是把 develop branch 的內容 複製到 master branch。
git checkout develop: 是改 HEAD 指標,從 HEAD(master) 改變成 HEAD(develop),而不會改變 master branch 的內容。
.gitignore vs. .git/info/exclude
.gitignore 及 .git/info/exclude 兩個具有相同的寫入格式,可以把不希望 git 追縱的檔案列出來,但兩者之間的相異處為何?
最大的不同點在於:
.gitignore 是可以上傳到 git remote repository 上的,跟其它的人一起分享,但是 .git/info/exclude 就是自己 local 端的設定。
也就是說,如果要隱藏的檔案路徑,是適用於大家的,就寫到 .gitignore,並上傳到 remote repository,但如果是個人習慣使用,就寫在 .git/info/exclude。
設定 alias
如果要看完整的 git log,可以把 "git tree" 設定為 "git log --graph --decorate --pretty=oneline --abbrev-commit" 的 alias:
# git config --global alias.tree "log --graph --decorate --pretty=oneline --abbrev-commit"
把 "git allclear" 設定為 "git clean -xf && git clean -xffd" 的 alias,直接修改 ~/.gitconfig 檔案,在 [alias] 欄位加入:
allclear=!sh -c 'git clean -xf && git clean -xffd'
其它問題
按 tab 鍵,git 指令沒有自動完成:
How to configure git bash command line completion?
Reference
Learn Git Branching
Git Tutorial
Pro Git book
Git
文字內容 或 影像內容 部份參考、引用自網路,如有侵權,請告知,謝謝。
留言列表