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~,其恢復的動作為:

 

  1. 回復檔案內容到 HEAD(master) 所指的上一個內容。
  2. 複製 HEAD(master) 的內容 到 Index
  3. 複製 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

文字內容 或 影像內容 部份參考、引用自網路,如有侵權,請告知,謝謝。

arrow
arrow
    全站熱搜

    silverwind1982 發表在 痞客邦 留言(0) 人氣()