git 沙河遊戲節點圖, 自由沙盒模擬git, 各種交互git命令

 


git學習練習總資源連接: https://try.github.io/ (練習已通,有document)javascript

本沙盒遊戲教學:https://learngitbranching.js.org/?demo java

自由沙盒模擬網頁 : http://git-school.github.io/visualizing-git/git

 

好的譯文: https://github.com/geeeeeeeeek/git-recipes/wikigithub


 

什麼是git? 

一個分佈式的源代碼庫。管理Linux內核源代碼。正則表達式

 git已快照形式保存和處理內容,每個提交都是一次快照。git能夠在快照之間回滾。vim

 


 

一個節點表明一個commit.api

*表明當前分支的最後一次提交:HEAD緩存

master是主幹。安全

其餘名字是分支。 併發

 

git merge :用於合併分支的代碼。

git rebase : 線性合併分支:

 

git rebase [-i] [目標] [移動記錄] 

git rebaes [目標]  #省略[要移動的記錄],則爲當前分支的全部commit。

 

假如當前分支是bugFix:

  1. git rebase master. 這樣bugFix分支就至關於在master的基礎上新增的代碼了。
  2. git checkout master 回到master
  3. git rebase bugFix,  master和bugFix的代碼都同樣了。

 

HEAD:

是一個對當前檢出記錄的符號引用 -- 也就是指向你正在其基礎上進行工做的提交記錄

它老是指向當前分支上最後一次的提交記錄。 大多數提交樹的git命令都是從改變HEAD的指向開始的。

⚠️,後面章節講的遠程分支 origin/master是例外

 

HEAD 一般是指向分支名的(如bugFix)。在你提交commit時,改變了分支的狀態,這一變化經過HEAD變得可見。

 

分離的HEAD:

讓它指向某個具體的提交記錄(hash值)而不是分支名。 

git checkout <hash> 

git checkout命令本質就是移動HEAD,到目標commit點, 而後更新工做目錄以匹配這個commit點。

由於這個操做會overwrite local changes,致使改變的文件丟失,因此Git強迫你先commit或stash工做目錄中的改變的文件。

⮀ git checkout master error: Your local changes to the following files would be overwritten by checkout: app/assets/javascripts/search.js Please commit your changes or stash them before you switch branches.

 


 

關於git stash  (具體工做原理和所有的知識見連接文章)

會把還沒有加入stage的文件和statge中的文件保存(就是未commited的文件),以便在以後使用。

以後能夠revert them from your working copy.

 

如今能夠進入任何其餘操做,如建立新commits, 轉變分支,執行其餘git操做了。

⚠️stash是本地的。當你push的時候,stash不會被傳輸。

 

Re-applying your stashed changes:

$ git stash pop

 

另外使用git stash apply, 能夠reapply the changes的同時在stash中保留它們。這在爲多個分支應用時有用。

⚠️:默認Git不會stash 未tracked文件和ignored files。

 

 

 


 

相對引用 

 

經過指定提交記錄hash值的方式在Git中移動不方便操做。

必須用到git log, 並且hash值很是長。

所以能夠只使用前幾個字符表明一個提交記錄 , 即「相對引用」。

^    表👆向上移動一個commit記錄。

~2 表明向上移動2個提交記錄,~5,表明移動5個提交記錄

使用git checkout HEAD^, 就表明向上移動一次。

 


 

強制修改分支位置--移動分支

 

git branch -f master HEAD~3

表明把master向上移動三個提交節點,即第3個father note 

-f :表明--force, force creation, move/rename, deletion 

 


 

撤銷變動

  • git reset
  • git revert 

 

Command Scope Common use cases
git reset Commit-level Discard commits in a private branch or throw away uncommited changes
git reset File-level Unstage a file
git checkout Commit-level Switch between branches or inspect old snapshots
git checkout File-level Discard changes in the working directory
git revert Commit-level Undo commits in a public branch
git revert File-level (N/A)

 

Git Reset

原文:

takes a specified commit and resets the "three trees" to match 
the state of the repository at that specified commit.

Three Trees

 

把分支回退指定個數的commit記錄,來實現撤銷改動。至關於使用時間機器回退到過去開發的階段。(撤銷的提交記錄還存在,只是未加入stage暫存區) 

⚠️ 這條命令對團隊使用的遠程分支無效!

例子:

# 從當前工做目錄回退一個commit.
git reset HEAD~

# 從當前工做目錄回退2個commit
git reset HEAD~2 

⚠️被回退的2個commit提交變成懸掛提交。下次Git執行垃圾回收時,這兩個提交會被刪除!

 

git reset能夠把stage中的文件拿出stage。git reset </filename>

⭠ autoquery± ⮀ git reset README.md Unstaged changes after reset: M README.md

 

 

三個模式選項

  • --soft -stage緩存區和工做目錄都不會改變。
  • --mixed默認選項。✅
    • 緩衝區和你指定的提交同步a(在提交a後,加入緩存區的文件被拿出來了)
    • 工做目錄不受影響(在提交a後對工做目錄中的文件進行的改變被保留!)。
  • --hard -緩存區和工做目錄都被更新,以匹配指定的commit點a。
    • 至關於回退到剛剛提交完a的狀態! 
    • 在提交a後的操做所有刪除,包括工做目錄中對文件的改變,至關於時光倒流

能夠認爲這個三個模式是對a git reset操做的做用域的定義!

通常使用默認的--mixed。

 


 

Git Revert (點擊見詳細)

專門用於撤銷遠程提交記錄。但本質上是新增一個commit記錄,但更改了code,去掉了以前那個commit記錄中的變動代碼。

c0-c1-c2(->c3)

git revert C1, 結果是新增了一個c3. 

c3是c1的反轉操做,即c1中變化的代碼,在c3中被撤銷了。

 

例如, 你追蹤一個bug並發現它是在某個commit點a內增長的一個變量。你無需手動進入這個commit點,刪除這個變量,而後再committing一個新的snapshot,你直接使用git revert a命令自動爲你作上面的事情。 

⚠️:若是你revert提交點c1, 可是c2中有對c1中變化的代碼的進一步修改,你不能使用git revert c1, 系統會提示你衝突,須要先搞定衝突代碼。

 

How it works

git revert命令用於撤銷一個倉庫的commit歷史中的某個變化。

