Git
概念
Git 中有 4 个区域:
- 工作区( Working Area )
- 暂存区( Stage )
- 本地仓库( Local Repository )
- 远程仓库( Remote Repository )
文件有 5 种状态:
未修改( Origin )
已修改( Modified )
已暂存( Staged )
已提交( Committed )
已推送( Pushed )
文件刚开始处于工作区,编辑文件后可以使用
git diff
查看文件进行了哪些修改add 命令可以添加到暂存区,可以使用
git diff --cached
查看文件在暂存区和本地仓库之间的区别commit 提交到本地仓库,可以使用
git diff master origin/master
查看本地仓库分支和远程仓库分支之间的区别
注意,Git 保存的不是文件差异或者变化量,而只是一系列文件快照,并使用一个 commit 来指向它们。push 将本地仓库的代码提交到远程仓库
索引
分支
命令
status
1 | $ git status -s # 短版status |
diff(比较文件)
1 | git diff --cached # ,同--staged |
log(显示提交历史)
对比分支差异
列出最近两次提交引入的更改(-p 相当于 diff 命令)
1 | $ git log -p -2 |
其他选项
1 | $ git log --stat # 列出每次提交的state(相当于加state命令) |
打印出炫酷的效果:
1 | $ git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative |
ignore
.gitignore 文件中的规则匹配的文件会被 git 忽略,但是文件事先要从索引中删除。
config
1 | $ git config --global credential.helper cache # 设置凭证缓存,以后就不用每次都输入密码了,但默认只保存15分钟 |
add(建立索引)
1 | git add . |
unmodifying(已修改->未修改)
1 | git checkout . |
commit(提交)
1 | $ git commit -a # 自动add并提交追踪过的所有文件 |
unstage(撤销 add,已暂存->已修改)
1 | $ git reset HEAD <file>... # 撤销上一次的add |
tag
1 | $ git tag # 显示所有标签 |
aliase
1 | $ git config --global alias.co checkout |
以后就可以使用 git ci 来 commit 了
1 | $ git config --global alias.visual '!gitk' |
为自己写的工具设置别名
push
1 | $ git push origin serverfix:awesomebranch # 将serverfix代表的分支推到远程origin的awesomebranch分支上 |
remote
1 | $ git remote # 显示远程服务器名,默认赋名origin |
branch
1 | $ git branch -v # 显示每个branch的最后一个commit |
checkout
1 | $ git checkout -b [branch] [remotename]/[branch] # 在本地创建一个新分支,与远程的一个分支同步 |
rebase(衍合)和 merge(合并)
- 实现方式:rebase 和 merge 都是用来在推送之前整合提交历史的,但是实现的方式却不同,rebase 先找出两个分支的公共祖先,然后将一个分支的从该节点之后的所有提交都当成补丁应用到另一个分支上;merge 同样是先找到分支的公共祖先,然后对两个分支的最新提交进行合并???,将合并中修改的内容生成一个新的 commit。
- 冲突解决:rebase 和 merge 在实施过程中都有可能会出现冲突的情况,merge 遇见冲突后会直接停止,等待手动解决冲突并重新提交 commit 后,才能再次 merge;而 rebase 遇见冲突后会暂停当前操作,开发者可以选择手动解决冲突、add 更新索引,然后 git rebase –continue 继续,或者 –skip 跳过(注意此操作中当前分支的修改会直接覆盖目标分支的冲突部分),亦或者 –abort 直接停止该次 rebase 操作。
- pull 命令其实相当于 fetch+merge,可以通过在后面加上
--rebase
选项来指定为 rebase 操作,或者先 fetch,之后再考虑使用 merge 还是 rebase。 - 不要 rebase 已经公开的提交对象,因为它会舍弃当前分支已经提交的 commit,对别人来说就像该分支被回滚了一样,如果 pull 了可能就会出问题。
https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging#Basic-Merge-Conflicts - 当有修改未 commit 时,不能进行 rebase 操作,此时可以考虑先用 git stash 命令暂存;但是 merge 可能会直接将未 commit 的内容覆盖掉。
1
2
3
4
5
6$ git rebase b # 嫁接过去,将当前分支里的补丁应用到目标分支的最后一个提交对象上,也就是在目标分支的最后一个commit的基础上重演一遍修改,最后将当前分支的???指过去
$ git rebase --onto master server client # 将分支server上的另一分支client衍合到master上
$ git rebase master server # 将server分支衍合到master中来
$ git rebase -i b # 显示详细信息,包括各commit会被连接到目标分支的哪个commit后面,并且可以指定命令(策略pick、reword、edit、squash、fixup、exec)???????,默认为pick
$ git merge b # 将目标分支合并进来
$ git merge --ff-only # ff的意思是fast-forward,这种情况下要么当前分支已经是最新的了、要么合并是可以fast-forward的(只移动分支指针),默认情况下是--no-ff,也就是普通的合并
stash
1 | $ git stash apply # 使用最近一次的stash记录来还原当前分支 |
reset
统计代码量
统计每个人的代码量:
1 | 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 |
统计某个人某段时间内的代码量:
1 | git log --since='2019-01-15' --until='2019-12-31' --format='%aN' | sort -u | |
回滚
Git 支持对本地代码库或远程代码库回滚。
参考:git 远程分支回滚
工作流
首先 master 分支即发布的版本,在此上分出一个 develop(huang)版本,每次发布任务时,在 develop 的基础上分出 liu、du、zhou、shen,完成各自的任务,完成后合并到 develop 上。
若 master 上出 bug 了就直接分出一个 hotfix 分支,修复后马上合并到 master 和 develop 上。
开发完成后(即 liu、du、zhou、shen 等的分支都已合并进 develop)在 develop 上分出一个 release,进行测试,最后合并到 master 上。