總結自:
廖雪峯的官方網站(Git教程)
Git
創建文件夾learngit
$ mkdir learngit
進入目錄learngit
$ cd learngit
顯示當前路徑
$ pwd
顯示隱藏文件夾
$ ls -ah
顯示內容
$ cat readme.txt
刪除文件test.txt
$ rm test.txt
創建版本庫\提交
初始化當前目錄爲倉庫
$ git init
添加指定文件(readme.txt)到暫存區,可以一次添加多文件
$ git add readme.txt
提交到倉庫,此次提交描述爲:"wrote a readme file"
$ git commit -m "wrote a readme file"
初始化一個Git倉庫,使用git init
命令。
添加文件到Git倉庫,分兩步:
- 使用命令
git add <file>
,注意,可反覆多次使用,添加多個文件; - 使用命令
git commit -m <message>
,完成。
查看狀態
查看倉庫當前的狀態
$ git status
查看difference,顯示的格式正是Unix通用的diff格式
$ git diff readme.txt
顯示從最近到最遠的提交日誌
$ git log
$ git log --pretty=oneline
要隨時掌握工作區的狀態,使用git status
命令。
如果git status
告訴你有文件被修改過,用git diff
可以查看修改內容
時光機穿梭
版本回退
回退到上一個版本
$ git reset --hard HEAD^
回退到指定版本
$ git reset --hard 1094a
查看命令歷史記錄
$ git reflog
HEAD
指向的版本就是當前版本,因此,Git允許我們在版本的歷史之間穿梭,使用命令git reset --hard commit_id
。
穿梭前,用git log
可以查看提交歷史,以便確定要回退到哪個版本。
要重返未來,用git reflog
查看命令歷史,以便確定要回到未來的哪個版本。
管理修改
比較工作區和暫存區(最後一次add)的區別
$ git diff readme.txt
比較暫存區和版本庫的區別
$ git diff --cached
查看工作區和版本庫裏面最新版本的區別
$ git diff HEAD -- readme.txt
每次修改,如果不用git add
到暫存區,那就不會加入到commit
中。
撤銷修改
讓文件回到最近一次git commit或git add時的狀態。
$ git checkout -- readme.txt
把暫存區的修改回退到工作區(保留了更改內容)
$ git reset HEAD <file>
場景1:當你改亂了工作區某個文件的內容,想直接丟棄工作區的修改時,用命令git checkout -- file
。
場景2:當你不但改亂了工作區某個文件的內容,還添加到了暫存區時,想丟棄修改,分兩步,第一步用命令git reset HEAD <file>
,就回到了場景1,第二步按場景1操作。
場景3:已經提交了不合適的修改到版本庫時,想要撤銷本次提交,參考版本回退,不過前提是沒有推送到遠程庫。
刪除文件
提交刪除到暫存區
$ git rm test.txt
- 如果你用的
rm <file>
刪除文件,那就相當於只刪除了工作區的文件,如果想要恢復,直接用git checkout -- <file>
- 如果你用的是
git rm <file>
刪除文件,那就相當於不僅刪除了文件,而且還添加到了暫存區,需要先git reset HEAD <file>
,然後再git checkout -- <file>
- 如果你想徹底把版本庫的刪除掉,先
git rm <file>
,再git commit -m <message>
就ok了
遠程倉庫
本地Git倉庫和GitHub倉庫之間的傳輸是通過SSH加密的,所以,需要一點設置:
第1步:創建SSH Key。在用戶主目錄下,看看有沒有.ssh目錄,如果有,再看看這個目錄下有沒有id_rsa
和id_rsa.pub
這兩個文件,如果已經有了,可直接跳到下一步。如果沒有,打開Shell(Windows下打開Git Bash),創建SSH Key:
$ ssh-keygen -t rsa -C "[email protected]"
你需要把郵件地址換成你自己的郵件地址,然後一路回車,使用默認值即可,由於這個Key也不是用於軍事目的,所以也無需設置密碼。
如果一切順利的話,可以在用戶主目錄裏找到.ssh
目錄,裏面有id_rsa
和id_rsa.pub
兩個文件,這兩個就是SSH Key的祕鑰對,id_rsa
是私鑰,不能泄露出去,id_rsa.pub
是公鑰,可以放心地告訴任何人。
第2步:登陸GitHub,打開“Account settings”,“SSH Keys”頁面:
然後,點“Add SSH Key”,填上任意Title,在Key文本框裏粘貼id_rsa.pub
文件的內容
添加遠程庫
在Github上New repository後,可以選擇四種方式克隆新的倉庫或者關聯本地倉庫:
- 使用桌面版快速設置對應倉庫
- 使用命令行創建一個新的倉庫
- 通過命令行推送現有倉庫
- 從另一個倉庫導入
要關聯一個遠程庫,使用命令git remote add origin git@server-name:path/repo-name.git
;
關聯後,使用命令git push -u origin master
第一次推送master分支的所有內容;
此後,每次本地提交後,只要有必要,就可以使用命令git push origin master
推送最新修改;
分佈式版本系統的最大好處之一是在本地工作完全不需要考慮遠程庫的存在,也就是有沒有聯網都可以正常工作,而SVN在沒有聯網的時候是拒絕幹活的!當有網絡的時候,再把本地提交推送一下就完成了同步,真是太方便了!
關聯遠程倉庫,遠程庫的名字就是origin,這是Git默認的叫法
$ git remote add origin [email protected]:sunny2019/learngit.git
把本地庫的內容推送到遠程,用git push命令,實際上是把當前分支master推送到遠程。
由於遠程庫是空的,我們第一次推送master分支時,加上了-u參數,Git不但會把本地的master分支內容推送的遠程新的master分支,還會把本地的master分支和遠程的master分支關聯起來,在以後的推送或者拉取時就可以簡化命令。
$ git push -u origin master
把本地master分支的最新修改推送至GitHub
$ git push origin master
從遠程庫克隆
從遠程庫克隆gitskills倉庫(SSH)
git clone [email protected]:sunny2019/gitskills.git
從遠程庫克隆gitskills倉庫(HTTPS)
git clone https://github.com/sunny2019/gitskills.git
要克隆一個倉庫,首先必須知道倉庫的地址,然後使用git clone
命令克隆。
Git支持多種協議,包括https
,但通過ssh
支持的原生git
協議速度最快。
分支管理
創建與合併分支
創建+切換分支
$ git checkout -b <name>
創建分支
$ git branch <name>
切換分支
$ git checkout <name>
查看分支
$ git branch
合併某分支到當前分支
$ git merge <name>
刪除分支
$ git branch -d <name>
解決衝突
查看分支合併圖
$ git log --graph
$ git log --graph --pretty=oneline --abbrev-commit
當Git無法自動合併分支時,就必須首先解決衝突。解決衝突後,再提交,合併完成。
解決衝突就是把Git合併失敗的文件手動編輯爲我們希望的內容,再提交。
用git log --graph
命令可以看到分支合併圖。
分支管理策略
通常,合併分支時,如果可能,Git會用Fast forward
模式,但這種模式下,刪除分支後,會丟掉分支信息。
如果要強制禁用Fast forward
模式,Git就會在merge
時生成一個新的commit
,這樣,從分支歷史上就可以看出分支信息。
禁用Fast forward模式合併某分支到當前分支
$ git merge --no-ff -m "merge with no-ff" <name>
在實際開發中,我們應該按照幾個基本原則進行分支管理:
首先,master
分支應該是非常穩定的,也就是僅用來發布新版本,平時不能在上面幹活;
那在哪幹活呢?幹活都在dev
分支上,也就是說,dev
分支是不穩定的,到某個時候,比如1.0版本發佈時,再把dev
分支合併到master
上,在master
分支發佈1.0版本;
你和你的小夥伴們每個人都在dev
分支上幹活,每個人都有自己的分支,時不時地往dev
分支上合併就可以了。
所以,團隊合作的分支看起來就像這樣:
Git分支十分強大,在團隊開發中應該充分應用。
合併分支時,加上--no-ff
參數就可以用普通模式合併,合併後的歷史有分支,能看出來曾經做過合併,而fast forward
合併就看不出來曾經做過合併。
Bug 分支
儲存工作現場(一定先git add一下)
$ git stash
查看工作現場儲存列表
$ git stash list
恢復工作現場(不從儲存列表刪除)
$ git stash apply
刪除工作現場儲存列表的內容
$ git stash drop
恢復工作現場並刪除工作現場儲存列表的內容
$ git stash pop
恢復指定的stash
$ git stash apply stash@{0}
修復bug時,我們會通過創建新的bug分支進行修復,然後合併,最後刪除;
當手頭工作沒有完成時,先把工作現場git stash
一下,然後去修復bug,修復後,再git stash pop
,回到工作現場。
stash
之前必須要add
的。我的測試結果:如果在分支dev
中新增加了文件new,此文件是untrack
的狀態,此時如果不add
就直接stash
,回到master
中會發現在dev
中新增加的文件new跑到master
裏了,而且當你回到dev
分支後恢復現場,你的new文件反而不見了(至於爲什麼會這樣,大家可以當成untrack
的文件不會被git系統所管理,自然也不會被stash
,只會一直躺在那個文件裏)。所以我們只需要知道在分支中stash
之前一定要add
就可以了。
Feature 分支
強行刪除分支
$ git branch -D <name>
開發一個新feature,最好新建一個分支;
如果要丟棄一個沒有被合併過的分支,可以通過git branch -D <name>
強行刪除。
多人協作
查看遠程庫的信息
git remote
查看詳細的遠程庫信息
$ git remote -v
推送分支
$ git push origin <branch-name>
創建遠程origin的其他分支到本地並切換
$ git checkout -b <branch-name> origin/<branch-name>
抓取當前分支的最新提交
$ git pull
指定本地其他分支與遠程origin/其他分支的鏈接
$ git branch --set-upstream-to=origin/<branch-name> <branch-name>
因此,多人協作的工作模式通常是這樣:
首先,可以試圖用git push origin <branch-name>
推送自己的修改;
如果推送失敗,則因爲遠程分支比你的本地更新,需要先用git pull
試圖合併;
如果合併有衝突,則解決衝突,並在本地提交;
沒有衝突或者解決掉衝突後,再用git push origin <branch-name>
推送就能成功!
如果git pull
提示no tracking information
,則說明本地分支和遠程分支的鏈接關係沒有創建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>
。
這就是多人協作的工作模式,一旦熟悉了,就非常簡單。
小結
查看遠程庫信息,使用git remote -v
;
本地新建的分支如果不推送到遠程,對其他人就是不可見的;
從本地推送分支,使用git push origin <branch-name>
,如果推送失敗,先用git pull抓取遠程的新提交;
在本地創建和遠程分支對應的分支,使用git checkout -b <branch-name> origin/<branch-name>
,本地和遠程分支的名稱最好一致;
建立本地分支和遠程分支的關聯,使用git branch --set-upstream <branch-name> origin/<branch-name>
;
從遠程抓取分支,使用git pull
,如果有衝突,要先處理衝突。
Rebase 變基
整理分叉提交歷史
$ git rebase
只對尚未推送或分享給別人的本地修改執行變基操作清理歷史;從不對已推送至別處的提交執行變基操作。
rebase
操作可以把本地未push的分叉提交歷史整理成直線;
rebase
的目的是使得我們在查看歷史提交的變化時更容易,因爲分叉的提交需要三方對比。
標籤管理
創建標籤
給當前分支打上一個標籤
$ git tag <name>
查看所有標籤
$ git tag
給指定提交打上標籤
$ git tag <tagname> <commit_id>
查看標籤信息
$ git show <tagname>
創建帶有說明的標籤
$ git tag -a <tagname> -m "blablabla..." <commit_id>
注意:標籤總是和某個commit
掛鉤。如果這個commit
既出現在master
分支,又出現在dev
分支,那麼在這兩個分支上都可以看到這個標籤。
-
命令
git tag <tagname>
用於新建一個標籤,默認爲HEAD
,也可以指定一個commit id
; -
命令
git tag -a <tagname> -m "blablabla..."
可以指定標籤信息; -
命令
git tag
可以查看所有標籤。
操作標籤
刪除標籤
$ git tag -d <tagname>
推送指定標籤到遠程
$ git push origin <tagname>
推送全部尚未推送到遠程的本地標籤
$ git push origin --tags
刪除遠程的標籤
$ git push origin :refs/tags/<tagname>
命令git push origin <tagname>
可以推送一個本地標籤;
命令git push origin --tags
可以推送全部未推送過的本地標籤;
命令git tag -d <tagname>
可以刪除一個本地標籤;
命令git push origin :refs/tags/<tagname>
可以刪除一個遠程標籤。
使用 GitHub
-
在GitHub上,可以任意Fork開源倉庫;
-
自己擁有Fork後的倉庫的讀寫權限;
-
可以推送pull request給官方倉庫來貢獻代碼。
自定義 Git
讓Git顯示顏色
$ git config --global color.ui true
忽略特殊文件
強制添加到Git
$ git add -f <file-name>
檢查是哪條規則忽略了該文件
$ git check-ignore -v <file-name>
-
忽略某些文件時,需要編寫
.gitignore
; -
.gitignore
文件本身要放到版本庫裏,並且可以對.gitignore
做版本管理!
配置別名
st就表示status,co表示checkout,ci表示commit,br表示branch,unstage表示reset HEAD
$ git config --global alias.st status
$ git config --global alias.co checkout
$ git config --global alias.ci commit
$ git config --global alias.br branch
$ git config --global alias.unstage 'reset HEAD'
$ git config --global alias.last 'log -1'
$ git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
配置Git的時候,加上--global
是針對當前用戶起作用的,如果不加,那隻針對當前的倉庫起作用。
每個倉庫的Git配置文件地址:.git/config
當前用戶的Git配置文件地址:.gitconfig
配置別名也可以直接修改這個文件,如果改錯了,可以刪掉文件重新通過命令配置。
搭建 Git 服務器
假設你已經有sudo
權限的用戶賬號,下面,正式開始安裝。
第一步,安裝git:
$ sudo apt-get install git
第二步,創建一個git
用戶,用來運行git
服務:
$ sudo adduser git
第三步,創建證書登錄:
收集所有需要登錄的用戶的公鑰,就是他們自己的id_rsa.pub
文件,把所有公鑰導入到/home/git/.ssh/authorized_keys
文件裏,一行一個。
第四步,初始化Git倉庫:
先選定一個目錄作爲Git倉庫,假定是/srv/sample.git
,在/srv
目錄下輸入命令:
$ sudo git init --bare sample.git
Git就會創建一個裸倉庫,裸倉庫沒有工作區,因爲服務器上的Git倉庫純粹是爲了共享,所以不讓用戶直接登錄到服務器上去改工作區,並且服務器上的Git倉庫通常都以.git
結尾。然後,把owner改爲git
:
$ sudo chown -R git:git sample.git
第五步,禁用shell登錄:
出於安全考慮,第二步創建的git用戶不允許登錄shell,這可以通過編輯/etc/passwd
文件完成。找到類似下面的一行:
git:x:1001:1001:,,,:/home/git:/bin/bash
改爲:
git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell
這樣,git
用戶可以正常通過ssh使用git,但無法登錄shell,因爲我們爲git
用戶指定的git-shell
每次一登錄就自動退出。
第六步,克隆遠程倉庫:
現在,可以通過git clone
命令克隆遠程倉庫了,在各自的電腦上運行:
$ git clone git@server:/srv/sample.git
Cloning into 'sample'...
warning: You appear to have cloned an empty repository.
剩下的推送就簡單了。
小結
搭建Git服務器非常簡單,通常10分鐘即可完成;
要方便管理公鑰,用Gitosis
;
要像SVN那樣變態地控制權限,用Gitolite
。