其餘撤銷命令如git checkout 和 git reset,移動HEAD和branch ref pointers到一個指定的commit點。

Git revert也take a specified commit,可是,git revert不會移動ref pointers到這個commit點。

而是執行一個反轉操做,反轉那個commit的改變的代碼,並建立一個新的「revert commit」。

最後ref pointers 會更新,指向這個新的"revert commit", 讓這個commit成爲分支的端點tip。

 

選項

-e  --edit (默認選項) 打開系統的編輯器,提示你編輯commit信息。

-n --no-commit (一個特別的選項)使用它,git revert不會建立新的commit, 只會在working directory反轉變化的代碼,並在緩存中加入反轉代碼後的文件。一句話理解:須要你手動提交!其餘沒變化。

 

和get reset的比較:

1:不會改變歷史記錄。

  • 基於這個優勢git revert能夠在一個public branch上使用,
  • 而git reset最好在我的的branch上進行操做。

2:git revert只改變單一的提交點。而git reset會從當前提交往回退(回到過去)。

能夠這麼理解:

  • git revert是撤銷committed changes的工具

⚠️git revert也和git checkout相似,在revert操做期間會重寫工做目錄中的文件。因此它會要求你commit/stash changes。

 


 

 

File-level Operations

git reset和git checkout命令能夠接收一個file path做爲參數。這會強制把它們的操做限制到一個單一文件。

例子:

git reset HEAD~2 foo.py

 

當引用一個文件路徑時, git reset更新緩存區以匹配特定commit點的版本的指定文件。

👆的命令會取得在提早兩個提交點的版本的foo.py文件,並把它放入Staged files緩存區中。

可是工做區出現對應的文件的unstaged 狀態:

⭠ autoquery ⮀ git reset head~3 README.md Unstaged changes after reset: M README.md ⭠ autoquery± ⮀ git status On branch autoquery Changes to be committed: (use "git reset HEAD <file>..." to unstage)  modified: README.md Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory)  modified: README.md

 

個人理解:

  1. 執行git reset head~2 foo.py命令
  2. 取得的文件foo.py放入緩存區,但程序發現取出的文件和當前的foo.py文件的內容不一致,因此出現👆的狀況。

另外,若是我修改了上一個commit點的foo.py文件並放入緩存區。

而後又執行git reset head~2 foo.py

程序發現取出的文件和當前修改的foo.py文件的內容不一致,會把當前修改的foo.py文件放入工做目錄區。

⚠️複雜的操做盡可能配合可視輔助工具Sourcetree

 

 

Git checkout head File命令

它會把file放入working directory工做目錄。

⚠️個人實際操做是使用此條命令後,取出的文件會放入到緩存區!個人理解:

  1. git checkout head File
  2. 程序自動把取出的文件執行git add命令,放入緩存區。
git checkout HEAD~2 foo.py

 

⚠️此時git checkout命令不會移動HEAD標籤,即你不會切換分支!

⚠️:若是把這個變化git commit就至關於直接執行一個git revert命令了!!

 

 

 

 

 


 

總體提交記錄 

當開發人員說,我想把這個commit放到這裏,那個commit放到剛纔的提交的後面,就可使用:

將一些commit複製到當前位置HEAD下面的話,使用這個命令: 

git cherry-pick <提交號>...

 

⚠️我的理解,是每一個commit應該是一個獨立的模塊。

⚠️,前提是你知道你想要的commit記錄的hash值,才行。若是不知道,往下看⬇️

 

 


 

 

交互式的rebase 

 

git rebase -i HEAD~3

指帶參數 --interactive的rebase命令,簡寫-i

 

rebase會打開一個UI界面:

 

 


 

git 技巧 1: 本地stage提交

 

假如當前在bugFix分支(C4), 而master在C1, 但願只把C4合併到master上。

c1(master)-c2-c3-c4(bigFix*) 

第一種辦法:

git checkout master#HEAD回到master 

git cherry-pick C4#ok了

第二種辦法:

git rebase -i C1 #會打開UI界面,選擇C4,去掉C2, C3 ,肯定。

#這時buFix是當前分支它包含C4直接放到了C1下面。

git checkout master #回到master, 由於master的數據比較舊

git merge bugFix#合併分支。 

 

 


 

git 技巧 2: 

 

git commit --amend

修復最新提交的便捷方式。做用是:

將緩存的修改和以前的commit合併到一塊兒,生成一個新的提交併替換掉原來的提交。

這是從寫項目歷史的命令。

 

討論:

倉促的提交在你平常開發過程當中時常會發生。很容易就忘記了緩存一個文件或者弄錯了提交信息的格式。--amend 標記是修復這些小意外的便捷方式。

 

注意:⚠️

不要修復public commit! 永遠不要重設和其餘開發者共享的commit。

修復也同樣:永遠不要修復一個已經推送到公共倉庫的commit!

 https://learngitbranching.js.org/?demo (點擊連接看演示, 而後選擇第四行第2個按鈕)

c1(master)—c2(newImage)—c3(caption*) 

設計師須要在c2上調整圖片格式,如何作?

|再問:

設計師幹嗎不在C3上調整?

答:猜想C2提交記錄是針對圖片的設計,c3提交記錄是針對其餘設計。

假設:

git checkout newImage

git commit --amend

git checkout capiton

git merge newImage #這會致使新產生一條commit記錄。C4, 不符合線性的要求。

 

而使用:

# 調整C2, C3的位置,讓C2位於分支tip, 由於git commit --amend用於最新提交點。
 git rebase -i C1 # 對C2進行修改
 git commit --amend #再調整回原先的結構。
 git rebase -i C1  #至關於,歷史commit記錄樹沒有發生變化。 

#而後就能夠合併了
git checkout master
git checkout caption

 

 

⚠️,做者提示這可能會致使衝突:改用挑🍒,更快捷。cherry-pick

git checkout newImage

git commit --amend      #這會出現一個分叉。

git checkout master

git cherry-pick C2' C3

 


 

標籤的做用:tag

 

給某個提交記錄一個標籤,相似⚓️。 用於重要版本的標記。 

git tag V1 <hash> 

若是不指定<hash>提交記錄,則標記到HEAD指向的位置,所以能夠寫兩條語法:

git checkout <hash>

git tag V1 

 

Git Describe

