本文是6月份在公司的一次git培训文档
一. 关于Git
Git: Linus 的第二个伟大作品, 是Linus用C实现的一个分布式版本控制工具
集中式: 如SVN
分布式: 如Git
优势:
- 去中心化
- 本地提交
- 分支策略
概念
- Local Structure
- Workspace 工作区
- Index/Stage 索引区
- Local Repo 仓库
- Objects
- commit 提交
- tree 目录树
- blob 文件
- tag 里程碑
- References
- branch 分支
- remote 远程
- HEAD 头指针
- Actions
- status
- add
- commit
- checkout
- reset
- diff
- log
- pull
- push
- blame
- …
二. 理解Git
What seems complex from a distance is often quite simple when you look closely enough
1. 本地仓库结构
-
工作区(workspace):本地仓库里除了
.git/
以外的文件 -
版本库(Repository):
.git/
里的所有文件 -
暂存区(stage or index)一个包含文件索引的目录树,
.git/index
(二进制文件)
2. 对象和引用的关系
- git对象:
.git/objects/
git 对象分为- commit(提交)
- tree(目录)
- blob(文件)
- tag(里程碑)
三. 使用Git
1. 本地操作
-
git add
git add 默认只把工作区修改和新增的文件加入index,并不会把在工作区的删除加入index。
-
git rm <path>
在工作区和index区删除该path文件 -
git add -u <path>
将修改,删除加入index, 但是不包括新增 -
git add -A <path>
将修改,新增,删除 都加入index -
git add -p
交互式地询问是否把修改片段添加到index,按照修改片段来区分,不是按照修改文件。
-
-
git commit
-
-m
添加内联说明消息 -
--amend -m "..."
修改最新的一个提交的说明, commit号会被修改, 但是父提交不会改变 -
-a
对工作区和index区修改和删除文件进行提交(对未入版本库的文件不起作用),跳过git add 不赞成使用
-
-
git reset
git reset 的主要作用有2个:
1)用当前版本库的文件替换index区或者工作区
2)用指定的历史提交内容,替换版本库,index区,工作区
-
git reset [commit] --<paths>
带有文件名, 用该commit(默认HEAD)的该文件替换当前index中的文件,通常作为git add操作的回滚 [repository->index] -
git reset [方式] [commit]
,有以下几种方式,方式默认是–mixed:-
–soft:只把当前分支指向改为commit(默认HEAD), 一个用例是合并本地多步提交 [commit -> repository]:
git reset --soft HEAD^^
工作区和index都没改变git commit -m "这个动作合并了3个提交为一个"
因为index内容没被reset,现在直接commit即实现了修改log(reset),但是不改内容的目的
-
–mixed:除了实现soft,还把index区替换为commit指向的目录树 [commit -> repository and index]
-
–hard:除了实现mixed,还把工作区替换为commit指向的目录树的内容一致 [commit -> repository, index, work] 注意index的新文件会被去掉,work的新文件会保留
-
-
回滚到上次HEAD的提交:
git reset --hard HEAD@{1}
-
-
git checkout
-
git checkout [commit] -- <paths>
带有path,不会改变HEAD内容。当-
省略 commit: 用index的paths文件替换工作区相应文件 [index->work]
-
带有 commit:用版本库中的paths文件替换index和工作区相应文件 [repository->index and work] 注意index和工作区的新文件不会被更改
-
-
-
git diff
-
git diff
工作区和index比较 -
git diff HEAD
工作区和当前分支版本库比较 -
git diff --cached
git diff --staged
index和版本库比较 -
git diff $start_commit..$end_commit -- path/to/file
2个提交之间diff, 文件可选, 注意文件路径前有空格
-
2. 回滚
git reflog --all
HEAD 变化记录git reset --hard HEAD@{1}
回滚到上一次HEAD的指向git push -f
参数 -f 将会强制(force)把本地老代码推送到远端, 以覆盖新代码-
回滚后为出现某些机器提交号不一致?
对于force push后的版本库, 如果另外一台机器代码存在force去掉的代码, 此时此机器pull 代码后, 废旧代码任然可能存在, 这容易造成force更新后, 各个机器commit不一致的情况(所谓的水印不一致)
解决方案, 其他机器执行
git reset --hard origin/master
四. 雕虫小技
Learn more, Do less
git clean -fd
删除本地非版本库, 非ignore的文件git cherry-pick 提交号
重放该提交git revert 提交号
创建一个新的commit, 用以undo 指定的提交, 如果能回滚(即指定提交后, 没有其他提交修改这部分代码), 会直接到commit步骤, 如果不能回滚, 将会发送冲突-
git log <since>..<until>
查看2个引用之间的提交,常用于比较当前分支和远程该分支的提交差异, 输出可以理解为后面一个减去前面一个(后面一个比前面一个多的 commit)-
看看是否有提交没有push:
git log origin/分支名..HEAD
-
看看后面一个分支比前一个分支多的commit:
git log origin/分支A..分支B
-
看看是否本地不是最新(应该在remote updaate之后):
git log HEAD..origin/分支名
-
看看2次HEAD变更之间的所有提交log
git log HEAD@{1}..HEAD@{0}
注意顺序,调换2个head的位置,无输出
-
git commit --amend -m "..."
修改最新的一个提交的说明, commit号会被修改, 但是父提交不会改变- 使用reset –soft 进行合并提交记录
- git bisect 二分查找法排查bug
五. 其他主题
To be continue
- git config
- git stash
- gitignore
- git hooks
- git tag
- git flow
- git subtree
- git commit 规范
- git 补丁
- git rebase
六. 抛砖引玉
ToDo