Eli's Blog

1. 基本概念

1.1 git特点

1) 直接存储文件快照(特定时间点的完整文件),而非存储差异。
2) 几乎所有操作都在本地执行,只有同步版本库才需要联网。
3) 天然的数据完整性校验(SHA-1, 40bits).

1.2 git文件变更操作

文件变更的三个阶段:

  • 修改(modified)
  • 暂存(staged): 已加入下次提交列表)
  • 提交(committed): 保存到版本数据目录

三个阶段数据存放区域:

  • 工作目录(workspace)
  • 暂存索引文件(.git/index)
  • 本地数据目录(.git/objects)

Git Data Transport Commands (http://osteele.com)

2. 初始化设置

2.1 配置用户

1
2
3
4
5
6
git config --global user.name 'eli.he'
git config --global user.email 'eli.he@live.cn'

git config --global core.autocrlf false

git config --list

2.2 密钥设置

1) 生成密钥

1
ssh-keygen -t rsa -C 'eli.he@live.cn'

2) 上传公钥 id_rsa.pub 至SSH keys管理

1
cat ~/.ssh/id_rsa.pub

3) 测试连通性

1
ssh -T git@github.com

2.3 设置忽略文件

  • 全局(.gitignore)
  • 个人(.git/info/exclude)

3. 版本库

3.1 新建版本库

1
2
3
4
5
mkdir test
cd test
git init

git remote add origin git@github.com:elihe2011/test.git

3.2 克隆版本库

1
2
3
4
5
# 默认远程仓库名为origin
git clone https://github.com/elihe2011/abc.git

# 指定远程仓库名为git_prj
git clone -o git_prj https://github.com/elihe2011/abc.git

3.3 查看远程版本库

1
2
git remote -v
git remote show origin

3.4 获取远程版本,但不合并

1
2
git fetch origin master
git fetch ~/github/new_test master

3.5 获取远程版本,并合并

1
2
git pull origin master
git pull ~/github/new_test master

3.6 代码修改提交

1
2
3
4
5
6
7
git add .
git commit -m 'add a.txt' a.txt
git commit -m 'add all'

git commit -am 'commit tracked files'

git commit -m --amend --no-edit # 使用新的commit替代原有的,保持commit描述不变

3.7 推送至远程库

1
2
3
4
5
git push -u origin master 

# -u, --set-upstream 第一次push的时候需要,自动添加如下配置
branch.master.remote=origin
branch.master.merge=refs/heads/master

4. 文件操作

4.1 检查修改

1
2
3
4
5
git diff hello.py    # workspace, staged

git diff --cached # staged, local-repository

git diff master origin/master # local-repo remote-repo

4.2 撤销操作

4.2.1 checkout

workspace和staged撤销修改

1
2
3
4
5
6
# 撤销本次修改,commit前均可操作
git checkout hello.py

# 使用特定commit的文件,替换staged和workspace下的文件
git checkout ad12sa1 hello.py
cat .git/HEAD # defd8bb....

4.2.2 reset

不可恢复的撤销 (谨慎操作)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# staged区回滚,git add的反操作
git reset [<files>]

# staged区和workspace回滚,回到最近一次提交
git reset [<files>] --hard

# staged区回滚到指定commit,之前的提交全部删除
git reset <commit>

# workspace区也回滚
git reset <commit> --hard

# 作用于staged区
git reset --mixed HEAD
  • 实例:
    1
    2
    3
    4
    5
    git reset HEAD -- a.txt
    git reset a.txt

    # HEAD^表示上个版本,HEAD^^上上个版本,HEAD~N往上N个版本
    git reset HEAD^^ -- a.txt

4.2.3 revert 仅反转提交

撤销已提交的快照,但不从项目中删除这个commit,而是新生成一个commit

  • 实例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    touch 1.txt 2.txt 3.txt
    git add .
    git commit -m 'add 1.txt' 1.txt
    git commit -m 'add 2.txt' 2.txt
    git commit -m 'add 3.txt' 3.txt

    git log --oneline -5
    git revert cc79f5a # revert 2.txt
    ls -l [1-3].txt # 1.txt, 3.txt

reset和revert的区别:

reset: 被设计用来撤销本地的修改,它会完整地删除一个change set。

revert: 被设计用来安全地撤销一个公共commit,会保留最初的change set,通过新建一个commit来撤销

4.2.4 撤销操作场景

1) 已修改,未暂存

1
2
git checkout .
git reset --hard

2) 已暂存,未提交

1
2
3
4
5
6
git reset
git checkout .

or

git reset --hard

3) 已提交,未推送

1
git reset --hard origin/master

4) 已推送

1
2
git reset --hard HEAD^
git push -f origin master

4.2.5 撤销命令说明

命令 操作区域
checkout staged -> workspace
reset committed -> staged
reset –hard committed -> staged -> workspace

4.3 删除文件

4.3.1 删除已traced文件

1
2
3
4
5
6
7
8
9
10
11
# 删除workspace中的文件,如果已在staged中,报错
git rm a.txt

# 同时删除workspace & staged文件,保留committed文件
git rm -f a.txt

# 同时删除staged & committed文件,保留workspace文件
git rm --cached a.txt

