Git的作用
- 协同工作。业界绝大多数公司都是基于Git进行代码管理,因此Git是一个程序员的必备技能
- 开源社区。目前绝大多数的开源项目都是基于Git维护的,参与这些项目的开发都需要使用Git。
Git是什么?
版本控制
版本控制一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统
Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.
为什么需要版本控制?
- 更好的关注变更,了解到每个版本的改动是什么,方便对改动的代码进行检查,预防事故发生;
- 也能够随时切换到不同的版本,回滚误删误改的问题代码;
版本控制工具
| 版本控制类型 | 代表性工具 | 解决的问题 | 基本原理 | 优缺点 |
|---|---|---|---|---|
| 本地版本控制 | RCS | 本地代码的版本控制 | 本地保存所有变更的补丁集,可以理解成就是所有的Diff,通过这些补丁,我们可以计算出每个版本的实际的文件内容 | 只能本地使用,无法团队协作,使用场景有限 |
| 集中式版本控制 | SVN | 提供一个远端服务器来维护代码版本。本地不保存代码版本,解决多人协作问题 | 提供一个远端服务来保存文件,所有用户的提交都提交到该服务器中,增量保存每次提交的Diff,如果提交的增量中和远端现存的文件存在冲突,则需要本地提前解决冲突 | 学习简单,支持二进制文件,对大文件支持更友好;本地不存储版本管理的概念,所有提交都只能联上服务器后才可以提交,分支上的支持不够好,对于大型项目团队合作比较困难,用户本地不保存所有版本的代码,如果服务端故障容易导致历史版本的丢失 |
| 分布式版本控制 | Git | 每个仓库都能记录版本历史,解决只有一个服务器保存版本的问题 | 每个库都存有完整的提交历史,可以直接在本地进行代码提交;每次提交记录的都是完整的文件快照,而不是记录增量;通过Push等操作来完成和远端代码的同步 | 分布式开发,每个库都是完整的提交历史,支持本地提交,强调个体;分支管理功能强大,方便团队合作,多人协同开发;校验和机制保证完整性,一般只添加数据,很少执行别除操作,不容易导致代码丢失。 相对SVN更复杂,学习成本更高;对于大文件的支持不是特别好(git-lfs工具可以弥补这个功能) |
Git基本命令
Git介绍
git init
mkdir dirname
cd dirname
git init
在执行完成 git init命令后,Git 仓库会生成一个 .git 目录,默认为master分支。该目录包含了资源的所有元数据,其他的项目目录保持不变。git init其他参数:
--initial-branch:初始化的分支--bare:创建一个裸仓库(纯Git目录,没有工作目录)--template:可以通过模板来创建预先构建好的自定义git目录
git config
用户名配置:
git config --global user.name "username"
git config --global user.email xxx@xxx.com
Instead of 配置:
git config --global url.git@github.com:.insteadOf https://github.com/
Git命令别名配置:
git config --global alias.cin "commit --amend --no-edit"
git remote
查看远程仓库
git remote -v
添加远程库
git remote add [origin] [url]
同一个Origin设置不同的Push和Fetch URL
git remote add origin [url1]
git remote set-url --add --push origin [url2]
HTTP Remote
免密配置
URL形式:github.com/git/git.git
内存:git config --global credential.helper 'cache--timeout:=3600'
硬盘:git config --global credential.helper "store --file/path/to/credential-file"
不指定目录的情况默认是~/.git-credentials
SSH Remote
URL形式:git@github.com:git/git.git
免密配置
SSH可以通过公私钥的机制,将生成公钥存放在服务端,从而实现免密访问。
目前的Key的类型四种,分别是dsa、rsa、ecdsa、ed25519。默认使用的是rsa,由于一些安全问题,现在已经不推荐使用dsa和rSa了, 优先推荐使用ed25519
生成公密钥:
ssh-keygen -t ed25519 -C [email]
git add
git add命令后文件会被添加到暂存区
git add [path]
git commit
git commit将暂存区的文件提交到仓库
git commit -m "[description]"
.git下的objects
- Blob:存储文件的内容
- Tree:存储文件的目录信息,可以多个Blob信息
- Commit:存储提交信息:一个Commit可以对应唯一版本的代码
如何把三个Object信息串联在一起?
- 通过Commit寻找到Tree信息,每个Commit都会存储对应的Tree ID
- 通过Tree存储的信息,获取到对应的目录树信息
- 从tree中获得blob的ID,通过Blob ID获取对应的文件内容
.git下的refs
Refs文件存储的内容对应Commit ID,可以把ref当做指针,指向对应的Commit来表示当前Ref对应的版本。
refs/heads前缀表示的是分支,除此之外还有其他种类的ref,比如refs/tags前缀表示的是标签。
分支管理-branch
创建分支命令:
git branch (branchname)
切换分支命令:
git checkout (branchname)
创建并切换到新分支
git checkout -b (branchname)
git tag
表示发布稳定版本
git tag v0.1
Annotation Tag——附注标签
附注标签是一种特殊的标签,可以为tag增加一些信息
git tag -a v0.1 -m "标签信息"
追溯历史版本
上面提到Refs中指向得问Commit可以获取唯一的代码版本。Commit中存有parent commit字段,通过commit的串联获取历史版本的代码。
commit --amend:可以修改最近的一次commit信息,修改之后commit id会变。
rebase:通过git rebase -i HEAD~3可以实现对最近三个commit的修改:1、合并commit;2、修改具体的commit message;3、删除某个commit
filter --branch:可以指定删除所有提交中某个文件或者全局修改邮箱地址等操作。
悬空Object:没有ref指向的object,通过fsck查看
git fsck --lost-found
Git GC
git gc可以删除一些不需要的object,以及会对object进行打包压缩来减小仓库的体积.
git gc --prune=now
git reflog:reflog是用于记录操作日志,防止误操作后数据丢失,通过reflog来找到丢失的数据,手动将日志设置为过期。
git reflog expire --expire=now --all
git clone & pull & fetch
Clone:拉取完整的仓库到本地目录,可以指定分支,深度。Fetch:将远端某些分支最新代码拉取到本地,不会执行merge操作,会修改refs/remote内的分支信息,如果需要和本地代码合并需要手动操作。Pull:拉取远端某分支,并和本地代码进行合并,操作等同于git fetch + git merge也可以通过git pull -rebase完成git fetch + git rebase操作。可能存在冲突,需要解决冲突。
git push
push:将本地代码同步到远端。git push origin master
冲突问题
- 如果本地的commit记录和远端的commit历史不一致,则会产生冲突,比如
git commit --amend or git rebase都有可能导致这个问题. - 如果该分支就自己一个人使用,或者团队内确认过可以修改历史则可以通过
git push origin master -f来完成强制推送,一般不推荐主干分支进行该操作,正常都应该解决冲突后再进行推送。
推送规则限制
可以通过保护分支,来配置一些保护规则,防止误操作,或者一些不合规的操作出现,导致代码丢失。