## git 簡介
git是一個分布式的版本控制系統,一個git工程有三個工作區域:
* 工作目錄
* 暫存區域
* 本地倉庫
git add之后是到了暫存區域,git commit之后是到了本地倉庫。
## git-config全局配置
```bash
$ git config --global user.name "<user_name>"
$ git config --global user.email "<user_email>"
```
## git常用命令
* git add xxx 添加文件到暫存區
* git rm xxx 刪除文件,替代物理刪除文件,然后提交
* git commit -m "xxx" 提交更改到本地倉庫
* git push 推送更改到遠程分支
* git pull 從遠程分支拉取更改
* git reset HEAD xxx 如果某個文件被add了,但不想commit可以恢復
* git branch xxx 創建某個分支
* git checkout xxx 切換到某個分支
* git checkout -b xxx 新建某個分支并切換過去
* git branch -av 查看所有本地分支+遠程分支及對應版本號
* git merge --no-ff xxx 合并分支
* git branch -d/-D xxx 刪除本地分支(區別是是否被merged)
* git diff xxx 查看文件改動
* git log xxx 查看文件變動日志
##### git fetch 和 git pull
git fetch就是將遠程的分支拉取到本地遠程,具體有幾種寫法:
* git fetch origin
將所有的origin遠程分支都拉取到本地遠程,并且名字一一對應
* git fetch origin xxx
把xxx分支拉取到本地遠程,并且FETCH_HEAD指向它
* git fetch origin xxx:yyy
把xxx分支拉取到本地遠程和本地,并且將本地分支命名為yyy(這樣在本地就存在本地分支和本地遠程分支)
git branch查看本地分支,-r選項查看本地遠程分支,-a選項查看所有分支
```bash
$ git brand -r
origin/HEAD -> origin/master
origin/develop
origin/master
$ git brand -a
develop
* master
remotes/origin/HEAD -> origin/master
remotes/origin/develop
remotes/origin/master
```
* git pull == git fetch + git merge
git pull相當于從遠程分支fetch到本地遠程分支后,再merge到本地分支。
## git統計人員代碼貢獻量:
```bash
git log --format='%aN' | sort -u | while read name; do echo -en "$name\t"; git log --author="$name" --pretty=tformat: --numstat | awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "added lines: %s, removed lines: %s, total lines: %s\n", add, subs, loc }' -; done
```
## git撤銷操作
##### 撤銷本地工作目錄的更改
如果更改了本地文件還沒有git add,那么可以使用如下命令撤銷修改:
```bash
$ git checkout -- <file>
```
git checkout會把工作目錄里的文件修改到git之前記錄的某個狀態,默認情況下恢復到當前分支的最后一次commit。
##### 撤銷暫存區的修改(即撤銷git add)
如果已經通過git add將修改添加到暫存區,但還沒有commit,那么可以使用如下命令撤銷到git add之前的狀態:
```bash
$ git reset HEAD <file>
```
##### 撤銷本地倉庫的更改(即撤銷git commit)
如果在本地commit了一些內容但還沒有push,這時你想撤銷提交可以使用如下命令:
```bash
$ git reset <commit_id>
// 或者 git reset --hard <commit_id>
```
git reset會把代碼返回到指定的commit狀態,這樣就像是這些提交從來沒有發生過。默認情況下git reset會保留工作目錄,這樣提交是沒有了,但是修改的內容還在磁盤上,這是一種安全的選擇。如果希望一步就撤銷提交和修改的內容,就加上 --hard 選項。
##### 撤銷已push的更改(即撤銷git push)
如果已經執行了git push把內容發送到了遠程倉庫,如果現在想撤銷某一個commit,可以用如下命令:
```bash
$ git revert <commit_id>
```
git revert會產生一個新的commit,它和指定的commit是相反的(或者說是反轉的),任何從原先的commit里刪除的內容會在新的commit里被加回去,任何在原先的commit里加入的內容會在新的commit里被刪除。這是git最安全、最基本的撤銷場景,因為它并不會改變歷史,所以你現在可以git push新的“反轉”commit來抵消你錯誤提交的commit。
## git flow分支模型

