此頁圖解git中的最經常使用命令。若是你稍微理解git的工做原理,這篇文章可以讓你理解的更透徹。 若是你想知道這個站點怎樣產生,請前往GitHub repository。php
git配置文件html
[user] name = zhaoyingchao email = zyc@alibaba-inc.com [alias] st = status -sb co = checkout br = branch -a mg = merge ci = commit cil = commit --amend ds = diff --staged dt = difftool mt = mergetool last = log -1 HEAD latest = for-each-ref --sort=-committerdate --format=\"%(committername)@%(refname:short) [%(committerdate:short)] %(contents)\" ls = log --pretty=format:\"%C(yellow)%h %C(blue)%ad %C(red)%d %C(reset)%s %C(green)[%cn]\" --decorate --date=short hist = log --pretty=format:\"%C(yellow)%h %C(red)%d %C(reset)%s %C(green)[%an] %C(blue)%ad\" --topo-order --graph --date=short type = cat-file -t dump = cat-file -p lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit lgc = log --branches --not --remotes lgac =log --branches --not --remotes --simplify-by-decoration --decorate --online [core] autocrlf = true [push] default = simple [credential] helper = store username = zhaoyingchao
上面的四條命令在工做目錄、暫存目錄(也叫作索引)和倉庫之間複製文件。git
git add files
把當前文件放入暫存區域。git commit
給暫存區域生成快照並提交。git reset -- files
用來撤銷最後一次git add files
,你也能夠用git reset
撤銷全部暫存區域文件。git checkout -- files
把文件從暫存區域複製到工做目錄,用來丟棄本地修改。你能夠用 git reset -p
, git checkout -p
, or git add -p
進入交互模式。github
也能夠跳過暫存區域直接從倉庫取出文件或者直接提交代碼。數據庫
git commit -a
至關於運行 git add 把全部當前目錄下的文件加入暫存區域再運行。git commit.git commit files
進行一次包含最後一次提交加上工做目錄中文件快照的提交。而且文件被添加到暫存區域。git checkout HEAD -- files
回滾到複製最後一次提交。後文中如下面的形式使用圖片。vim
綠色的5位字符表示提交的ID,分別指向父節點。分支用橘色顯示,分別指向特定的提交。當前分支由附在其上的HEAD標識。 這張圖片裏顯示最後5次提交,ed489是最新提交。 master分支指向這次提交,另外一個maint分支指向祖父提交節點。瀏覽器
有許多種方法查看兩次提交之間的變更。下面是一些示例。緩存
提交時,git用暫存區域的文件建立一個新的提交,並把此時的節點設爲父節點。而後把當前分支指向新的提交節點。下圖中,當前分支是master。 在運行命令以前,master指向ed489,提交後,master指向新的節點f0cec並以ed489做爲父節點。服務器
即使當前分支是某次提交的祖父節點,git會一樣操做。下圖中,在master分支的祖父節點maint分支進行一次提交,生成了1800b。 這樣,maint分支就再也不是master分支的祖父節點。此時,合併 (或者 衍合) 是必須的。app
若是想更改一次提交,使用 git commit --amend
。git會使用與當前提交相同的父節點進行一次新提交,舊的提交會被取消。
另外一個例子是分離HEAD提交,後文講。
checkout命令用於從歷史提交(或者暫存區域)中拷貝文件到工做目錄,也可用於切換分支。
當給定某個文件名(或者打開-p選項,或者文件名和-p選項同時打開)時,git會從指定的提交中拷貝文件到暫存區域和工做目錄。好比,git checkout HEAD~ foo.c
會將提交節點HEAD~(即當前提交節點的父節點)中的foo.c
複製到工做目錄而且加到暫存區域中。(若是命令中沒有指定提交節點,則會從暫存區域中拷貝內容。)注意當前分支不會發生變化。
當不指定文件名,而是給出一個(本地)分支時,那麼HEAD標識會移動到那個分支(也就是說,咱們「切換」到那個分支了),而後暫存區域和工做目錄中的內容會和HEAD對應的提交節點一致。新提交節點(下圖中的a47c3)中的全部文件都會被複制(到暫存區域和工做目錄中);只存在於老的提交節點(ed489)中的文件會被刪除;不屬於上述二者的文件會被忽略,不受影響。
若是既沒有指定文件名,也沒有指定分支名,而是一個標籤、遠程分支、SHA-1值或者是像master~3相似的東西,就獲得一個匿名分支,稱做detached HEAD(被分離的HEAD標識)。這樣能夠很方便地在歷史版本之間互相切換。好比說你想要編譯1.6.6.1版本的git,你能夠運行git checkout v1.6.6.1
(這是一個標籤,而非分支名),編譯,安裝,而後切換回另外一個分支,好比說git checkout master
。然而,當提交操做涉及到「分離的HEAD」時,其行爲會略有不一樣,詳情見在下面。
當HEAD處於分離狀態(不依附於任一分支)時,提交操做能夠正常進行,可是不會更新任何已命名的分支。(你能夠認爲這是在更新一個匿名分支。)
一旦此後你切換到別的分支,好比說master,那麼這個提交節點(可能)不再會被引用到,而後就會被丟棄掉了。注意這個命令以後就不會有東西引用2eecb。
可是,若是你想保存這個狀態,能夠用命令git checkout -b name
來建立一個新的分支。
reset命令把當前分支指向另外一個位置,而且有選擇的變更工做目錄和索引。也用來在從歷史倉庫中複製文件到索引,而不動工做目錄。
若是不給選項,那麼當前分支指向到那個提交。若是用--hard
選項,那麼工做目錄也更新,若是用--soft
選項,那麼都不變。
若是沒有給出提交點的版本號,那麼默認用HEAD。這樣,分支指向不變,可是索引會回滾到最後一次提交,若是用--hard
選項,工做目錄也一樣。
若是給了文件名(或者 -p
選項), 那麼工做效果和帶文件名的checkout差很少,除了索引被更新。
merge 命令把不一樣分支合併起來。合併前,索引必須和當前提交相同。若是另外一個分支是當前提交的祖父節點,那麼合併命令將什麼也不作。 另外一種狀況是若是當前提交是另外一個分支的祖父節點,就致使fast-forward合併。指向只是簡單的移動,並生成一個新的提交。
不然就是一次真正的合併。默認把當前提交(ed489 以下所示)和另外一個提交(33104)以及他們的共同祖父節點(b325c)進行一次三方合併。結果是先保存當前目錄和索引,而後和父節點33104一塊兒作一次新提交。
cherry-pick命令"複製"一個提交節點並在當前分支作一次徹底同樣的新提交。
衍合是合併命令的另外一種選擇。合併把兩個父分支合併進行一次提交,提交歷史不是線性的。衍合在當前分支上重演另外一個分支的歷史,提交歷史是線性的。 本質上,這是線性化的自動的 cherry-pick
上面的命令都在topic分支中進行,而不是master分支,在master分支上重演,而且把分支指向新的節點。注意舊提交沒有被引用,將被回收。
要限制回滾範圍,使用--onto
選項。下面的命令在master分支上重演當前分支從169a6以來的最近幾個提交,即2c33a。
一樣有git rebase --interactive
讓你更方便的完成一些複雜操做,好比丟棄、重排、修改、合併提交。沒有圖片體現這些,細節看這裏:git-rebase(1)
文件內容並無真正存儲在索引(.git/index)或者提交對象中,而是以blob的形式分別存儲在數據庫中(.git/objects),並用SHA-1值來校驗。 索引文件用識別碼列出相關的blob文件以及別的數據。對於提交來講,以樹(tree)的形式存儲,一樣用對於的哈希值識別。樹對應着工做目錄中的文件夾,樹中包含的 樹或者blob對象對應着相應的子目錄和文件。每次提交都存儲下它的上一級樹的識別碼。
若是用detached HEAD提交,那麼最後一次提交會被the reflog for HEAD引用。可是過一段時間就失效,最終被回收,與git commit --amend
或者git rebase
很像。
Git 中的 HEAD 能夠理解爲一個指針,咱們能夠在命令行中輸入 cat .git/HEAD
查看當前 HEAD 指向哪兒,通常它指向當前工做目錄所在分支的最新提交。
當使用 git checkout < branch_name>
切換分支時,HEAD 會移動到指定分支。
可是若是使用的是 git checkout < commit id>
,即切換到指定的某一次提交,HEAD 就會處於 detached 狀態(遊離狀態)。
HEAD 處於遊離狀態時,咱們能夠很方便地在歷史版本之間互相切換,好比須要回到某次提交,直接 checkout 對應的 commit id 或者 tag 名便可。
它的弊端就是:在這個基礎上的提交會新開一個匿名分支!
也就是說咱們的提交是沒法可見保存的,一旦切到別的分支,遊離狀態之後的提交就不可追溯了。
解決辦法就是新建一個分支保存遊離狀態後的提交:
dev1
的最後一次提交checkout
出要回到的那個分支,這裏是 dev1
merge
剛纔建立的臨時分支,把那些代碼拿回來
git status
查看下合併結果,有衝突就解決
刪除剛纔建立的臨時分支
查看 Log,當前 HEAD 指向本地 dev1 ,和遠端 dev1 一致,OK 了!
1.進入本地項目路徑,例如 cd /git/test 你的項目路徑/
2.輸入命令
git init 初始化倉庫
3.添加.gitignore文件,將不必的加入版本控制的文件過濾掉,例如
這裏使用vim .gitignore編輯文件,而後加入如下三行,而後保存退出:wq
index.php Runtime/* README.md
4.當前輸入git remote
命令後,咱們能夠看到沒有任何東西輸出,由於咱們還沒添加遠程倉庫,如今咱們添加遠程倉庫地址,例如 執行命令git remote add origin 遠程倉庫地址(這裏使用https地址來進行訪問)
,添加後,咱們再試試執行命令git remote
看看,終於有輸出了
git remote git remote add origin 遠程倉庫地址
origin git@xxx:intelligencevillage.git (fetch) origin git@xxx:intelligencevillage.git (push)
5.而後咱們先嚐試添加代碼到本地倉庫,執行git add -A
,-A是自動添加所有要上傳到倉庫的文件,添加完後輸入git commit
提交到本地倉庫。
git add -A -A是自動添加所有要上傳到倉庫的文件,添加完後輸入 git commit 提交到本地倉庫
6.以後使用git push
上傳到遠程倉庫,若是是新建分支第一次push,會提示:
git push
英文:
fatal: The current branch develop has no upstream branch. To push the current branch and set the remote as upstream, use git push --set-upstream origin master
中文:
fatal: 當前分支 master 沒有對應的上游分支。 爲推送當前分支並創建與遠程上游的跟蹤,使用 git push --set-upstream origin master
而後輸入git push --set-upstream origin master
這行命令,再而後輸入用戶名和密碼,就push成功了。
之後的push就只須要輸入git push origin
若是使用SSH訪問方式的話,則須要生成ssh公鑰才能訪問(一下是ssh訪問方式)
$ssh-keygen -t rsa -b 4096 -C "your_email@example.com" # Creates a new ssh key, using the provided email as a label # Generating public/private rsa key pair. Enter file in which to save the key (/Users/you/.ssh/id_rsa): [Press enter] //
7.當發現遠程倉庫已經有內容並提示先執行git pull
,將內容進行合併後再上傳,在執行git pull
的時候,或者會出現
There is no tracking information for the current branch. Please specify which branch you want to merge with. See git-pull(1) for details git pull <remote> <branch> If you wish to set tracking information for this branch you can do so with: git branch --set-upstream-to=origin/<branch> master
也就是指定當前工做目錄工做分支,跟遠程的倉庫,分支之間的連接關係。而後按照提示輸入git branch --set-upstream-to=origin/master master
與master分支關聯,完成後再執行 git pull
和 git push
,打完收工!
git branch --set-upstream-to=origin/master master 與master分支關聯指定當前工做目錄工做分支,跟遠程的倉庫,分支之間的連接關係。 git pull git push
遠程分支
要說分支就必定要從分支產生的最遙遠的歷史談起。這一切開始於你用clone命令從遠端把代碼庫的代碼拉取到本地開始。這個時候,git自動把這個遠端代碼庫命名爲origin並自動建立一個origin/master分支。相對的在本地建立一個叫作master的本地分支。這個時候這兩個分支的指針都是指向一個地方的(不一樣的push發生的時候,master的指針就會發生變化)。
要建立一個遠程分支是很是必要的。也很是的簡單。只須要先建立一個本地分支。
git branch 分支名 如 git branch develop
這只是建立了一個叫作develop的分支。若是要使用這個分支,還須要切換到這個分支上:
git checkout 分支名 如 git checkout develop
還有一個更快的方式建立分支,並直接切換到這個分支上:
git checkout -b 分支名 git checkout -b develop
一個命令就把上面的兩個命令幹得事所有搞定了。
說了半天都是折騰在本地分支(local branch)了。沒有離題。遠程分支就是本地分支push到遠端之後生成的。也就是前面咱們折騰出來的develop分支只要push到遠端服務器上就能夠了。
git push origin 分支名 git push origin develop
可是,你還須要給你創建起來的遠端的和本地的分支設定一個直接的聯繫。這個時候就須要把你本地的分支變成一個tracking branch。Tracking branch就是一個和遠端的分支有直接聯繫的本地分支。若是你在一個tracking branch裏使用git pull命令,那麼git自動檢測到從哪一個代碼庫獲取代碼和哪一個分支執行merge操做。建立tracking branch:
git checkout --track origin/分支名 git checkout --track origin/develop
整個的命令是:
git checkout -b [本地分支名] [遠端代碼庫名稱]/[分支名] //這時會建立一個本地分支名和遠端分支名不同的分支
上面的是一個簡寫的版本。
下面是要給謹慎使用的命令,刪除遠端分支。
git push origin --delete develop To https://github.com/xxx/xxxx.git - [deleted] develop
這個時候遠端分支就被刪除了。
平常工做
平常裏使用Git的時候就是處理代碼的pull,push和merge以及在這個時候遇到的各類問題。
既然有了這麼多分支。也許是兩個,可是使用Git建立分支的成本真的很是的低,因此有的時候能夠是每個大一點的issue就是一個分支。這時候就須要在多個分支之間切換:
git checkout [分支名稱] git checkout develop
天天早晨一到公司首先要作的就是確保你在正確的分支上,而後從git repository上面把代碼弄下來。這就要用到pull:
git pull [遠端代碼庫名稱] [分支名稱] git pull origin develop
若是你在前一天的晚上忘記push代碼或者有其餘的人在你push以後push了代碼了。那麼就會遇到:「衝突」。git會告訴你:
error: Your local changes to "你修改過的文件" would be overwritten by merge. Aborting.
Please commit your changes or stash them before you can merge.
這種狀況是編輯文件的衝突
這樣的一個Aborting很是的鬱悶。好的提示已經告訴咱們該如何解決這個問題了。使用stash。
1. 使用stash命令把本地的代碼先存起來。
git stash
這時,你本地的修改已經暫時存起來了。使用命令:git stash list能夠看到保存的信息。
2. 而後使用咱們上面說到的pull命令拉取遠端庫的代碼。
git pull
3. 還原暫時保存的本地的修改
git stash pop stash@{0}
手動的解決衝突吧。當你處理好這些衝突的代碼以後。
git add [衝突文件名]
而後commit,以後:
當把代碼同步的事情弄順了之後就應該考慮要把本地文件提交到遠端代碼庫了。
git push origin [本地分支名]:[遠端分支名]
固然若是你的本地分支名和遠端分支名是同樣的,那麼就只須要git push origin [分支名稱]就能夠了。
補充:
1. 有的時候即便你處理完成衝突以後再commit仍是會有問題:
fatal: cannot do a partial commit during a merge.
這個時候:
git commit -i [衝突文件名]
來commit衝突的文件。
2. 這裏你還會用到別的命令:
git status // 看看git裏的狀態,是衝突的有哪些文件等 git show | head // 查看commit進去的是誰、日期等
3. 撤銷對某個文件的修改:
git checkout -- [文件名]
若是是文件的刪除衝突的話:
這個時候只要使用
git rm [文件名]
刪掉已經被刪掉的文件就能夠了。
commit以後用git show | head命令查看結果。
合併分支
要合併那個分支,好比要把develop的分支合併到master上。那麼:
1. 轉到master分支上:
git checkout master
2. 開始合併:
git merge develop
在這個命令執行以後就會把develop分支上的代碼都合併到master上了。
若是遇到任何衝突
git diff //查看是什麼衝突
按照以上提到的解決衝突的方法解決衝突就能夠。
撤銷一個合併
若是你發現你的本地代碼簡直是一團糟,須要回到合併以前的狀態:
git reset --hard HEAD
本地代碼回到合併以前的狀態。
或者,你已經把合併後的代碼提交,但仍是想把它們撤銷:
git reset --hard ORIG_HEAD
可是這個命令某些狀況下會很危險,尤爲是在你已經把合併後的分支刪除以後再使用這個命令。。。
刪除不存在對應於遠程分支的本地分支
在刪除以前首先須要查看一下遠端代碼庫origin下得分支都是什麼狀況的:
$ git remote show origin #* remote origin # Fetch URL: git@github.com:xxx/xxx.git # Push URL: git@github.com:xxx/xxx.git # HEAD branch: master # Remote branches: # master tracked # refs/remotes/origin/b1 stale (use 'git remote prune' to remove) # Local branch configured for 'git pull': # master merges with remote master # Local ref configured for 'git push': # master pushes to master (up to date)
這時候你會看到這個b1的分支仍是stable的。使用git remote prune origin能夠將其從本地代碼庫中去除。
還有一個更簡單的方法:git fetch -p。會在fetch以後刪除沒有與遠程分支對應的本地分支。
重命名遠程分支
這個過程很墨跡。由於要先刪除遠程分支,而後重命名本地分支,而後再提交這個命名好的本地分支到遠程分支。
如今有一個devel的分支,要把它重命名爲develop。先用git branch -av命令查看分支的情況。這裏最重要是肯定好了,你要刪除的不是默認分支!以後就能夠刪除了:
git push --delete origin devel #To git@github.com:xxx/xxxxxxxx.git # - [deleted] devel
重命名本地分支:
git branch -m devel develop
推送本地分支到遠端:
$ git push origin develop #Counting objects: 92, done. #Delta compression using up to 4 threads. #Compressing objects: 100% (48/48), done. #Writing objects: 100% (58/58), 1.38 MiB, done. #Total 58 (delta 34), reused 12 (delta 5) #To git@github.com:xxx/xxx-xxxxxx-x.git # * [new branch] develop -> develop
查看未推送
查看所有分支的已經commit可是沒有push的:
git log --branches --not --remotes
查看所有分支的所有的最近的commit:
git log --branches --not --remotes --simplify-by-decoration --decorate --online
查看某文件的歷史記錄:
git log my/file.c #所有歷史 git log -n 1 -- my/file.c #查看最近歷史修改
常見錯誤處理
1. non-fast-forward
若是有人比你先push代碼到你所在的分支了,那麼git就不容許你再嵌入代碼到這代碼庫。
git push origin master # To https://github.com/USERNAME/REPOSITORY.git # ! [rejected] master -> master (non-fast-forward) # error: failed to push some refs to 'https://github.com/USERNAME/REPOSITORY.git' # To prevent you from losing history, non-fast-forward updates were rejected # Merge the remote changes (e.g. 'git pull') before pushing again. See the # 'Note about fast-forwards' section of 'git push --help' for details.
這時候使用fetch和merge的方法解決這個問題:
fetch: git fetch origin [分支名稱] merge: git merge origin [分支名稱] 等於 git pull
或者直接pull。pull命令同時執行了這兩個命令。
https://marklodato.github.io/visual-git-guide/index-zh-cn.html#detached
https://git-scm.com/docs/git-checkout#_detached_head