用來找到最近的tag。幫助你在commit record的歷史中移動了屢次後找到方向。

git describe <ref>

<ref>是任何識別commit記錄的引用,不指定的話,則以當前HEAD位置爲準。

 

它的輸出結構:

<tag>_<numCommits>_g<hash>

解釋:

<tag>是離<ref>最近的標籤,

numCommits是表示和<ref>相差多少個commit記錄,

hash表示的是你所給定的<ref>所表示的提交記錄hash值的前幾位。 

 

Pushing tags

默認,標籤不會自動推送上去。 --tags將你全部的本地標籤推送到遠程倉庫。

git push <remoteName> <TagName>

push all tags:

git push <remoteName> --tags

 


 

挑戰1:線性移動合併分支:git rebase  (能夠看sandbox案例)

 

git rebase [-i] [目標] [要移動的記錄] 

git rebaes [目標] #省略[要移動的記錄],則爲當前HEAD 


 

挑戰2: 使用HEAD~和HEAD^2來移動HEAD的位置 

相對引用的擴展:

^2表明第二個父引用記錄,能夠鏈式使用。

git checkout HEAD~^2~

 表示上一個父記錄,而後再第二個父記錄,而後再上一個父記錄。

 

若是要在這裏創建一個新分支

git branch bugFix HEAD~^2~ 

 

 


 

挑戰3 ,git rebase 的再次使用。

HEAD也能夠作[目標] 

git rebase [-i] [目標] [要移動的記錄] 

 



 

remote repertory

 

簡單來講就是你的倉庫在其餘機器上的備份。

特色:

  • 備份,恢復丟失數據
  • 遠程讓代碼能夠社交化了!其餘人能夠爲你的代碼作貢獻。 

git clone: 在本地建立一個遠程倉庫的拷貝 

  


 

 

遠程跟蹤分支 remote-tracking branch

  

在本地倉庫多了一個名爲o/master的分支,這種類型的分支叫作 遠程跟蹤分支。

遠程跟蹤分支反應了遠程倉庫(在你上次和它通訊時)的狀態。

這有助於理解你本地的工做和公共工做的差異 -- 這是和別人分享工做成果最重要的一步。 

 

特別的屬性:在你checkout時,自動進入分離的HEAD狀態。 緣由是Git要求,不能在遠程跟蹤分支上直接寫代碼,須要先在其餘地方寫好代碼後,更新到遠程倉庫對應的位置,遠程跟蹤分支纔會更新。

 

git checkout o/master;

git commit;

在有新的commit提交記錄後,o/master不會同步更新,會和HEAD分離。

⚠️,Head老是指向當前分支上最後一次的提交記錄,但這裏是例外。

o/master只有在遠程倉庫中對應的分支更新後,纔會更新。 

 

格式:<remote name>/<branch name> 

簡稱: o/ 

默認: remote name 是 origin

 


 

Git Fetch 

 

從remote repertory得到數據。

當從遠程倉庫得到數據時, 遠程分支會自動更新,以反應最新的遠程倉庫。 

 

git fetch會作的事情: 

  • 從遠程倉庫下載本地倉庫缺乏的commit記錄
  •  更新遠程跟蹤分支 如 origin/feature_branch
git fetch 不會作的事情:
  • ⚠️不會更新你的master分支和其餘分支,也不會修改你磁盤上的文件。
  • 所以,不是說git fetch後本地倉庫就和遠程倉庫同步了,這是❌的想法。
  • git fetch只是單純的下載服務。 
//取指定的分支或tags,下載全部須要的commits和文件
git fetch <repository> [<refspec>...] // 取全部remote branch
git fetch --all [<options>]

// 試運行,就是一次彩排,看看會出現什麼結果
git fetch --dry-run

 

 

使用git fetch 同步遠程倉庫:

git fetch origin //會顯示咱們下載的branchs
//a1e8fb5..45e66a4 master -> origin/master
//a1e8fb5..9e8ab1c develop -> origin/develop
//* [new branch] some-feature -> origin/some-feature

若是想要查看上游master增長了什麼commit,能夠運行git log命令,並使用origin/master進行檢索:

git log --oneline master..origin/master

 

而後批准這些變化併合並它們到你的本地master分支:

git checkout master git log origin/master

//如今origin/master和master分支指向同一個commit點了,
//而且你和上游upstream 開發同步了。
git merge origin
/master

 


 

Git Pull

 

下載下來後,把遠程分支合併到本地的方法: 

  • git cherry-pick o/master
  • git rebase o/master
  • git merge o/master
  • 等等 

 

 git pull 就是直接一步完成2個命令。即git fetch和git merge的方便代碼。

 等同於:git fetch 和git cherry-pick o/master

 效果等同於:git fetch, git rebase master o/master, git rebase o/master master。但結構是線性的,由於使用git rebase是線性合併,o/master會指向新C3' 

 


 

模擬團隊合做:下載。

  1. git fetch 
  2. 在本地的master分支新增了commit
  3. git merge o/master, 合併遠程分支到本地的master。

 


 

Git Push

 

當本地倉庫被修改,須要執行git push操做來分享這個修改的代碼給team members:

git push <remote> <branch>
git push <remote> -all

 

若是不帶任何參數,會使用push.default的設置。他的默認值是正在使用的Git的版本,推送前最好檢查一下這個配置 

  


  

偏離的困惑 

 

假如週一你克隆了一個倉庫,而後開發某個新功能。到週五時,能夠提交到遠程倉庫了。可是,

這周你的同事寫了一堆代碼並修改了你還在使用的API。這些變更讓你的新開發的功能不可用。

但他已經提交推送到遠程倉庫了。你的工做變成了基於舊版本的代碼,已和遠程倉庫的最新的代碼不匹配了。

 

這時,Git不會容許你push,它會要求你先合併遠程最新的代碼,而後你才能分享你的工做。

這就是歷史偏移 

 

須要:

  1. git fetch
  2. git rebae o/master#這裏可能你的新增功能,會失效,
  3. 你須要先修改代碼,而後commit。最後:
  4. git push 
還可使用git merge
  1. git fetch#更新本地倉庫中的遠程分支
  2. git merge o/master#這會產生新的commit記錄。C4
  3. git push 

 

--rebase選項: 

git pull --rebase , 等同於用git rebase合併遠程分支,而默認是git merge 

 

