Git 基本操作
整理自網上材料
git clone
git clone <版本庫的網址>
git clone https://github.com/xxxx/xxx.git
該指令會在本地主機生成一個目錄,與遠端主機的版本庫同名。如果要指定不同的目錄名,可以将目錄名作為
git clone
指令的第二個參數。
git clone <版本庫的網址> <本地目錄名>
git clone`支援多種協定,除了HTTP(s)以外,還支援SSH、Git、本地檔案協定等
$ git clone http[s]://example.com/path/to/repo.git/
$ git clone ssh://example.com/path/to/repo.git/
$ git clone git://example.com/path/to/repo.git/
$ git clone /opt/git/project.git
$ git clone file:///opt/git/project.git
$ git clone ftp[s]://example.com/path/to/repo.git/
$ git clone rsync://example.com/path/to/repo.git/
SSH協定還有另一種寫法。
$ git clone [user@]example.com:path/to/repo.git/
通常來說,Git協定下載下傳速度最快,SSH協定用于需要使用者認證的場合。各種協定優劣的詳細讨論請參考官方文檔。
git remote
為了便于管理,Git要求每個遠端主機都必須指定一個主機名。
git remote
指令就用于管理主機名。
不帶選項的時候,
git remote
指令列出所有遠端主機。
$ git remote
origin
使用
-v
選項,可以參看遠端主機的網址。
$ git remote -v
origin [email protected]:jquery/jquery.git (fetch)
origin [email protected]:jquery/jquery.git (push)
上面指令表示,目前隻有一台遠端主機,叫做origin,以及它的網址。
克隆版本庫的時候,所使用的遠端主機自動被Git命名為
origin
。如果想用其他的主機名,需要用
git clone
指令的
-o
選項指定。
$ git clone -o jQuery https://github.com/jquery/jquery.git
$ git remote
jQuery
上面指令表示,克隆的時候,指定遠端主機叫做jQuery。
git remote show
指令加上主機名,可以檢視該主機的詳細資訊。
$ git remote show <主機名>
git remote add
指令用于添加遠端主機。
$ git remote add <主機名> <網址>
git remote rm
指令用于删除遠端主機。
$ git remote rm <主機名>
git remote rename
指令用于遠端主機的改名。
$ git remote rename <原主機名> <新主機名>
git fetch
一旦遠端主機的版本庫有了更新(Git術語叫做commit),需要将這些更新取回本地,這時就要用到
git fetch
指令。
$ git fetch <遠端主機名>
上面指令将某個遠端主機的更新,全部取回本地。
git fetch
指令通常用來檢視其他人的程序,因為它取回的代碼對你本地的開發代碼沒有影響。
預設情況下,
git fetch
取回所有分支(branch)的更新。如果隻想取回特定分支的更新,可以指定分支名。
$ git fetch <遠端主機名> <分支名>
比如,取回
origin
主機的
master
分支。
$ git fetch origin master
所取回的更新,在本地主機上要用"遠端主機名/分支名"的形式讀取。比如
origin
master
,就要用
origin/master
讀取。
git branch
-r
選項,可以用來檢視遠端分支,
-a
選項檢視所有分支。
$ git branch -r
origin/master
$ git branch -a
* master
remotes/origin/master
上面指令表示,本地主機的目前分支是
master
,遠端分支是
origin/master
。
取回遠端主機的更新以後,可以在它的基礎上, 使用
git checkout
指令建立一個新的分支。
$ git checkout -b newBrach origin/master
上面指令表示,在
origin/master
的基礎上,建立一個新分支。
此外,也可以使用
git merge
指令或者
git rebase
指令,在本地分支上合并遠端分支。
$ git merge origin/master
# 或者
$ git rebase origin/master
上面指令表示在目前分支上,合并
origin/master
使用fetch指令取回更新後,會傳回一個
FETCH_HEAD
,指的是某個branch在伺服器上的最新狀态,我們可以在本地通過它檢視剛取回的更新資訊:
$ git log -p FETCH_HEAD
如果覺得fetch取回的更新沒有問題,可以合并到本地分支上:
$ git fetch origin master //從遠端主機的master分支拉取最新内容
$ git merge FETCH_HEAD //将拉取下來的最新内容合并到目前所在的分支中
一般使用git pull 來代替代替fetch 和 merge
git pull
git pull
指令的作用是,取回遠端主機某個分支的更新,再與本地的指定分支合并。它的完整格式稍稍有點複雜。
$ git pull <遠端主機名> <遠端分支名>:<本地分支名>
origin
next
分支,與本地的
master
分支合并,需要寫成下面這樣。
$ git pull origin next:master
如果遠端分支是與目前分支合并,則冒号後面的部分可以省略。
$ git pull origin next
上面指令表示,取回
origin/next
分支,再與目前分支合并。實質上,這等同于先做
git fetch
,再做
git merge
$ git fetch origin
$ git merge origin/next
在某些場合,Git會自動在本地分支與遠端分支之間,建立一種追蹤關系(tracking)。比如,在
git clone
的時候,所有本地分支預設與遠端主機的同名分支,建立追蹤關系,也就是說,本地的
master
分支自動"追蹤"
origin/master
Git也允許手動建立追蹤關系。
$ git branch --set-upstream master origin/next
上面指令指定
master
分支追蹤
origin/next
如果目前分支與遠端分支存在追蹤關系,
git pull
就可以省略遠端分支名。
$ git pull origin
上面指令表示,本地的目前分支自動與對應的
origin
主機"追蹤分支"(remote-tracking branch)進行合并。
如果目前分支隻有一個追蹤分支,連遠端主機名都可以省略。
$ git pull
上面指令表示,目前分支自動與唯一一個追蹤分支進行合并。
如果合并需要采用rebase模式,可以使用
--rebase
選項。
$ git pull --rebase <遠端主機名> <遠端分支名>:<本地分支名>
如果遠端主機删除了某個分支,預設情況下,
git pull
不會在拉取遠端分支的時候,删除對應的本地分支。這是為了防止,由于其他人操作了遠端主機,導緻
git pull
不知不覺删除了本地分支。
但是,你可以改變這個行為,加上參數
-p
就會在本地删除遠端已經删除的分支。
$ git pull -p
# 等同于下面的指令
$ git fetch --prune origin
$ git fetch -p
git push
git push
指令用于将本地分支的更新,推送到遠端主機。它的格式與
git pull
指令相仿。
$ git push <遠端主機名> <本地分支名>:<遠端分支名>
注意,分支推送順序的寫法是<來源地>:<目的地>,是以
git pull
是<遠端分支>:<本地分支>,而
git push
是<本地分支>:<遠端分支>。
如果省略遠端分支名,則表示将本地分支推送與之存在"追蹤關系"的遠端分支(通常兩者同名),如果該遠端分支不存在,則會被建立。
$ git push origin master
上面指令表示,将本地的
master
分支推送到
origin
master
分支。如果後者不存在,則會被建立。
如果省略本地分支名,則表示删除指定的遠端分支,因為這等同于推送一個空的本地分支到遠端分支。
$ git push origin :master
# 等同于
$ git push origin --delete master
上面指令表示删除
origin
master
如果目前分支與遠端分支之間存在追蹤關系,則本地分支和遠端分支都可以省略。
$ git push origin
上面指令表示,将目前分支推送到
origin
主機的對應分支。
如果目前分支隻有一個追蹤分支,那麼主機名都可以省略。
$ git push
如果目前分支與多個主機存在追蹤關系,則可以使用
-u
選項指定一個預設主機,這樣後面就可以不加任何參數使用
git push
$ git push -u origin master
上面指令将本地的
master
origin
主機,同時指定
origin
為預設主機,後面就可以不加任何參數使用
git push
了。
不帶任何參數的
git push
,預設隻推送目前分支,這叫做simple方式。此外,還有一種matching方式,會推送所有有對應的遠端分支的本地分支。Git 2.0版本之前,預設采用matching方法,現在改為預設采用simple方式。如果要修改這個設定,可以采用
git config
$ git config --global push.default matching
# 或者
$ git config --global push.default simple
還有一種情況,就是不管是否存在對應的遠端分支,将本地的所有分支都推送到遠端主機,這時需要使用
--all
$ git push --all origin
上面指令表示,将所有本地分支都推送到
origin
主機。
如果遠端主機的版本比本地版本更新,推送時Git會報錯,要求先在本地做
git pull
合并差異,然後再推送到遠端主機。這時,如果你一定要推送,可以使用
--force
$ git push --force origin
上面指令使用
--force
選項,結果導緻遠端主機上更新的版本被覆寫。除非你很确定要這樣做,否則應該盡量避免使用
--force
最後,
git push
不會推送标簽(tag),除非使用
--tags
$ git push origin --tags
git add
添加檔案到暫存區
# 添加某個檔案到暫存區,後面可以跟多個檔案,以空格區分
git add xxx
# 添加目前更改的所有檔案到暫存區。
git add .
git commit
# 送出暫存的更改,會新開編輯器進行編輯
git commit
# 送出暫存的更改,并記錄下備注
git commit -m "you message"
# 等同于 git add . && git commit -m
git commit -am
# 對最近一次的送出的資訊進行修改,此操作會修改commit的hash值
git commit --amend
git branch
# 建立本地分支,但不切換
git branch <branch-name>
# 檢視本地分支
git branch
# 檢視遠端分支
git branch -r
# 檢視本地和遠端分支
git branch -a
# 删除本地分支
git branch -D <branch-nane>
# 重新命名分支
git branch -m <old-branch-name> <new-branch-name>
通過 git branch -d
删除一個分支,比如:
git branch -d fix/authentication
當一個分支被推送并合并到遠端分支後, -d 才會本地删除該分支。
如果一個分支還沒有被推送或者合并,那麼可以使用 -D 強制删除它。 這就是本地删除分支的方法。
已有本地分支,與遠端庫建立關聯
git branch --set-upstream-to origin/遠端分支名 本地分支名
git checkout
git checkout指令對三個不同的實體進行操作, 它們分别是檔案, 送出和分支。有時, 此指令可能很危險, 因為此指令上沒有撤消選項。
切換本地分支,前提是分支存在:
$ git checkout <branchname>
建立并切換分支,注意,它是基于本地庫目前所處的分支上建立并切換,與遠端庫沒有關系:
$ git checkout -b <branchname>
git checkout指令使你可以建立并切換到新分支。你不僅可以建立一個新分支, 還可以通過單個指令同時切換它。 git checkout -b選項是一個便利标志, 它在運作git checkout 之前執行run git branch 操作。
拉去遠端庫分支,并在本地建立新分支,然後切換到新的分支上:
git checkout -b 本地分支名 origin/遠端分支名
注意:這是針對本地沒有改分支。
如果拉去不成功,則可能是本地沒有遠端庫的資訊,需要先執行:
git fetch
然後再
git checkout -b 本地分支名 origin/遠端分支名
使用git pull指令也可以:
$ git pull <遠端主機名> <遠端分支名>:<本地分支名>
git merge
合并分支
git merge branchname
git log
檢視版本資訊
# 檢視版本
git reflog
# 檢視版本詳細資訊
git log
git reset
如果想恢複到之前某個送出的版本,且那個版本之後送出的版本我們都不要了,就可以用這種方法。
版本穿梭
git reset --hard 版本号
退回到上一個版本
git reset --hard HEAD^
此時如果用
git push
會報錯,因為我們本地庫HEAD指向的版本比遠端庫的要舊:
需要使用
強推版本。
git push -f
git revert
git revert
是用于“反轉、逆轉”某一個版本,以達到撤銷該版本的修改的目的。比如,我們commit了三個版本(版本一、版本二、 版本三),突然發現版本二不行(如:有bug),想要撤銷版本二,但又不想影響撤銷版本三的送出,就可以用 git revert 指令來反做版本二,生成新的版本四,這個版本四裡會保留版本三的東西,但撤銷了版本二的東西。
最重要的一點:revert 是復原某個 commit ,不是復原“到”某個
指令
git revert -n 版本号
git rebase
rebase 是”變基”的意思,這裡的”基”,在我了解是指[多次] commit 形成的 git workflow,使用 rebase,我們可以改變這些曆史送出,修改 commit 資訊,将多個 commit 進行組合。
git tag
列出标簽
# 可帶上可選的 -l 選項 --list
git tag
# 如果隻對 1.8.5 系列感興趣,可以運作:
git tag -l "v1.8.5*"
v1.8.5
v1.8.5-rc0
v1.8.5-rc1
v1.8.5-rc2
v1.8.5-rc3
v1.8.5.1
v1.8.5.2
v1.8.5.3
v1.8.5.4
v1.8.5.5
建立标簽
Git 支援兩種标簽:輕量标簽(lightweight)與附注标簽(annotated)。
輕量标簽很像一個不會改變的分支——它隻是某個特定送出的引用。
而附注标簽是存儲在 Git 資料庫中的一個完整對象, 它們是可以被校驗的,其中包含打标簽者的名字、電子郵件位址、日期時間, 此外還有一個标簽資訊,并且可以使用 GNU Privacy Guard (GPG)簽名并驗證。 通常會建議建立附注标簽,這樣你可以擁有以上所有資訊。但是如果你隻是想用一個臨時的标簽, 或者因為某些原因不想要儲存這些資訊,那麼也可以用輕量标簽。
附注标簽
在 Git 中建立附注标簽十分簡單。 最簡單的方式是當你在運作
tag
指令時指定
-a
選項:
$ git tag -a v1.4 -m "my version 1.4"
$ git tag
v0.1
v1.3
v1.4
-m
選項指定了一條将會存儲在标簽中的資訊。 如果沒有為附注标簽指定一條資訊,Git 會啟動編輯器要求你輸入資訊。
通過使用
git show
指令可以看到标簽資訊和與之對應的送出資訊:
$ git show v1.4
tag v1.4
Tagger: Ben Straub <[email protected]>
Date: Sat May 3 20:19:12 2014 -0700
my version 1.4
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <[email protected]>
Date: Mon Mar 17 21:52:11 2008 -0700
changed the version number
輸出顯示了打标簽者的資訊、打标簽的日期時間、附注資訊,然後顯示具體的送出資訊。
輕量标簽
另一種給送出打标簽的方式是使用輕量标簽。 輕量标簽本質上是将送出校驗和存儲到一個檔案中——沒有儲存任何其他資訊。 建立輕量标簽,不需要使用
-a
、
-s
或
-m
選項,隻需要提供标簽名字:
$ git tag v1.4-lw
$ git tag
v0.1
v1.3
v1.4
v1.4-lw
v1.5
這時,如果在标簽上運作
git show
,你不會看到額外的标簽資訊。 指令隻會顯示出送出資訊:
$ git show v1.4-lw
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <[email protected]>
Date: Mon Mar 17 21:52:11 2008 -0700
changed the version number
後期打标簽
你也可以對過去的送出打标簽。 假設送出曆史是這樣的:
$ git log --pretty=oneline
15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment'
a6b4c97498bd301d84096da251c98a07c7723e65 beginning write support
0d52aaab4479697da7686c15f77a3d64d9165190 one more thing
6d52a271eda8725415634dd79daabbc4d9b6008e Merge branch 'experiment'
0b7434d86859cc7b8c3d5e1dddfed66ff742fcbc added a commit function
4682c3261057305bdd616e23b64b0857d832627b added a todo file
166ae0c4d3f420721acbb115cc33848dfcc2121a started write support
9fceb02d0ae598e95dc970b74767f19372d61af8 updated rakefile
964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo
8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme
現在,假設在 v1.2 時你忘記給項目打标簽,也就是在 “updated rakefile” 送出。 你可以在之後補上标簽。 要在那個送出上打标簽,你需要在指令的末尾指定送出的校驗和(或部分校驗和):
$ git tag -a v1.2 9fceb02
可以看到你已經在那次送出上打上标簽了:
$ git tag
v0.1
v1.2
v1.3
v1.4
v1.4-lw
v1.5
$ git show v1.2
tag v1.2
Tagger: Scott Chacon <[email protected]>
Date: Mon Feb 9 15:32:16 2009 -0800
version 1.2
commit 9fceb02d0ae598e95dc970b74767f19372d61af8
Author: Magnus Chacon <[email protected]>
Date: Sun Apr 27 20:43:35 2008 -0700
updated rakefile
...
共享标簽
git push
指令并不會傳送标簽到遠端倉庫伺服器上。 在建立完标簽後你必須顯式地推送标簽到共享伺服器上。 這個過程就像共享遠端分支一樣——你可以運作
git push origin
$ git push origin v1.5
Counting objects: 14, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (14/14), 2.05 KiB | 0 bytes/s, done.
Total 14 (delta 3), reused 0 (delta 0)
To [email protected]:schacon/simplegit.git
* [new tag] v1.5 -> v1.5
如果想要一次性推送很多标簽,也可以使用帶有
--tags
選項的
git push
指令。 這将會把所有不在遠端倉庫伺服器上的标簽全部傳送到那裡。
$ git push origin --tags
Counting objects: 1, done.
Writing objects: 100% (1/1), 160 bytes | 0 bytes/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To [email protected]:schacon/simplegit.git
* [new tag] v1.4 -> v1.4
* [new tag] v1.4-lw -> v1.4-lw
現在,當其他人從倉庫中克隆或拉取,他們也能得到你的那些标簽。
Note | 推送兩種标簽 使用 推送标簽并不會區分輕量标簽和附注标簽, 沒有簡單的選項能夠讓你隻選擇推送一種标簽。 |
---|---|
删除标簽
要删除掉你本地倉庫上的标簽,可以使用指令
git tag -d
。 例如,可以使用以下指令删除一個輕量标簽:
$ git tag -d v1.4-lw
Deleted tag 'v1.4-lw' (was e7d5add)
注意上述指令并不會從任何遠端倉庫中移除這個标簽,你必須用
git push :refs/tags/
來更新你的遠端倉庫:
第一種變體是
git push :refs/tags/
:
$ git push origin :refs/tags/v1.4-lw
To /[email protected]:schacon/simplegit.git
- [deleted] v1.4-lw
上面這種操作的含義是,将冒号前面的空值推送到遠端标簽名,進而高效地删除它。
第二種更直覺的删除遠端标簽的方式是:
$ git push origin --delete <tagname>
檢出标簽
如果你想檢視某個标簽所指向的檔案版本,可以使用
git checkout
指令, 雖然這會使你的倉庫處于“分離頭指針(detached HEAD)”的狀态——這個狀态有些不好的副作用:
$ git checkout 2.0.0
Note: checking out '2.0.0'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b <new-branch>
HEAD is now at 99ada87... Merge pull request #89 from schacon/appendix-final
$ git checkout 2.0-beta-0.1
Previous HEAD position was 99ada87... Merge pull request #89 from schacon/appendix-final
HEAD is now at df3f601... add atlas.json and cover image
在“分離頭指針”狀态下,如果你做了某些更改然後送出它們,标簽不會發生變化, 但你的新送出将不屬于任何分支,并且将無法通路,除非通過确切的送出哈希才能通路。 是以,如果你需要進行更改,比如你要修複舊版本中的錯誤,那麼通常需要建立一個新分支:
$ git checkout -b version2 v2.0.0
Switched to a new branch 'version2'
如果在這之後又進行了一次送出,
version2
分支就會因為這個改動向前移動, 此時它就會和
v2.0.0
标簽稍微有些不同,這時就要當心了。
将tag同步到遠端伺服器
同送出代碼後,使用
git push
來推送到遠端伺服器一樣,
tag
也需要進行推送才能到遠端伺服器。
git push origin [tagName]
推送單個分支。
git push origin v1.0
推送本地所有tag,使用
git push origin --tags