圖解git基本使用

圖解Git

此頁圖解git中的最經常使用命令。若是你稍微理解git的工做原理,這篇文章可以讓你理解的更透徹。 若是你想知道這個站點怎樣產生,請前往GitHub repositoryphp

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

正文

 

這裏寫圖片描述

  1. 基本用法
  2. 約定
  3. 命令詳解
    1. Diff
    2. Commit
    3. Checkout
    4. Detached HEAD(匿名分支提交)
    5. Reset
    6. Merge
    7. Cherry Pick
    8. Rebase
  4. 技術說明

基本用法

上面的四條命令在工做目錄、暫存目錄(也叫作索引)和倉庫之間複製文件。git

  • git add files 把當前文件放入暫存區域。
  • git commit 給暫存區域生成快照並提交。
  • git reset -- files 用來撤銷最後一次git add files,你也能夠用git reset 撤銷全部暫存區域文件。
  • git checkout -- files 把文件從暫存區域複製到工做目錄,用來丟棄本地修改。

你能夠用 git reset -pgit 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分支指向祖父提交節點。瀏覽器

命令詳解

Diff

有許多種方法查看兩次提交之間的變更。下面是一些示例。緩存

Commit

提交時,git用暫存區域的文件建立一個新的提交,並把此時的節點設爲父節點。而後把當前分支指向新的提交節點。下圖中,當前分支是master。 在運行命令以前,master指向ed489,提交後,master指向新的節點f0cec並以ed489做爲父節點。服務器

即使當前分支是某次提交的祖父節點,git會一樣操做。下圖中,在master分支的祖父節點maint分支進行一次提交,生成了1800b。 這樣,maint分支就再也不是master分支的祖父節點。此時,合併 (或者 衍合) 是必須的。app

若是想更改一次提交,使用 git commit --amend。git會使用與當前提交相同的父節點進行一次新提交,舊的提交會被取消。

另外一個例子是分離HEAD提交,後文講。

Checkout

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標識處於分離狀態時的提交操做

HEAD處於分離狀態(不依附於任一分支)時,提交操做能夠正常進行,可是不會更新任何已命名的分支。(你能夠認爲這是在更新一個匿名分支。)

一旦此後你切換到別的分支,好比說master,那麼這個提交節點(可能)不再會被引用到,而後就會被丟棄掉了。注意這個命令以後就不會有東西引用2eecb

可是,若是你想保存這個狀態,能夠用命令git checkout -b name來建立一個新的分支。

Reset

reset命令把當前分支指向另外一個位置,而且有選擇的變更工做目錄和索引。也用來在從歷史倉庫中複製文件到索引,而不動工做目錄。

若是不給選項,那麼當前分支指向到那個提交。若是用--hard選項,那麼工做目錄也更新,若是用--soft選項,那麼都不變。

若是沒有給出提交點的版本號,那麼默認用HEAD。這樣,分支指向不變,可是索引會回滾到最後一次提交,若是用--hard選項,工做目錄也一樣。

若是給了文件名(或者 -p選項), 那麼工做效果和帶文件名的checkout差很少,除了索引被更新。

Merge

merge 命令把不一樣分支合併起來。合併前,索引必須和當前提交相同。若是另外一個分支是當前提交的祖父節點,那麼合併命令將什麼也不作。 另外一種狀況是若是當前提交是另外一個分支的祖父節點,就致使fast-forward合併。指向只是簡單的移動,並生成一個新的提交。

不然就是一次真正的合併。默認把當前提交(ed489 以下所示)和另外一個提交(33104)以及他們的共同祖父節點(b325c)進行一次三方合併。結果是先保存當前目錄和索引,而後和父節點33104一塊兒作一次新提交。

Cherry Pick

cherry-pick命令"複製"一個提交節點並在當前分支作一次徹底同樣的新提交。

Rebase

衍合是合併命令的另外一種選擇。合併把兩個父分支合併進行一次提交,提交歷史不是線性的。衍合在當前分支上重演另外一個分支的歷史,提交歷史是線性的。 本質上,這是線性化的自動的 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 detached from XXX (git HEAD 遊離) 解決辦法

 

 

什麼是 HEAD

Git 中的 HEAD 能夠理解爲一個指針,咱們能夠在命令行中輸入 cat .git/HEAD 查看當前 HEAD 指向哪兒,通常它指向當前工做目錄所在分支的最新提交。