# 清理已被删除的所有文件
git rm $(git ls-files --deleted)

4.3.2 删除未traced的文件

1
2
git clean -f
git clean -df

5. 标签

5.1 创建标签

1
2
3
4
5
6
7
8
# 为当前分支最近一次提交创建标签
git tag 1.0

# 标签 develop/1.1
git tag develop_1.1 develop

# 为某个历史提交创建标签
git tag 1.2 66cbbb4

5.2 查询标签

1
2
3
git tag
git tag -l '1.2.*'
git show 1.1

5.3 检出标签

1
git checkout 1.0

5.4 按标签创建分支

1
2
3
git branch test 1.1

git checkout -b develop 1.2

5.5 删除标签

1
git tag -d 1.1

6. 日志

6.1 查询日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
git log
git log -5
git log stat # 详细日志
git log -p # 更详细日志

git log --author='eli'

git log --grep='modify' # 过滤提交描述

git log --graph
git log --graph --decorate --oneline

git log --oneline

git log ada6cb2..62a89cf

git log --merges
git log --no-merges # 过滤merge提交

git log --since='2017-11-20' --until='2017-12-01'

git log --pretty=format:"%cn committed %h on %cd"

# 格式化参数
%cn committer name
%h commit hash
%cd commit date
%s short message

git log --pretty="%h - %s" --author='eli' --since='2017-11-27 00:00:00' --before='2017-11-27 11:59:59'

6.2 git reflog 所有分支的日志

1
git reflog --relative-date

6.3 git shortlog

1
git shortlog

7. 分支

7.1 创建分支

1
2
3
4
5
6
7
8
# 从当前分支创建新分支,但不切换
git branch develop

# 从当前分支创建新分支,并切换
git checkout -b develop

# 从develop分支创建新分支
git checkout -b test develop

7.2 删除分支

1
2
3
4
5
# 删除已merge的分支
git branch -d develop

# 强制删除分支,不管是否已merge
git branch -D develop

7.3 更改分支名

1
git branch -m dev

7.4 切换分支

本质上是更新HEAD指向给定的branch或commit

1
2
3
4
5
6
7
8
git checkout develop

git checkout -b test

# 产生detached HEAD状态,detached意味着当前所有修改和项目发展的其他部分完全脱离,无法被merge
git checkout <commit>

git checkout <tag>

7.5 合并分支

1
2
3
4
5
# 自动指定merge算法
git merge <branch>

# 强制fast-forword merge算法
git merge --on-ff <branch>

7.6 rebase 合并分支(重定义分支起点)

1
git rebase <base>   # base: commit, tag, branch, HEAD~N
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
git checkout -b develop
touch echo.py
git add echo.py
git commit -m 'add echo.py on develop branch'

git checkout master
touch print.py
git add print.py
git commit -m 'add print.py on master branch'

git checkout develop
git rebase master # 将整个develop分支的commit放在master分支之后,不会创建merge commit,但会为develop分支的每个commit创建一个新的commit

git checkout master
git merge develop # 只产生merge commit,分支commit不合入

7.7 merge和rebase的区别:

  • merge: 产生一个merge commit,不会合入分支的commit

  • rebase: 不产生merge commit,但合入分支的commit

  • 示意图

  • git pull

    git pull: 按merge方式合并

    git pull –rebase: 按rebase方式合并

  • merge未产生merge commit的原因:只有在存在冲突,解决完冲突后才自动产生一个merge commit

  • git merge

    git merge: 被合并之前的commit全部抹除,只保留一个解决冲突的merge commit

    git merge –on-ff: 在没有冲突下,也自动产生一个merge commit

8. 远程分支操作

8.1 查询远程分支

1
git ls-remote

8.2 跟踪远程分支

1
2
3
git checkout -b daily origin/daily

git checkout --track origin/daily # 本地和远程的分支名保持一致

8.3 添加本地分支与远程分支的关联关系(–set-upstream-to=)

1
git branch -u origin/daily

8.4 查询当前已跟踪的分支

1
git branch -vv

8.5 删除远程分支

1
git push origin --delete daily

8.6 远程仓库被删除,导致无法pull

1
git remote prune origin

9. 导出版本库

1
git archive --format=zip HEAD > `date +%s`.zip

10. 撤销操作详细说明

10.1 reset

reset将一个分支的末端指向另一个提交,并移除当前分支的一些提交

1
2
git checkout hotfix
git reset HEAD~2

hotfix分支末端的两个提交变成悬挂提交,下次Git执行垃圾回收时,这两个提交会被删除。

撤销缓存区和工作目录:

  • –soft 缓存区和工作目录均不修改
  • –mixed 默认项,缓存区同步到你指定的提交,但工作目录不受影响
  • –hard 缓存区和工作目录均同步到你指定的提交

使用前提:你的更改未分享给别人,git reset是撤销这些更改的简单方法

10.2 revert

revert撤销一个提交同时会创建一个新的提交。比reset安全,且不会重写提交历史

1
2
git checkout hotfix
git revert HEAD~2

10.3 总结

git revert可以用在公共分支

git reset应该用在私有分支上

11. 配置项说明

11.1 区分大小写

1
git config core.ignorecase false