小結:工做流程: fetch, rebase/merge, push

 

強制push

Git 爲了防止你覆蓋中央倉庫的歷史,會拒絕你會致使非快速向前合併的推送請求。

--force 這個標記覆蓋了這個行爲,讓遠程倉庫的分支符合你的本地分支,刪除你上次 pull 以後可能的上游更改。

只有當你意識到你剛剛共享的提交不正確,並用 git commit --amend 或者交互式 rebase 修復以後,你才須要用到強制推送。

⚠️ 可是,你必須絕對肯定在你使用 --force 標記前你的同事們都沒有 pull 這些提交。

 


 


 

關於origin和它的周邊  --Git 遠程倉庫高級操做 

 

推送push 主分支

 

大型項目,開發人員會在特性分支上工做,工做完成後只作一次集成。

但有些開發者只在master上push,pull。這樣master老是最新的,始終與遠程分支保持一致。

 

  • 將特性分支集成到master上。
  • push並更新遠程分支 

  


 

爲何操做遠程分支不喜歡用merge, 見仁見智

 

  •  喜歡乾淨的提交樹,用rebase
  •  喜歡保留提交歷史的,用merge

 


 

遠程跟蹤分支:remote-tracking branches

 

Git 設置了master和o/master的關聯。 

  • pull時,commit記錄會被先下載到遠程分支,如:origin/master上,以後會再合併到master分支。
  • push時,咱們把工做從master推到遠程倉庫中的master分支,同時更新遠程分支origin/master。

 

它們的關聯關係,是由"remote tracking" 屬性決定的。

master被設定爲跟蹤o/master。

 

當你克隆遠程倉庫時,Git會爲遠程倉庫的每一個分支都設定一個遠程分支,而後再在本地建立一個和遠程倉庫

中的分支同樣的本地分支。

 

克隆完成後,你會獲得本地分支,若是沒有就是空白。

 

這也解釋了在克隆時會看到下面的輸出:

local branch "master" set to track remote branch "o/master" 

本地分支「master」設置跟蹤遠程分支 "o/master"

 


 

能夠指定"remote tracking" 屬性屬性

 

讓任意分支跟蹤o/master,而後該分支就會像master分支同樣獲得隱藏的push目的地和merge的目標。

這意味着你能夠在分支XXX上指向git push, 將工做推送到遠程倉庫的master分支上。

兩種設置方法:

 

  • git checkout -b XXX o/master
  • 若是已經有了XXX分支,則使用git branch -u o/master XXX 
-u的意思: -u, --set-upstream-to <upstream>

  

 


 

Git push的參數

 

默認Git經過當前checkout分支的屬性來肯定遠程倉庫和要push的目的地。

 

咱們也能夠明確指定push的參數: 

git push <options> <remote-Repository-name> <place> 

例子: 

git push --set-upstream origin master:

把當前分支push, 並設置遠程倉庫origin爲upstream。

 

解釋:

這行代碼通常用在建立一個遠程連接並同步上傳數據:

⭠ master ⮀ git remote add origin https://github.com/xxxxxx/yyyyyy.git
//連接遠程倉庫origin.
⭠ master ⮀ git push -u origin master //Branch master set up to track remote branch master from origin. //本地分支master已經開始追蹤遠程倉庫origin的master分支!

 

<place> 詳細解釋: 

能夠分解爲<localbranch-source>:<destination> 

即本地分支source,提交到遠程的另外一個分支destination。

<source>能夠是任何commit記錄位置。 

若是<destination>在遠程倉庫中並不存在,則會在遠程倉庫中新建這個分支。

例子: git push origin localbranch:remotebranch

 

強制執行一次non-fast-forward merge

git push origin --force 

⚠️,只有絕對肯定你正在作的才這麼用!

 

--all選項:推送全部分支:

git push <remote> --all

 

把標籤也推送上去,默認tags是不推送的。

git push <remote> --tags

 

Amended force push

git commit --amend 用於更新提交點,

本質就是把commit原先的改變和更新的內容存入一個新的commit點,扔掉原來的commit點。

 

可是如此,git push 會致使失敗,由於Git會發現Amended的commit點和遠程的commit點的內容是分離的。

 

此時須要使用--force選項來push一個amended commit!

# make changes to a repo and git add git commit --amend
#此時若是直接git push 會報告錯誤❌:
# ! [rejected]        master -> master (non-fast-forward)

#須要使用--force
git push
--force origin master

注意⚠️沒有同步更新remote-tracking branch!

當本地master分支和origin/master在一塊兒時,執行一次修改並commit,再git push, 這時origin/master不能同步更新,須要再次執行一次同步命名。git push ,git fetch均可以.

 

再次提交一次:

#修改一些文件並提交 git commit -am 'd'

 

能夠發現origin/master是處於4ebc769,

若是使用

git fetch

 

origin/master會更新到最新commit點。 

 

刪除遠程分支或者tag

實際是推送一個空的分支替換遠程一個分支,至關於刪除遠程的這個分支。

//查看本地和遠程的分支
git branch --all //刪除本地分支
git branch -D branch_name //刪除遠程分支
git push origin origin :branch_name

 

 

 


 

Git remote 

 

如⬆️代碼,git remote add origin <url>, 建立了本地和遠程倉庫origin的連接!

本地./.git/config文件儲存了這條記錄信息:

[core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true precomposeunicode = true [remote "origin"] url = https://github.com/chentianwei411/practice.git fetch = +refs/heads/*:refs/remotes/origin/* [branch "master"] remote = origin merge = refs/heads/master config (END)

 

git push -u origin master命令,則添加了[branch "master"]這個記錄。

 

全部git remote的操做,都會記錄在./.git/config文件中!

//執行git remote remove origin命令: //會斷開本地和遠程的鏈接:
//全部對跟蹤遠程的分支的設置和對遠程的配置設置被移除!

//結果: [core] repositoryformatversion
= 0 filemode = true bare = false logallrefupdates = true ignorecase = true precomposeunicode = true [branch "master"] config (END)

 

再次使用git remote add origin <url>, 便可再鏈接上遠程倉庫:見./.git/config文件增長的代碼:

[branch "master"] [remote "origin"] url = https://github.com/chentianwei411/practice
        fetch = +refs/heads/*:refs/remotes/origin/*

 

 

git remote get-url --all origin

列出全部的遠程鏈接URLs.

 

git remote show <name>

這條命令會給出詳細的關於一個遠程鏈接的配置信息.

先git remote -v命令,查看。而後用git remtoe show <name>:

  • show origin, 
  • show upstream ,
  • shou other_users_repo
* remote origin Fetch URL: https://github.com/chentianwei411/practice
  Push  URL: https://github.com/chentianwei411/practice
 HEAD branch: master Remote branch: master tracked Local ref configured for 'git push': master pushes to master (up to date)

 

 

git remote prune [--dry-run] origin

Deletes all stale remote-tracking branches under <name>.

刪除全部過時的遠程跟蹤分支, 即origin/xxx

⚠️origin/xxx是存在於本地倉庫的,用於接收從遠程倉庫pull下來的數據。而後再merge到xxx分支。

These stale branches have already been removed from the remote repository
referenced by <name>, but are still locally available in "remotes/<name>".

這些過時的分支已經從遠程倉庫origin移除了,可是在本地倉庫仍然能夠在remotes/origin中找到:

⭠ master ⮀ git branch --all hotfix * master try  remotes/origin/hotfix remotes/origin/master

 

--dry-run, 列出什麼分支會被剪除掉prune!

 git remote prune --dry-run origin Pruning origin URL: https://github.com/chentianwei411/practice
 * [would prune] origin/hotfix

 

git remote prune origin Pruning origin URL: https://github.com/chentianwei411/practice
 * [pruned] origin/hotfix

 

再次使用git branch -a命令查詢全部分支,會發現remotes/origin/hotfix分支已經被刪除!! 

 

顯示你的remotes

git remote

git remote -v

//-v選項,是verbose的意思 // 會列出標記的倉庫名字和相關信息,合做的倉庫URL.
 origin git@bitbucket.com:origin_user/reponame.git (fetch) origin git@bitbucket.com:origin_user/reponame.git (push) upstream https://bitbucket.com/upstream_user/reponame.git (fetch)
upstream    https://bitbucket.com/upstream_user/reponame.git (push)
other_users_repo    https://bitbucket.com/other_users_repo/reponame (fetch)
other_users_repo    https://bitbucket.com/other_users_repo/reponame (push)

 

 

添加遠程倉庫

當你添加了一個遠程倉庫。 你就可使用倉庫名字origin做爲<url>的簡寫,在其餘git命令上使用了。

這是由於./.git/config中記錄了url的信息:

[remote "origin"] url = https://github.com/chentianwei411/practice
        fetch = +refs/heads/*:refs/remotes/origin/*

 

 

 

 


 

 

Git Fetch origin <remotebranch-source>

 

和git push正相反,Git會查找remotebranch的本地遠程分支,並下載到本地的遠程分支。

這樣不會弄壞你的本地同名分支。

 

也能夠另外指定遠程倉庫的分支下載到哪一個本地的分支<destination>,

這樣會直接下載到某個分支上(不是遠程分支),⚠️開發人員不多這麼作,有風險。

 

若是本地沒有一個bar分支:

git fetch origin XX:bar的結果是, 會在本地自動建立一個bar分支,用來存儲遠程倉庫的commit信息。

 

若是隻有git fetch:

Git會下載遠程倉庫中全部的提交記錄到各個遠程分支...

 


 

省去<source> 的特殊用法:

 

刪除遠程倉庫的分支:

git push origin :foo  #推送一個空的source到遠程倉庫,若是遠程倉庫有foo分支,這個分支將被刪除。

 

git fetch origin :bar  #下載一個遠程倉庫沒有的空分支給本地,本地建立一個bar分支。

 


 

 

Git Pull參數

git pull origin foo 至關於:

git fetch origin foo; git merge o/foo

 

⚠️git pull origin master 會先下載到o/master, 而後merge到當前checkout檢出位置。

因此,使用git pull要不熟練,要不就別用。

 

git pull也可使用<source>:<destination>:

如:git pull origin master:foo

  1. 若是本地沒有foo, 先在本地建立一個foo分支,
  2. 而後從遠程倉庫下載master分支中的提交記錄並合併到foo分支
  3. 而後再merge到當前的檢出分支checkout分支上。

 

 


  

git clean 

 

將未跟蹤的文件從你的工做目錄working directory中移除。

未跟蹤文件是新增到在工做目錄但還沒有添加到用 git add添加到repo's index。

它只是提供了一條捷徑,由於用 git status 查看哪些文件還未跟蹤而後手動移除它們也很方便。

和通常的 rm 命令同樣,git clean是沒法撤消的,因此在刪除未跟蹤的文件以前想清楚,你是否真的要這麼作。

 

git clean 命令常常和 git reset --hard 一塊兒使用。

⚠️記住,reset 隻影響被跟蹤的文件,因此還須要git clean來清理未被跟蹤的文件。這個兩個命令相結合,你就能夠將工做目錄回到以前特定提交時的狀態。 

# 先測試一下比較好-n ,--dry-run
git clean --dry-run

#
移除當前目錄下未被跟蹤的文件。-f(強制)標記是必需的。
# 不會刪除未跟蹤的目錄directory和.gitignore中的文件。
git clean -f # 移除未跟蹤的文件,但限制在某個路徑下 git clean -f <path> # 測試移除未跟蹤的目錄directory git clean -dn

# 移除未跟蹤的目錄

git clean -d

 

⚠️請牢記,和 git reset --hard 同樣, git clean 是僅有的幾個能夠永久刪除提交的命令之一,因此要當心使用 

栗子:

# 編輯了一些文件 # 新增了一些文件 # 『糟糕』

# 將跟蹤的文件回滾回去, 新增文件從head, index, 工做目錄中刪除了!!修改的文件恢復到以前的代碼!!
git reset --hard # 移除未跟蹤的文件,先測試-n, -dn
git clean -n git clean -df

 


 

改變舊的或者多個commits: git rebase 

 

rebase改基。從一個分支移動到另外一個分支,即改基。

移動或聯合一系列的提交點到一個新的base commit。實際是建立了一系列新的提交點。

 

效果和目的:

⚠️不要用在public commit。

  1. 讓你修改你的歷史, 而且可交互的改基容許你如此作而不留下雜亂的痕跡。
  2. 讓你在修改錯誤和重新定義你的任務後,仍然保持了一個乾淨,線性linear的程序歷史。

在真實的場景:

  1. 在主分支發現bug.。一個功能分支的功能由此壞掉。
  2. 開發者檢查主分支歷史git log。 由於clean history,開發者能快速的找出project的歷史。
  3. 開發者使用git log仍是不能識別出bug是什麼時候插入的introduced。因此他執行了git  bisect
  4. 由於git history很乾淨, git bisect有一個refined set of commits 來比較。開發者快速的找到了這個插入bug的commit點。

 

例子:

當你在一個功能分支上進行開發時,主分支發現一個bug。

新增一個hotfix分支,用於fix bug。 在搞定bug後, 把bug分支合併到master。

你想要在你的功能分支上使用最新版本的主分支,但你想要保持你的功能分支的歷史乾淨,即好似你一直在最新版的master上開發功能分支。

# 開始新的功能分支
git checkout -b new-feature master # 編輯文件
git commit -a -m "Start developing a feature"


#在 feature 分支開發了一半的時候,咱們意識到項目中有一個安全漏洞:----

# 基於master分支建立一個快速修復分支
git checkout -b hotfix master # 編輯文件
git commit -a -m "Fix security hole"
# 合併回master
git checkout master git merge hotfix git branch -d hotfix #將 hotfix 分支並回以後 master,咱們有了一個分叉的項目歷史。----
git checkout new-feature git rebase master #它將 new-feature 分支移到了 master 分支的末端, #而後在master上進行標準的快速向前合併了:
git checkout master git merge new-feature

 

Rebasing的一個經常使用方式是:把upstream的變化集成到你的本地倉庫。

 

 移動整個功能分支⬆️

 

git rebase -i <base>

用 -i 標記運行 git rebase 開始交互式 rebase。交互式 rebase 給你在過程當中修改單個提交的機會,而不是盲目地將全部提交都移到新的基上。你能夠移除、分割提交,更改提交的順序。

 

討論

交互式 rebase 給你了控制項目歷史的徹底掌控。它給了開發人員很大的自由,由於他們能夠提交一個「混亂」的歷史而只需專一於寫代碼,而後回去恢復乾淨。

大多數開發者喜歡在併入主代碼庫以前用交互式 rebase 來完善他們的 feature 分支。他們能夠將不重要的提交合在一塊兒,刪除不須要的,確保全部東西在提交到「正式」的項目歷史前都是整齊的。對其餘人來講,這個功能的開發看上去是由一系列精心安排的提交組成的。

 

執行:git rebase -i master 後出現vim的交互界面:

  • 若是刪除全部pick,而後:wq保存退出,至關於取消rebase 這條命令。提示:Nothing to do
  • 若是直接:q退出,不作任何修改,至關於執行了git rebase master命令。
    • 提示:Successfully rebased and updated

 

若是隻pick 37c8c61,第一行。則提示成功:

Successfully rebased and updated refs/heads/b2.

 
而後就能夠快速前進的合併了:
git checkout master git merger b2

 

⚠️另外2個pick就被分支b2扔掉了!!

若是知道這2個commit的id,就能夠進入它們:

git chekcout xxxx

獲得提示信息You are in 'detached HEAD' state. 你處於分離的HEAD!

能夠把這2個提交點合併到b2, 再把b2合併到master。

 

Rebasing的其餘幾個有趣的命令:

  • edit
  • reword -能夠重寫提交信息message
  • squash -把當前的commit合併到上一個commit, 並提示你重寫提交message
  • fixup    -和squash同樣,不會重寫提交message.

 

edit 9a29b81 

如可使用命令edit, 代替pick,當:wq保存退出vim後,提示

⭠ b3 ⮀ git rebase -i master Stopped at bb28411... change yangcheng You can amend the commit now, with 
git commit
--amend
Once you are satisfied with your changes, run
git rebase
--continue

➦ bb28411 ⮀

 

而後你能夠在這個提交點上作修改,而後

➦ bb28411± ⮀ git add . ➦ bb28411± ⮀ git commit --amend [detached HEAD 36f12d6] change yangcheng Date: Sun Nov 25 11:45:44 2018 +0800
 1 file changed, 1 insertion(+), 1 deletion(-) ➦ 36f12d6 ⮀ git rebase --continue Successfully rebased and updated refs/heads/b3. ⭠ b3 ⮀

 

squash 9a29b81

合併後放入新增的一個commit中。 這是rebase的主要功能!!

緣由:

大量的細小的改動,每一個改動都是一個提交。致使倉庫的history看起來很亂。

許多這樣的commit並無實際地給你的倉庫history增長任何價值

它們弄亂了blame(新舊版本的對比), make bisects take longer and make the history hard to navigate.

⭠ b4 ⮀ git rebase -i master

#此時進入vim編輯器。重寫提交message,而後:wq
[detached HEAD fac0e93] change content
and guangzhou Date: Sun Nov 25 12:42:45 2018 +0800 2 files changed, 3 insertions(+), 1 deletion(-) Successfully rebased and updated refs/heads/b4.

 

而後:

git checkout master git merge b4
git branch -d b4

 

還有另外一種使用squash的方式:

git merge --squash <commit> 能夠把一個分支合併爲一個commit, 而後執行

git commit -m 'squash ...' 

 

最後刪除分支b3:  git branch -D b3


 

安全網:git reflog  

Git保持對分支的tip的追蹤!這種機制叫作reflog(reference logs), 引用日誌。

Git 用引用日誌這種機制來記錄分支頂端的更新和其餘commit引用。

它容許你回到那些不被任何分支或標籤引用的commits。在重寫歷史後,reflog包含了分支舊狀態的信息,有須要的話你能夠回到這個狀態。

每次當你的分支tip被任何緣由所更新(包括切換分支,pulling in new changes, 重寫歷史或者僅僅是增長新的commits), 一個新的entry將被增長到reflog。

reflog提供了一張安全網,全部的分支頂端的變化都會被記錄。

另外, reflog提供了到期日。默認設置expiration time是90天。

 

用法

git reflog # 是git reflog show HEAD的簡寫

顯示: 

fac0e93 HEAD@{0}: merge b4: Fast-forward 6f70a12 HEAD@{1}: checkout: moving from b4 to master fac0e93 HEAD@{2}: rebase -i (finish): returning to refs/heads/b4 fac0e93 HEAD@{3}: rebase -i (squash): change content and guangzhou 0481ff2 HEAD@{4}: rebase -i (pick): change content 6f70a12 HEAD@{5}: rebase -i (start): checkout master 3bc3338 HEAD@{6}: checkout: moving from master to b4 。。。
#fac0e96,第一行是最新的一次relog。

 

還能夠用:

git reflog --relative-date

fac0e93 HEAD@{3 hours ago}: merge b4: Fast-forward
6f70a12 HEAD@{3 hours ago}: checkout: moving from b4 to master
fac0e93 HEAD@{4 hours ago}: rebase -i (finish): returning to refs/heads/b4
...

#顯示相對如今,每條記錄發生的時間!

 

默認,git reflog會輸出HEAD ref。但也能夠顯示其餘ref。

如其餘分支,tags, remotes, Git stash均可以被引用。

引用中的語法格式:name@{qualifier}

得到所有的reflog:

git reflog show --all

 

查看具體某一個分支的引用:

⭠ b5 ⮀ git reflog show b5 //顯示:
905b28c b5@{0}: commit: change bj fac0e93 b5@{1}: branch: Created from HEAD (END)

 

若是使用過git stash命令儲存了緩存區的文件, 而且還未取出,則能夠用git reflog命令查看記錄:

git reflog stash
//顯示
bd1f5f7 stash@{0}: WIP on b5: 905b28c change bj

 

 

另外, 可使用git diff: Show changes between commits, commit and working tree

//git diff stash@{0} otherbranch@{0}
⭠ b5 ⮀ git diff stash@{0} b5@{0}
//顯示 diff --git a/beijing.txt b/beijing.txt index 7719339..6815264 100644 --- a/beijing.txt +++ b/beijing.txt @@ -1,3 +1,4 @@ +123 hahaha hello hello this is a beautiful city! (END)

 

通常用不到,使用圖形編輯器sourcetree,就可直觀的看一個commit的變化。

但用代碼,能夠有更豐富的細節設置,如加上一個到期的時間:

git diff master@{0} master@{1.day.ago}

 

具體可見git diff --help

 

恢復丟失的commits

Git 從不真地丟失任何東西,繼續執行了歷史重寫操做,如rebasing, commit amending。

 

git log的搜索功能很強大,有豐富的設置能夠查看各類狀況。

 

例如:

分支b5有4個commit,master有1個commit超過b5

⭠ b5 ⮀ git rebase -i master //進入vi編輯器。把第4行的pick改爲squash, :wq。 //terminal:
[detached HEAD 55ce6f9] change one Date: Sun Nov 25 17:06:31 2018 +0800
 2 files changed, 3 deletions(-) Successfully rebased and updated refs/heads/b5. 

 結果附加到master上的commit只有3個,最後一個是合併的commit

git log --pretty=oneline //也只能看到新增的3行log
55ce6f9c6f60d80f9b042f5f8a99556333d5854a change one 23bd2a5ead2b5a19d6bcc8667fbd23c636135264 change sth c4e32fb82669aa16ac60e2b9f8a1bc488a366be5 change bj

 

彷佛b5分支的最後2個commit,因爲squash,致使沒法找到了!其實否則:

使用git reflog命令,便可看到最新的ref日誌⬇️:

55ce6f9 HEAD@{0}: rebase -i (finish): returning to refs/heads/b5 55ce6f9 HEAD@{1}: rebase -i (squash): change one 07e7fbf HEAD@{2}: rebase -i (pick): 1 23bd2a5 HEAD@{3}: rebase -i (pick): change sth c4e32fb HEAD@{4}: rebase -i (pick): change bj eb80dcf HEAD@{5}: rebase -i (start): checkout master 1c226ea HEAD@{6}: checkout: moving from master to b5

能夠看到從start到finish的所有細節:一部瞭然!! 

  • 4行綠色是4個commit點
  • 第2行操做的方式是squash

若是想要恢復到執行git rebase以前,可使用:

git reset HEAD@{6}



 

 

保存改變的5個命令:

  • git add

  • git commit

  • git diff (比較commit的不一樣,能夠用可視化工具:sourcetree, 或者上遠程倉庫,在網頁上看。)

  • git stash(上面已經介紹,把staged和未staged的文件儲存起來)

  • .gitignore :這裏就介紹它。

 

.gitignore 

Git從copy的行爲上分類: 把文件分紅3種類別:

  1. tracked -一個文件以前被staged or commited
  2. untracked -一個從未被staged or commited的文件,通常是新建的文件。
  3. ignored -不加入tracked的文件。

包括:

  • 獨立緩存/packages
  • build output directories:如 /bin, /out, /target
  • compiled code:  .pyc, .class文件
  • 在運行時產生的文件:  .log, .lock, .tmp
  • 隱藏的系統文件:  .DS_store, Thumbs.db
  • 我的的IDE配置文件

通常能夠在~/.gitignore文件內查看倉庫中被忽略的文件:

當你有新的文件須要被忽略,.gitignore文件必須手動編輯和提交。

 

Global Git ignore rules

你須要本身創建.gitignore, 並設置core.excludesFile屬性。

$ touch ~/.gitignore $ git config --global core.excludesFile ~/.gitignore

 

 

Shared .gitignore files in your repository

一般,Git ignore rules被定義在倉庫根目錄的.gitignore文件中。

但也能夠在你的倉庫中的不一樣的目錄中定義多個.gitignore文件。

然而最簡單的方法仍是在根目錄建立.gitignor文件,由於它自己也是被版本控制的,當你push,就能夠和團隊共享。

 

Personal Git igonore rules

你也能夠定義我的的ignore模式,這在特殊的.git/info/exclude文件中。

它不會被版本控制!因此你能夠作一些私事!

 

如何忽略一個以前commit過的文件?

從倉庫刪除這個文件,而後增長一個.gitignore rule.

使用 --cached選項和git rm

git-rm - Remove files from the working tree and from the index. --cached: unstage and remove paths only from the index. 但會保留在working directory!

例子:

$ echo debug.log >> .gitignore $ git rm --cached debug.log //提示:rm 'debug.log'  $ git commit -m "Start ignoring debug.log"

[master 6d51c73] Start ignoring debug.log
1 file changed, 1 deletion(-)
delete mode 100644 debug.log


.gitignore自身是被追蹤的!,須要git add .gitignore

 

 

Committing an ignored file

能夠強制一個被忽略的文件被提交到倉庫,使用-f選項便可:

$ cat .gitignore *.log $ git add -f debug.log $ git commit -m "Force adding debug.log"

 

固然,這不是一個明顯的,可讓團隊成員瞭解的方法:改成:

$ echo !debug.log >> .gitignore $ cat .gitignore  *.log  !debug.log $ git add debug.log $ git commit -m "Adding debug.log"

 

*.log表示全部帶.log後綴的文件都會被忽略,可是!dubug.log表示這個文件不會被忽略!

 

Stashing an ignored file

使用git stash回你歷史的存儲本地的變化,並在以後用git stash pop取回。

可是默認git stash忽略.gitignore中的文件。

使用--all選項,能夠stash 忽略的和未跟蹤的文件。

具體git stash 說明文檔見:https://www.atlassian.com/git/tutorials/git-stash/#stashing-untracked-or-ignored

 

Debugging .gitignore files

若是你有複雜的.gitignore模式或者有多個.gitignore文件,那麼想要知道一個文件爲什麼被忽略,就比較麻煩。

你可使用git check-ignore -v <file-name>來看什麼模式讓這個文件被忽略

 


 

 

git rm

用於把一個文件從a Git repository中移除(working directory和index, 或者只從index中移除)。

某種程度上能夠認爲是git add命令的相反命令。

 

git rm命令能夠用於移除單獨的文件或一組文件集合。

它的主要功能是從Git index中移除跟蹤的文件。

另外它也能同時從staging index和 working directory移除文件。

注意git rm 不會移除branches。

 

選項--cached: 

這個選項的用途是取消文件的tracking,但保留這個文件在working directory!

案例見上.gitignore

 

如何undo git rm?

git rm命令須要執行git commit來生效。

git rm將更新staging index 和 working directory,

⚠️這些變化不會立刻產生效果,只有當新的commit被建立,這些變化纔會被添加到commit history中。

這就意味着git rm能夠恢復。(符合git 做爲時光機的原則)執行git reset HEAD

 

⚠️git rm只能用在當前current branch的文件!

 

爲何使用git rm來代替rm

當一個被跟蹤的文件被rm命令執行,Git倉庫會識別這個標準的殼命令rm。

Git倉庫會更新working directory來反應這個移除。但它不會更新staging index。

因此須要額外的git add命令,把這個移除的改變添加到staging index。

git rm 是一個方便的shorcut。它將同時更新working directory and the staging index 。

例子:取消文件shanghai.txt的跟蹤,並刪除這個文件。

⭠ master ⮀ git rm shanghai.txt 提示:rm 'shanghai.txt'
⭠ master± ⮀ git status 提示: On branch master Your branch is ahead of 'origin/master' by 4 commits. (use "git push" to publish your local commits) Changes to be committed: (use "git reset HEAD <file>..." to unstage) deleted: shanghai.txt   #幫你使用了git add命令。

 

⚠️sourcetree,可使用discard,取消一個文件的修改或刪除。就是恢復操做!

等同命令:

git checkout <file>
git checkout -- <file> #加上-- 防止文件名和branch名字重複致使❌。

 

 

Unstage a file:

git reset HEAD <file>  
git rm --cached <file> #刪除staging保留working direotry中的文件。

 

 

小節:

git rm --cache <file>用於再也不對某個文件進行tracking。以前commi過的文件,再也不跟蹤!

git clean -df 刪除未跟蹤的文件和目錄

git reset --hard 回滾跟蹤的文件,即恢復文件到未修改的狀態並再也不跟蹤,新增的文件則從工做目錄刪除。 

 



 

 

git fetch 命令是如何與remote branches 合做的?(深刻分析)

Behind the scenes,在幕後, ./.git/objects目錄中,Git存儲了全部的commits, 包括local和remote。

~/practice/.git/objects ⮀ ⭠ master ⮀ ls
00   0d   1b   24   38   40   51   60   70 7e 8b 9b a8 bb c7 d4 e7 fd 02   11   1c   27   3b   43   55   65   76   81   90   9d   ab   bd   c8   de   eb   info
04   15   1f   2d   3c   49   59   68   77   84   92   a1   ad   be   ce   e0   f0   pack

 

經過使用branch refs(就是commit點的🆔), GIT讓分支commits清楚的分開。

遠程分支的Refs,  儲存在./.git/refs/remotes/

//👇兩條命令均可以查看
git branch -r git branch --all

 

本地分支的Refs,儲存在./.git/refs/heads/

~/practice/.git/refs/heads ⮀ ⭠ master ⮀ ls hotfix master try

 less try能夠看到:

ad64e76234f1dee8ea19618d4f5964edbc20bd36 try (END)

 


 

git log

針對commit點的查詢和搜索功能:

//在屏幕上顯示幾行
git log -n <limit>

//單行顯示,用於全局的概覽, 內容包括id和messages
git log --oneline 
// 顯示每一個commit的文件改變的概覽 git log
--stat //使用-p選項,看每一個提交點的patch。比--stat更詳細的每一個commit的區別 git log -p

  

經過對message進行匹配來搜索,<pattern>能夠是字符串和正則表達式:

git log --grep="<pattern>"

  

看一個特定文件的提交歷史:

git log <file>

  

顯示一個相似sourcetree的結構:

git log --graph --decorate --oneline

 

⚠️,選項能夠一塊兒使用。

 

 

git blame

  • The high-level function of git blame is the display of author metadata attached to specific committed lines in a file. This is used to explore the history of specific code and answer questions about what, how, and why the code was added to a repository.

用於比較commit點的歷史代碼。信息還包括添加代碼的做者名字,解釋。

合做者能夠查看這些歷史代碼。

通常使用UGI網頁,如在線git上查看這些歷史代碼。

例子:example

git clone https://kevzettler@bitbucket.org/kevzettler/git-blame-example.git 
cd git-blame-example

//使用git log查看全部commit信息。
git log

 

 git blame只用於單獨的文件的歷史commit點的比較。須要提供file-path來輸出信息。

//輸出幫助信息
git blame //輸出文件的commit歷史: 即每一個commit的代碼的增減。
git blame README.md
相關文章
相關標籤/搜索