## 目錄
[TOC]
## 參考資料
- [Git官網](http://git-scm.com/)
- [**Github 15分鐘學習Git**](https://try.github.io)
- [Git參考手冊](http://gitref.org/zh/index.html)
- [Git簡明手冊](http://www.mceiba.com/tool/git-cheat-sheet.html)
- [Git Magic](http://www-cs-students.stanford.edu/~blynn/gitmagic/intl/zh_cn/)
- [Git Community Book 中文版](http://gitbook.liuhui998.com/index.html)
- [Pro Git](http://git-scm.com/book/en/v2)
- [圖解Git](http://marklodato.github.io/visual-git-guide/index-zh-cn.html)
- [git-簡明指南](http://rogerdudler.github.io/git-guide/index.zh.html)
- [learnGitBranching 在線學習工具](http://pcottle.github.io/learnGitBranching/)
- [初級教程](http://rogerdudler.github.io/git-guide/index.zh.html)
- [廖雪峰的Git教程](http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000)
- [蔣鑫老師將帶你入github的大門](http://www.worldhello.net/gotgithub/)
- [git詳解](http://www.open-open.com/lib/view/open1328069609436.html)
## 配置
首先是配置帳號信息
> `ssh -T git@github.com` #登陸github
## 修改項目中的個人信息
`$ git config --global user.name "chaoy2010"`
`$ git config --global user.email chaoy2010@gmail.com`
#### config
>`git config --global user.name idyer` #設置提交用戶名
`git config --global user.email chaoy2010@gmail.com` #設置提交郵箱
`git config --list` #查看配置的信息
#### help
>`git help config` #獲取幫助信息
#### 配置密鑰
>`ssh-keygen -t rsa -C chaoy2010@gmail.com` #生成密鑰
`ssh -T git@github.com` #測試是否成功
## 多賬號ssh配置
#### 1.生成指定名字的密鑰
>`ssh-keygen -t rsa -C "郵箱地址" -f ~/.ssh/github_idyer`
會生成 `github_idyer` 和 `github_idyer.pub` 這兩個文件
#### 2.密鑰復制到托管平臺上
>`vim ~/.ssh/github_idyer.pub`
打開公鑰文件 `github_idyer.pub` ,并把內容復制至代碼托管平臺上
#### 3.修改config文件
> `vim ~/.ssh/config` #修改config文件,如果沒有創建 `config`
```
Host idyer.github.com
HostName github.com
User git
IdentityFile ~/.ssh/github_idyer
Host abc.github.com
HostName github.com
User git
IdentityFile ~/.ssh/github_abc
```
#### 4.測試
> `ssh -T git@idyer.github.com` # `@`后面跟上定義的Host
## 新建倉庫
### init
`git init` #初始化
### status
`git status` #獲取狀態,獲取更新的文件信息,包括新增的文件、修改過過得文件
### add
`git add file` #.或*代表全部添加
`git rm --cached <added_file_to_undo>` 在commit之前撤銷git add操作
`git reset head` 好像比上面`git rm --cached`更方便
### commit
`git commit -m "此次提交的說明(如增加了某個功能或者修改某個功能等)" -a` #
### push
`git push origin master`
##從現有倉庫克隆
`git clone git://github.com/JSLite/JSLite.js.git `
`git clone git://github.com/JSLite/JSLite.js.git mypro` #克隆到自定義文件夾
`git clone [user@]example.com:path/to/repo.git/` #SSH協議還有另一種寫法。
git clone支持多種協議,除了HTTP(s)以外,還支持SSH、Git、本地文件協議等,下面是一些例子。`$ git clone <版本庫的網址> <本地目錄名>`
```
$ 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/
```
#### push
`git push origin master`
`git push -f origin master` #強制推送
1. 縮寫 -f
2. 全寫--force
3. 注:強制推送文件沒有了哦
### pull
只能拉取 `origin` 里的一個url地址,這個fetch-url
默認為你添加的到 `origin`的第一個地址
`git pull origin master`
`git pull --all` #獲取遠程所有內容包括tag
`git pull origin next:master` #取回origin主機的next分支,與本地的master分支合并
`git pull origin next` #遠程分支是與當前分支合并
上面一條命令等同于下面兩條命令
`git fetch origin`
`git merge origin/next`
如果遠程主機刪除了某個分支,默認情況下,git pull 不會在拉取遠程分支的時候,刪除對應的本地分支。這是為了防止,由于其他人操作了遠程主機,導致git pull不知不覺刪除了本地分支。
但是,你可以改變這個行為,加上參數 -p 就會在本地刪除遠程已經刪除的分支。
```
$ git pull -p
# 等同于下面的命令
$ git fetch --prune origin
$ git fetch -p
```
### 更改pull
只需要更改config文件里,那三個url的順序即可,fetch-url會直接對應排行第一的那個utl連接。
## 本地
### add
`git add *` #跟蹤新文件
`git add -u [path]` #添加[指定路徑下]已跟蹤文件
### rm
`rm *&git rm *` #移除文件
`git rm -f *` #移除文件
`git rm --cached *` #取消跟蹤
`git mv file_from file_to` #重命名跟蹤文件
`git log` #查看提交記錄
### commit
`git commit` #提交更新
`git commit -m 'message'` #提交說明
`git commit -a` #跳過使用暫存區域,把所有已經跟蹤過的文件暫存起來一并提交
`git commit --amend` #修改最后一次提交
`git commit log` #查看所有提交,包括沒有push的commit
`git commit -m "#133"` #關聯issue 任意位置帶上`#` 符號加上issue號碼
`git commit -m "fix #133"` commit關閉issue
`git commit -m '概要描述'$'\n\n''1.詳細描述'$'\n''2.詳細描述'` #提交簡要描述和詳細描述
### reset
`git reset HEAD` *#取消已經暫存的文件
`git reset --mixed HEAD ` *#同上
`git reset --soft HEAD ` *#重置到指定狀態,不會修改索引區和工作樹
`git reset --hard HEAD ` *#重置到指定狀態,會修改索引區和工作樹
`git reset -- files` *#重置index區文件
那么如何跟隨著commit關閉一個issue呢? 在confirm merge的時候可以使用一下命令來關閉相關issue:
1. fixes #xxx
1. fixed #xxx
1. fix #xxx
1. closes #xxx
1. close #xxx
1. closed #xxx
### revert
`git revert HEAD` #撤銷前一次操作
`git revert HEAD~` #撤銷前前一次操作
`git revert commit` ##撤銷指定操作
### checkout
`git checkout -- file` #取消對文件的修改(從暫存區——覆蓋worktree file)
`git checkout branch|tag|commit -- file_name` #從倉庫取出file覆蓋當前分支
`git checkout HEAD~1 [文件]` #將會更新 working directory 去匹配某次 commit
`git checkout -- .` #從暫存區取出文件覆蓋工作區
`git checkout -b gh-pages 0c304c9` 這個表示 從當前分支 commit 哈希值為 0c304c9 的節點,分一個新的分支gh-pages出來,并切換到 gh-pages
### diff
`git diff file` #查看指定文件的差異
`git diff --stat` #查看簡單的diff結果
`git diff` #比較Worktree和Index之間的差異
`git diff --cached` #比較Index和HEAD之間的差異
`git diff HEAD` #比較Worktree和HEAD之間的差異
`git diff branch` #比較Worktree和branch之間的差異
`git diff branch1 branch2` #比較兩次分支之間的差異
`git diff commit commit` #比較兩次提交之間的差異
`$ git diff master..test` #上面這條命令只顯示兩個分支間的差異
`git diff master...test` #你想找出‘master’,‘test’的共有 父分支和'test'分支之間的差異,你用3個‘.'來取代前面的兩個'.'
### stash
`git stash` #將工作區現場(已跟蹤文件)儲藏起來,等以后恢復后繼續工作。
`git stash list` #查看保存的工作現場
`git stash apply` #恢復工作現場
`git stash drop` #刪除stash內容
`git stash pop` #恢復的同時直接刪除stash內容
`git stash apply stash@{0}` #恢復指定的工作現場,當你保存了不只一份工作現場時。
### merge
`git merge --squash test` ##合并壓縮,將test上的commit壓縮為一條
### cherry-pick
`git cherry-pick commit` #揀選合并,將commit合并到當前分支
`git cherry-pick -n commit` #揀選多個提交,合并完后可以繼續揀選下一個提交
### rebase
`git rebase master` #將master分之上超前的提交,變基到當前分支
`git rebase --onto master 169a6` #限制回滾范圍,rebase當前分支從169a6以后的提交
`git rebase --interactive` #交互模式,修改commit
`git rebase --continue` #處理完沖突繼續合并
`git rebase --skip` #跳過
`git rebase --abort` #取消合并
## 分支branch
### 刪除
`git push origin :branchName` #刪除遠程分支
`git push origin --delete new` #刪除遠程分支`new`
`git branch -d branchName` #刪除本地分支,強制刪除用-D
`git branch -d test` #刪除本地test分支
`git branch -D test` #強制刪除本地test分支
### 提交
`git push -u origin branchName` #提交分支到遠程origin主機中
### 拉取
`git fetch -p` #拉取遠程分支時,自動清理 遠程分支已刪除,本地還存在的對應同名分支。
### 分支合并
`git merge branchName` #合并分支 - 將分支branchName和當前所在分支合并
`git merge origin/master` #在本地分支上合并遠程分支。
`git rebase origin/master` #在本地分支上合并遠程分支。
`git merge test` #將test分支合并到當前分支
### 重命名
`git branch -m old new` #重命名分支
### 查看
`git branch` #列出本地分支
`git branch -r` #列出遠端分支
`git branch -a` #列出所有分支
`git branch -v` #查看各個分支最后一個提交對象的信息
`git branch --merge` #查看已經合并到當前分支的分支
`git branch --no-merge` #查看為合并到當前分支的分支
### 新建
`git branch test` #新建test分支
`git checkout -b newBrach origin/master` #取回遠程主機的更新以后,在它的基礎上創建一個新的分支
### 連接
`git branch --set-upstream dev origin/dev` #將本地dev分支與遠程dev分支之間建立鏈接
`git branch --set-upstream master origin/next` #手動建立追蹤關系
### 分支切換
`git checkout test` #切換到test分支
`git checkout -b test` #新建+切換到test分支
`git checkout -b test dev` #基于dev新建test分支,并切換
## 遠端
`git fetch <遠程主機名> <分支名>` #fetch取回所有分支(branch)的更新
`git fetch origin remotebranch[:localbranch]` # 從遠端拉去分支[到本地指定分支]
`git merge origin/branch` #合并遠端上指定分支
`git pull origin remotebranch:localbranch` # 拉去遠端分支到本地分支
`git push origin branch` #將當前分支,推送到遠端上指定分支
`git push origin localbranch:remotebranch` #推送本地指定分支,到遠端上指定分支
`git push origin :remotebranch` #刪除遠端指定分支
`git checkout -b [--track] test origin/dev` 基于遠端dev分支,新建本地test分支[同時設置跟蹤]
### 撤銷遠程記錄
`git reset --hard HEAD~1` #撤銷一條記錄
`git push -f origin HEAD:master` #同步到遠程倉庫
## 忽略文件
`echo node_modules/ >> .gitignore`
## 刪除文件
`git rm -rf node_modules/`
## 源remote
git是一個分布式代碼管理工具,所以可以支持多個倉庫,在git里,服務器上的倉庫在本地稱之為remote。
個人開發時,多源用的可能不多,但多源其實非常有用。
`git remote add origin1 git@github.com:yanhaijing/data.js.git`
`git remote` #顯示全部源
`git remote -v` #顯示全部源+詳細信息
`git remote rename origin1 origin2` #重命名
`git remote rm origin` #刪除
`git remote show origin` #查看指定源的全部信息
## 同步一個fork
[github教程](https://help.github.com/articles/syncing-a-fork/)
[在github上同步一個分支(fork)](http://www.miss77.net/549.html)
### 設置
在同步之前,需要創建一個遠程點指向上游倉庫(repo).如果你已經派生了一個原始倉庫,可以按照如下方法做。
```shell
$ git remote -v
# List the current remotes (列出當前遠程倉庫)
# origin https://github.com/user/repo.git (fetch)
# origin https://github.com/user/repo.git (push)
$ git remote add upstream https://github.com/otheruser/repo.git
# Set a new remote (設置一個新的遠程倉庫)
$ git remote -v
# Verify new remote (驗證新的原唱倉庫)
# origin https://github.com/user/repo.git (fetch)
# origin https://github.com/user/repo.git (push)
# upstream https://github.com/otheruser/repo.git (fetch)
# upstream https://github.com/otheruser/repo.git (push)
```
### 同步
同步上游倉庫到你的倉庫需要執行兩步:首先你需要從遠程拉去,之后你需要合并你希望的分支到你的本地副本分支。
從上游的存儲庫中提取分支以及各自的提交內容。 `master` 將被存儲在本地分支機構 `upstream/master`
```shell
git fetch upstream
# remote: Counting objects: 75, done.
# remote: Compressing objects: 100% (53/53), done.
# remote: Total 62 (delta 27), reused 44 (delta 9)
# Unpacking objects: 100% (62/62), done.
# From https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY
# * [new branch] master -> upstream/master
```
檢查你的 fork's 本地 `master` 分支
```shell
git checkout master
# Switched to branch 'master'
```
合并來自 `upstream/master` 的更改到本地 master 分支上。 這使你的前 fork's `master` 分支與上游資源庫同步,而不會丟失你本地修改。
```shell
git merge upstream/master
# Updating a422352..5fdff0f
# Fast-forward
# README | 9 -------
# README.md | 7 ++++++
# 2 files changed, 7 insertions(+), 9 deletions(-)
# delete mode 100644 README
# create mode 100644 README.md
```
## 標簽tag
當開發到一定階段時,給程序打標簽是非常棒的功能。
`git tag` #列出現有標簽
`git tag v0gi.1` #新建標簽
`git tag -a v0.1 -m 'my version 1.4'` #新建帶注釋標簽
`git checkout tagname` #切換到標簽
`git push origin v1.5` #推送分支到源上
`git push origin --tags` #一次性推送所有分支
`git tag -d v0.1` #刪除標簽
`git push origin :refs/tags/v0.1` #刪除遠程標簽
`git pull --all` #獲取遠程所有內容包括tag
`git --git-dir='<絕對地址>/.git' describe --tags HEAD` #查看本地版本信息
## 日志log
`git config format.pretty oneline` #顯示歷史記錄時,每個提交的信息只顯示一行
`git config color.ui true` #彩色的 git 輸出
`git log` #查看最近的提交日志
`git log --pretty=oneline` #單行顯示提交日志
`git log --graph --pretty=oneline --abbrev-commit`
`git log -num` #顯示第幾條log(倒數)
`git reflog` #查看所有分支的所有操作記錄
`git log --since=1.day` #一天內的提交;你可以給出各種時間格式,比如說具體的某一天(“2008-01-15”),或者是多久以前(“2 years 1 day 3 minutes ago”)。
`git log --pretty="%h - %s" --author=自己的名字` #查看自己的日志
`git log -p -2` #展開兩次更新顯示每次提交的內容差異
`git log --stat` #要快速瀏覽其他協作者提交的更新都作了哪些改動
`git log --pretty=format:"%h - %an, %ar : %s"`#定制要顯示的記錄格式
`git log --pretty=format:'%h : %s' --date-order --graph`#拓撲順序展示
`git log --pretty=format:'%h : %s - %ad' --date=short` #日期YYYY-MM-DD顯示
`git log <last tag> HEAD --pretty=format:%s` 只顯示commit
|選項 | 說明|
|----|----|
|%H |提交對象(commit)的完整哈希字串|
|%h |提交對象的簡短哈希字串|
|%T |樹對象(tree)的完整哈希字串|
|%t |樹對象的簡短哈希字串|
|%P |父對象(parent)的完整哈希字串|
|%p |父對象的簡短哈希字串|
|%an |作者(author)的名字|
|%ae |作者的電子郵件地址|
|%ad |作者修訂日期(可以用 -date= 選項定制格式)|
|%ar |作者修訂日期,按多久以前的方式顯示|
|%cn |提交者(committer)的名字|
|%ce |提交者的電子郵件地址|
|%cd |提交日期|
|%cr |提交日期,按多久以前的方式顯示|
|%s |提交說明|
## 重寫歷史
`git commit --amend` #改變最近一次提交
`git rebase -i HEAD~3` #修改最近三次的提交說明,或者其中任意一次
`git commit --amend` #保存好了,這些指示很明確地告訴了你該干什么
`git rebase --continue` 修改提交說明,退出編輯器。
```
pick f7f3f6d changed my name a bit
pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file
```
改成
```
pick 310154e updated README formatting and added blame
pick f7f3f6d changed my name a bit
```
## 查看某個文件歷史
`git log --pretty=oneline 文件名` #列出文件的所有改動歷史
`git show c178bf49` #某次的改動的修改記錄
`git log -p c178bf49 ` #某次的改動的修改記錄
`git blame 文件名` #顯示文件的每一行是在那個版本最后修改。
`git whatchanged 文件名` #顯示某個文件的每個版本提交信息:提交日期,提交人員,版本號,提交備注(沒有修改細節)
## 打造自己的git命令
```sh
git config --global alias.st status
git config --global alias.br branch
git config --global alias.co checkout
git config --global alias.ci commit
```
配置好后再輸入git命令的時候就不用再輸入一大段了,例如我們要查看狀態,只需:
```sh
git st
```
## 總結
`git help *` #獲取命令的幫助信息
`git status` #獲取當前的狀態,非常有用