Git
1. Git发展历程
1.1 版本控制系统
1.1.1 本地版本控制
本地计算机记录文件每次的更新,可以对每个版本做一个快照,或是记录补丁文件。适合个人用,如RCS。
1.1.2 集中式版本控制
所有的版本数据都保存在服务器上,协同开发者从服务器上同步更新或上传自己的修改。代表产品:SVN、CVS、VSS。
所有的版本数据都存在服务器上,用户的本地只有自己以前所同步的版本,如果不连网的话,用户就看不到历史版本,对带宽要求较高。而且,所有数据都保存在单一的服务器上,有很大的风险这个服务器会损坏,这样就会丢失所有的数据,当然可以定期备份。
1.1.3 分布式版本控制
所有版本信息仓库全部同步到本地的每个用户,如Git。可以在本地查看所有版本历史,可以离线在本地提交,只需在连网时push到相应的服务器或其他用户那里。由于每个用户那里保存的都是所有的版本数据,只要有一个用户的设备没有问题就可以恢复所有的数据,但这增加了本地存储空间的占用。
1.2 Git崛起
Git是免费、开源的,Linux之父开发。【李纳斯·托沃兹(Linus Benedic Torvalds)1969、芬兰】
优点:
- 适合分布式开发,强调个体。
- 公共服务器压力和数据量都不会太大。
- 速度快、灵活。
- 任意两个开发者之间可以很容易的解决冲突。
- 离线工作。
缺点:
- 模式上比SVN更加复杂。
- 不符合常规思维。
- 代码保密性差,一旦开发者把整个库克隆下来就可以完全公开所有代码和版本信息。
1.3 Git替代产品
- google:自研的Piper ,基于商业软件 Perforce。
- facebook:深度改造的 Mercurial 系统。
- SVN:Subversion
- VSS:Micorosoft Visual SourceSafe
- CVS:Concurrent Versions System
2. Git基本术语
2.1 workspace工作空间
本地编辑的地方,执行git add
操作后到暂存区。
2.2 Staging Area暂存区
用来提交前可以暂存工作区的变化,执行git commit
操作后到Repos本地库。
2.3 Repository本地仓库区
安全存放数据的位置,提交的所有版本的数据。其中HEAD
指向最新放入仓库的版本。
2.4 Remote远程仓库
一般指托管代码的服务器中的仓库。
2.5 Branch分支
主线分开的副本,方便团队分工。默认分支是master
。
2.6 Checkin,Checkout
- checkin: 将新版本复制回仓库,
- checkout: 从仓库中将文件的最新修订版本复制到工作空间
2.7 Head 头
头是一个象征性的参考,常用以指向当前分支。
3. Git操作
3.1 环境配置
3.1.1 查看配置
# 查看详细配置信息(由下面三部分构成)
$ git config -l
# 查看系统全局相关的Config
$ git config --system --list
# 查看当前用户相关的Config
$ git config --global --list
# 查看当前仓库相关的Config
$ git config --local --list
配置信息存储在本地gitconfig
文件中:
- 系统全局配置的
gitconfig
在/%GitHome%/etc/
目录下,–system 系统级 - 当前用户配置的
gitconfig
在/%userdir%/
目录下,–global 用户全局 - 当前仓库配置的
gitconfig
在/Repo/.gitconfig/
仓库目录下,–local当前仓库
注意:对于同一配置项,三个配置文件的优先级是 system < global < local。就近选择
通过命令的操作也会反应在配置文件中,即直接编辑.gitconfig
文件
3.1.2 常用配置
# 名称
$ git config --global user.name "zhangsan"
# 邮箱
$ git config --global user.email zhangsan@qq.com
## 名称和邮箱会体现在 用户目录的gitconfig文件中
# 添加配置项
$ git config [--local|--global|--system] key value
[--local|--global|--system] #可选的,对应本地仓库,用户全局,系统设置
key #配置项
value #对应的值
# 删除配置项
$ git config [--local|--global|--system] --unset key
#
user.name #用户名
user.email #邮箱
core.editor #文本编辑器
merge.tool #差异分析工具
core.paper "less -N" #配置显示方式
color.diff true #diff颜色配置
alias.co checkout #设置别名
git config user.name #获得用户名
git config core.filemode false #忽略修改权限的文件
了解完配置Config后,开始着手仓库Repo。
3.2 本地仓库
3.2.1 新建仓库
创建本地仓库的两种方式:
# 1.本地创建
$ git init
# 2.克隆
$ git clone [url]
3.2.2 删除仓库
1. 删除.git文件
2. $ find . -name ".git" | xargs rm -Rf
当登录一台机器后,怎么查看某用户的仓库数量和位置呢?
3.3 远程仓库
3.3.1 托管平台
- GitHub:https://github.com/
- Gitlab:https://about.gitlab.com/
- Bitbucket:https://bitbucket.org/
- 开源中国: http://git.oschina.net/
- Coding:https://coding.net/
- Gitee:https://gitee.com/
3.3.2 新建远程Git仓库
注册托管平台账号,新建空项目。
3.3.3 绑定到本地仓库
以开发环境的视角,分为“拉”和“推”。顾名思义:
-
“拉”:从远程仓库
git clone
克隆到本地。 -
“推”:从本地仓库上传同步到远程仓库。
# 拉
$ git clone http[s]://example.com/path/to/repo.git/ [<localRepoName>]
$ 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/
# 推
# 增加一个新的远程仓库,并命名
$ git remote add <name> <url>
# 上传本地指定分支到远程仓库
$ git push [<remote>] [<branch>]
# 强行推送当前分支到远程仓库,即使有冲突
$ git push [<remote>] --force
# 推送所有分支到远程仓库
$ git push [<remote>] --all
3.3.4 本地查看远程仓库
查看远程所有仓库:
# 简单查看远程---所有仓库(只能查看远程仓库的名字)
$ git remote
# 查看远程所有仓库
$ git remote -v
# 查看单个仓库的详细信息。
$ git remote show [remote]
新建远程仓库:
$ git remote add [name] [url]
删除远程仓库:
$ git remote rm [remote-name]
修改远程仓库:
$ git remote rename [oldname] [newname]
3.3.5 上传数据
# 上传数据,
$ git push [remote-name] [本地分支]:[远程分支]
# 推送本地master分支 到 origin远程主机
$ git push origin master
# 删除远程分支master
$ git push origin :master
# 等同于
$ git push origin --delete master
# 推送所有分支到远程仓库
$ git push [remote] --all
# 强行推送当前分支到远程仓库,即使有冲突
$ git push [remote] --force
3.3.6 拉取数据
# 获取远程仓库数据,不影响本地分支,可理解为拉取分支
$ git fetch [remote] [branch]
# 取回远程仓库的变化,并与本地分支合并,可理解为拉取分支的数据并合并
$ git pull [remote] [branch]
# 取回origin主机的next分支,与本地的master分支合并
$ git pull origin next:master
3.4 分支
3.4.1 查看分支
拿到Git仓库,首先查看它已有的分支:
# 列出所有本地分支
$ git branch
# 列出所有远程分支
$ git branch -r
# 列出所有本地分支和远程分支
$ git branch -a
3.4.2 新建分支
# 新建一个分支,但依然停留在当前分支
$ git branch [branch-name]
# 新建一个分支,并切换到该分支
$ git checkout -b [branch]
3.4.3 删除分支
# 删除分支(-D 强制删除)
$ git branch -d [branch-name]
# 删除远程分支
$ git push origin --delete [branch-name]
$ git branch -dr [remote/branch]
3.4.4 分支合并
# 合并指定分支到当前分支
$ git merge [branch]
3.4.5 远程分支
# 取回origin主机的next分支,与本地的master分支合并
$ git pull origin next:master
# 如果远程分支是与当前分支合并,则冒号后面的部分可以省略。
$ git pull origin next
# 实质上,这等同于先做git fetch,再做git merge。
$ git fetch origin
$ git merge origin/next
3.4.5 高级操作:
# 新建一个分支,指向指定commit
$ git branch [branch] [commit]
# 新建一个分支,与指定的远程分支建立追踪关系
$ git branch --track [branch] [remote-branch]
# 切换到指定分支,并更新工作区
$ git checkout [branch-name]
# 切换到上一个分支(name为-则为上一个分支)
$ git checkout -
# 建立追踪关系,在现有分支与指定的远程分支之间
$ git branch --set-upstream [branch] [remote-branch]
# 合并指定分支到当前分支
$ git merge [branch]
# 选择一个commit,合并进当前分支
$ git cherry-pick [commit]
3.5 文件操作
3.5.1 查看文件状态
# 查看指定文件状态
$ git status [filename]
# 查看所有文件状态
$ git status
四种状态:
- Untracked:未跟踪,还未加入到git库。通过
git add
变为 Staged状态。 - Unmodify:文件已入git库,还未发生修改。
- Modified:文件已入git库,且发生修改。通过
git add
变为 Staged状态。或git checkout
从库中取出文件, 覆盖当前修改,返回到unmodify状态 - Staged:暂存状态,执行
git commit
后将修改同步到git库中。
3.5.2 删除文件
# 直接从暂存区删除文件,工作区则不做出改变,即只从stage中删除,保留物理文件
$ git rm --cached <file>
# 不但从stage中删除,同时删除物理文件
$ git rm readme.txt
# 如果已经用add 命令把文件加入stage了,就先需要从stage中撤销
$ git reset HEAD <file>
# 移除所有未跟踪文件
# 一般会加上参数-df,-d表示包含目录,-f表示强制清除。
$ git clean [options]
3.5.3 对比操作
用git status
只能查看对哪些文件做了改动,如果要看改动了什么,可以用git diff [files]
#比较暂存区的文件与之前已经提交过的文件
$ git diff --cached
#比较repo与工作空间中的文件差异
$ git diff HEAD~n
3.5.4 Checkout
签出命令git checkout
是git最常用的命令之一,同时也是一个很危险的命令,因为这条命令会重写工作区workspace。
# 签出branch分支。
$ git checkout <branch>
# 汇总显示工作区、暂存区与HEAD的差异
$ git checkout
# 暂存区中文件来覆盖工作区中的文件。
$ git checkout --filename
# 这条命令最危险!相当于用暂存区的所有文件直接覆盖本地文件
$ git checkout -- . 或写作 git checkout .
3.5.5 忽略文件
主目录的建立.gitignore
文件
# 忽略所有 .txt结尾的文件
*.txt
# 但lib.txt除外
!lib.txt
# 忽略build/目录下的所有文件
build/
# 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt
doc/*.txt
3.6 提交操作
3.6.1 add
add: 将文件或目录添加到了index暂存区。
3.6.2 commit
commit:将暂存区的文件提交到本地仓库。
# 提交暂存区到仓库区
$ git commit -m [message]
# 提交暂存区的指定文件到仓库区
$ git commit [file1] [file2] ... -m [message]
# 提交工作区自上次commit之后的变化,直接到仓库区,跳过了add,对新文件无效
$ git commit -a
# 提交时显示所有diff信息
$ git commit -v
3.6.3 Stage(Index)撤销
git add
把更新提交到暂存区。这时如果想撤回本次操作,怎么做?
git status
的输出中提示我们可以通过git reset HEAD <file>..."
把Stage暂存区的更新移出到WorkSpace中。
3.6.4 仓库更新撤销
commit提交到git库后,如果想撤回本地操作,怎么做?
- 使用Head指针
- 使用commit id
在Git中,有一个HEAD指针指向当前分支中最新的提交。当前版本,我们使用
HEAD^
,那么再前一个版本可以使用HEAD^^
,如果想回退到更早的提交,可以使用HEAD~n
。(也就是,HEAD^
=HEAD~1
,HEAD^^
=HEAD~2
)
# 撤销到某某版本
$ git reset --hard HEAD^
$ git reset --hard HEAD~1
$ git reset --59cf9334cf957535cb328f22a1579b84db0911e5
# 把指定的提交的所有修改回滚,并同时生成一个新的提交。
$ git revert <commit-id>
3.7 其他
3.7.1 查看提交日志
# 以图形化的方式显示提交历史的关系
$ git log --graph
# 表示显示1行。
$ git log -1
# 查看所有分支日志
$ git reflog
# 搜索提交历史,根据关键词
$ git log -S [keyword]
# 显示某个commit之后的所有变动,每个commit占据一行
$ git log [tag] HEAD --pretty=format:%s
# 显示某个commit之后的所有变动,其"提交说明"必须符合搜索条件
$ git log [tag] HEAD --grep feature
# 显示某个文件的版本历史,包括文件改名
$ git log --follow [file]
$ git whatchanged [file]
3.7.2 查看指令记录
# 查看在bash下输入过的指令
$ history
3.7.3 代码统计
# 统计某人的代码提交量,包括增加,删除:
git log --author="$(git config --get user.name)" --pretty=tformat: --numstat | gawk '{ add += $1 ; subs += $2 ; loc += $1 - $2 } END { printf
"added lines: %s removed lines : %s total lines: %s\n",add,subs,loc }' -
# 仓库提交者排名前 5(如果看全部,去掉 head 管道即可):
git log --pretty='%aN' | sort | uniq -c | sort -k1 -n -r | head -n 5
# 仓库提交者(邮箱)排名前 5:这个统计可能不会太准,因为很多人有不同的邮箱,但会使用相同的名字
git log --pretty=format:%ae | gawk -- '{ ++c[$0]; } END { for(cc in c) printf "%5d %s\n",c[cc],cc; }' | sort -u -n -r | head -n 5
# 贡献者统计:
git log --pretty='%aN' | sort -u | wc -l
# 提交数统计:
git log --oneline | wc -l
# 显示所有提交过的用户,按提交次数排序
$ git shortlog -sn
# 显示指定文件是什么人在什么时间修改过
$ git blame [file]
# 显示今天你写了多少行代码
$ git diff --shortstat "@{0 day ago}"