這裏寫圖片描述

當使用 git checkout < branch_name> 切換分支時,HEAD 會移動到指定分支。

這裏寫圖片描述

可是若是使用的是 git checkout < commit id>,即切換到指定的某一次提交,HEAD 就會處於 detached 狀態(遊離狀態)。

這裏寫圖片描述

HEAD 遊離狀態的利與弊

HEAD 處於遊離狀態時,咱們能夠很方便地在歷史版本之間互相切換,好比須要回到某次提交,直接 checkout 對應的 commit id 或者 tag 名便可。

它的弊端就是:在這個基礎上的提交會新開一個匿名分支!

這裏寫圖片描述

也就是說咱們的提交是沒法可見保存的,一旦切到別的分支,遊離狀態之後的提交就不可追溯了。

這裏寫圖片描述

解決辦法就是新建一個分支保存遊離狀態後的提交:

這裏寫圖片描述

具體解決操做

  1. git branch -v 查看當前領先多少 
    • 這裏寫圖片描述
    • 4449a91 指向的是 dev1 的最後一次提交
  2. 新建一個 temp 分支,把當前提交的代碼放到整個分支 
    • 這裏寫圖片描述
  3. checkout 出要回到的那個分支,這裏是 dev1 
    • 這裏寫圖片描述
  4. 而後 merge 剛纔建立的臨時分支,把那些代碼拿回來 
    • 這裏寫圖片描述
  5. git status 查看下合併結果,有衝突就解決 
    • 這裏寫圖片描述
  6. 合併 OK 後就提交到遠端 
    • 這裏寫圖片描述
  7. 刪除剛纔建立的臨時分支

    • 這裏寫圖片描述
  8. 查看 Log,當前 HEAD 指向本地 dev1 ,和遠端 dev1 一致,OK 了!

    • 這裏寫圖片描述

本地Git與遠程倉庫進行關聯

1.進入本地項目路徑,例如 cd /git/test 你的項目路徑/
2.輸入命令

git init  初始化倉庫


3.添加.gitignore文件,將不必的加入版本控制的文件過濾掉,例如

  • index.php(主索引文件)
  • Runtime/*(緩存文件)
  • README.md(readme文件)

這裏使用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 pullgit 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命令同時執行了這兩個命令。

 

1、Git GUI 客戶端

  1. Git 客戶端下載(Windows)
  2. TortoiseGit 客戶端下載(Windows)
  3. Sourcetree 客戶端下載(Windows、Mac)
  4. Git Extensions 客戶端下載(Windows、Mac、Linux)
  5. SmartGit 客戶端下載(Windows、Mac、Linux)
  6. GitEye 客戶端下載 (Windows、Mac、Linux)
  7. gitg 客戶端下載(Windows、Linux)
  8. ungit 客戶端下載(Windows、Mac、Linux)
  9. git-cola 客戶端下載(Windows、Mac、Linux)
  10. Tower 客戶端下載(Mac)
  11. Gitbox 客戶端下載(Mac)
  12. GitUp 客戶端下載(Mac)
  13. giggle 客戶端下載(Linux)
  14. Pocket Git 客戶端下載(Andorid)
  15. Working Copy 客戶端下載(IOS)
  16. Git2Go 客戶端下載(IOS))
  17. GitDrive 客戶端下載(IOS)
  18. 推薦GitKraken https://www.gitkraken.com/

2、Git IDE 插件

  1. Eclipse、Myeclipse 插件下載
  2. Netbeans 插件下載
  3. IntelliJ IDEA 插件下載
  4. Visual Studio 插件下載
  5. Atom 插件下載
  6. Sublime Text 插件下載

3、Git 瀏覽器插件

  1. Git 瀏覽器插件下載(Chrome、Firefox、Safari、Opera,支持碼雲和Github)
  2. Octotree 瀏覽器插件下載(Chrome,支持Github)
  3. GitLab-TreeView 瀏覽器插件下載(Chrome,支持GitLab

4、在線 Git 代碼託管平臺

  1. 碼雲 Gitee 官網
  2. GitHub 官網
  3. GitLab 官網
  4. Bitbucket 官網

 

Thanks

https://marklodato.github.io/visual-git-guide/index-zh-cn.html#detached 
https://git-scm.com/docs/git-checkout#_detached_head

https://blog.csdn.net/u011240877/article/details/76273335

相關文章
相關標籤/搜索