主要分支:
* master分支
>這個分支是最近發布到生產環境的代碼,這個分支只能從其他分支合并,不能在這個分支直接修改。
* develop分支
>這個分支是我們的主開發分支,包含所有要發布到下一個release的代碼,這個主要合并其他分支,比如feature分支。
輔助分支:
* feature分支(分支名:feature/*)
>這個分支主要是用來開發一個新的功能,一旦開發完成,我們合并回develop分支并進入下一個release。
* release分支(分支名:release-*)
>當你需要發布一個新release的時候,我們基于develop分支創建一個release分支,測試完成后,我們將release分支合并到master和develop分支。
* hotfix分支(分支名:hotfix-*)
>當我們在production發現新的bug時,我們需要創建一個hotfix,完成hotfix后,我們合并回master和develop分支。
### git flow代碼示例
##### 創建develop分支(也可以使用gitlab在遠程創建,然后將develop分支clone到本地)
```bash
$ git branch develop master
$ git push -u origin develop
```
##### 開始新的feature分支
```bash
$ git checkout -b feature/some-feature develop
$ git push -u origin feature/some-feature
# 做一些改動
$ git status
$ git add
$ git commit
$ git push
```
##### 完成feature
```bash
$ git checkout develop
$ git pull
$ git merge --no-ff feature/some-feature
$ git push
# 刪除本地分支
$ git branch -d feature/some-feature
# 刪除遠程分支
$ git push origin --delete feature/some-feature
```
##### 開始release
```bash
$ git checkout -b release-1.0 develop
$ git push -u origin release-1.0
# 如果有改動
$ git status
$ git add
$ git commit
$ git push
```
##### 完成release
```bash
# 合并到master
$ git checkout master
$ git pull
$ git merge --no-ff release-1.0
$ git push
# 合并到develop
$ git checkout develop
$ git pull
$ git merge --no-ff release-1.0
$ git push
# 刪除本地分支
$ git branch -d release-1.0
# 刪除遠程分支
$ git push origin --delete release-1.0
# 打標簽
$ git tag -a v1.0 master -m "version 1.0"
# 推送本地tag到遠程
$ git push origin v1.0
# 如果要推送本地所有的tag使用--tags參數
$ git push origin --tags
```
##### 開始hotfix
```bash
$ git checkout master
$ git pull
$ git checkout -b hotfix-1.1 master
# fix bug
$ git status
$ git add
$ git commit
```
##### 完成hotfix
```bash
# 合并到master
$ git checkout master
$ git pull
$ git merge --no-ff hotfix-1.1
$ git push
# 合并到develop
$ git checkout develop
$ git pull
$ git merge --no-ff hotfix-1.1
$ git push
$ git branch -d hotfix-1.1
$ git tag -a v1.1 master -m "version 1.1"
$ git push origin --tags
```
### git 忽略文件提交 .gitignore 文件說明
* 從未提交過的文件可以用.gitignore
> 也就是添加之后從來沒有提交(commit)過的文件,可以使用.gitignore忽略該文件
* 已經推送(push)過的文件,想從git遠程庫中刪除,并在以后的提交中忽略,但是卻還想在本地保留這個文件
> 執行命令:git rm --cached Xml/config.xml
* 已經推送(push)過的文件,想在以后的提交時忽略此文件,即使本地已經修改過,而且不刪除git遠程庫中相應文件
> 執行命令 git update-index --assume-unchanged Xml/config.xml
* 后面的 Xml/config.xml 是要忽略的文件的路徑。如果要忽略一個目錄,打開 git bash,cd到 目標目錄下,執行:
> git update-index --assume-unchanged $(git ls-files | tr '\n' ' ')
* gitignore 配置
> https://github.com/github/gitignore
比如有一個配置文件 jdbc.properties 記錄數據庫的鏈接信息,每個人的鏈接信息肯定不一樣,但是又要提供一個標準的模板,用來告知如何填寫鏈接信息,那么就需要在git遠程庫上有一個標準配置文件,然后每個人根據自己的具體情況,修改一份鏈接信息自用,而且不會將該配置文件提交到庫!