Git
版本控制工具
版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。版本控制能方便查看更改历史,备份以及恢复以前的版本,保证多人协作不出问题。
Git对待数据的方式,更像是把数据看作是对小型文件系统的一组快照。每次提交更新或者在Git中保存项目状态时,它主要对当时的全部文件制作一个快照并保存这个快照的索引。为了高效,如果文件没有修改,Git不再重新存储该文件,而只是保留一个链接指向之前存储的文件,Git对待数据更像是一个快照流。
安装Git和TortoiseGit
TortoiseGit
TortoiseGit提供了Git的图形化操作界面,Git工作区的目录和文件的图标符加了标识版本控制状态的图像,可以非常直观地看到哪些文件被更改了需要提交。通过对右键菜单的扩展,可以非常方便操作Git版本库。
通过设置,选择Git提供的ssh客户端,这样在下载ssh协议的代码仓库时,命令行与图形界面都可以使用同一套公钥和密钥。
Git基本配置
3种配置等级
- 系统配置:
git config --system
对所有用户都有效,存放在git的安装目录下:%Git%/etc/gitconfig
- 用户配置:
git config --global
只对当前用户有效,存放在用户目录下:~/.gitconfig
仓库配置:
git config --local
只对当前项目有效,存放在项目目录下:
.git/config
配置个人身份
1 | git config --global user.name "Hunter" |
这个配置信息会在Git仓库提交的修改信息中体现,和Git服务器认证使用的密码或者公钥密码无关。
文本换行符配置
这一节的内容仍然是给我造成困惑的部分,感觉从参考资料来看,跨平台的项目开发应该要自动转换换行符。但是在我目前有限的开发经验来看,似乎并没有对项目造成影响,怀疑可能是IDE完成了相应的工作。
默认的配置状态为:core.autocrlf=true
,暂且不去作修改,待日后有了深刻的理解再来完善本节内容。
编码配置
中文编码支持
git config --global gui.encoding utf-8
图形化界面采用的编码
git config --global i18n.commitencoding utf-8
git commit log存储时,采用的编码
git config --global i18n.logoutputencoding utf-8
查看git log时,显示所采用的编码
显示路径中的中文
git config --global core.quotepath false
与服务器的认证配置
http/https协议认证
禁用SSL证书验证:git config http.sslverify false
- 当你连接到一个不受信任的远程仓库时,可能没有有效的 SSL 证书,或者证书已经过期。
- 当你在开发或测试环境中使用自签名的 SSL 证书时,可能需要禁用验证以避免错误。
SSH协议认证
使用公钥认证,无需输入密码,加密传输,操作便利又保证安全性。
配置过程
生成公钥
在bash命令行中输入如下命令:
1
ssh-keygen -t rsa -C "hspecial@163.com"
一路回车,就能在用户目录下
~/.ssh
中,生成公钥id_rsa.pub
添加公钥
id_rsa.pub
中的内容到代码平台
新增公钥
出于某些情况,你可能要在另外的平台或者另外的项目,使用不同的邮箱来生成公钥,以便和代码平台的账号相匹配。
生成公钥
提示
Enter file in which to save the key
(输入要保存密钥的文件,即id_rsa文件)”时,输入密钥文件的保存位置。为了和用户配置等级的密钥区分,我选择在默认公钥的目录下创建对应的平台或项目名的文件夹。输入保存密钥的文件绝对路径即可。添加公钥
id_rsa.pub
中的内容到代码平台
Git基本命令
Git版本控制下的工程区域
- 工作区 working directory
日常工作的代码文件或者文档所在的文件夹。
- 暂存区 stage
一般存放在工程根目录.git/index
文件中,因此也可以把暂存区叫做索引。
- 版本库 Repository
.git
文件夹就是Git的版本库,也可以叫本地仓库。
Git版本控制下的三种文件状态
- 已修改 modified
修改了某个文件,但还没有提交保存
- 已暂存 staged
把已修改的文件放在下次提交时要保存的清单中。被git add
的文件就是已暂存的状态。
- 已提交 committed
文件已经被安全地保存在本地数据库中
常用命令
工程准备
git init
:本地目录下新建git项目仓库git clone [URL]
:复制远端工程到本地如果所在的项目Git服务器已支持
git-lfs
,对二进制文件进行了区别管理,那么复制工程的时候**务必使用git lfs clone [URL]
**,否则克隆操作无法下载到工程中的二进制文件,工程内容不完整。
查看修改
git diff
:查看工作区的修改内容(当前索引与上次提交/任意两个节点(分支)之间的差异)git diff --cached
:当前索引与上次提交之间的差异
添加
--name-status
参数,可以只看文件列表git status
:查看工作区和暂存区的文件状态该命令能看到修改的git文件是否已被暂存,新增的文件是否纳入了git版本库的管理。
Untracked files
:新建但未被跟踪的文件Changes not staged for commit
:修改但未被暂存的文件Changes to be committed
:已修改并已暂存的文件
文件修改后提交推送
git add
:新增文件到暂存区把文件添加到暂存区,是提交修改文件之前的必要操作。如果文件已经被git追踪,即曾经提交过,在Git的早期版本中,需要
git add
再提交;在较新的版本中,无需git add
即可提交。git rm
:删除文件到暂存区执行
git rm
后,通过git status
查看时,会有deleted: xxx
的提醒。之后进行提交,对应的文件就不再受git工程的管理。直接从硬盘中删除文件,然后对该文件执行git commit
,git会自动将删除的文件从索引中移除,效果相同。git mv
:移动文件到暂存区相当于在
mv
操作的基础上,用git将操作传入了暂存区。git commit
:提交更改的文件将暂存区中的文件改动提交到本地的版本库,一般需要附带提交描述信息,所以常见的用法是:
git commit file_name -m "commit message"
如果要一次性提交所有在暂存区改动的文件到版本库,可以执行
git commit -am "commit message"
git push
:将本地版本库的分支推送到远端对应的分支常见的推送命令格式:
git push origin branch_name:new_branch_name
new_branch_name
是推送成功后,在远端服务器上的分支名,:new_branch_name
可以不写,远端分支名就和本地分支名相同。
查看日志
git log
:查看当前分支上的提交日志git log
默认按提交时间的由近到远列出所有的历史提交日志,每个日志基本包含:- 提交节点
- 作者信息
- 提交时间
- 提交说明
--name-status
能列出涉及改动的具体文件
分支管理
git branch
:列出所有本地分支如果想查看远端服务器上的分支,
-r
即可,返回的分支名带origin前缀,即表示在远端。如果想查看远端和本地的所有分支,-a
即可。新建分支
默认基于当前节点创建分支
git checkout -b new_branch_name
新建后会自动切换到新分支git branch new_branch_name
新建后不会切换到新分支
删除分支
git branch -d branch_name
git branch -D branch_name
大写的D表示强制删除当目标分支上包含未合并的改动,则需要通过强制删除来操作。
git branch -d -r branch_name
删除服务器上的远程分支删除后还需要推送到服务器:
git push origin : branch_name
切换分支
git checkout branch_name
git checkout -f branch_name
如果当前分支工作区存在修改未提交的文件,与目的分支上的内容冲突,会导致切换失败,则需要使用
git checkout -f
进行强制切换。
checkout的对象可以是分支,也可以是某个提交节点或者节点下的某个文件。
从远端更新分支
git pull origin remote_branch:local_branch
从远端服务器中获取某个分支的更新,再**与本地指定的分支进行自动合并(merge)**,如果远程指定的分支与本地指定的分支相同,则可以直接执行
git pull origin remote_branch
git fetch origin remote_branch:local_branch
与
git pull
不同,git fetch
在获取到更新后,不会自动合并,而是留给用户一个操作空间,确认git fetch
内容符合预期后,再决定是否手动合并节点。
分支合并
合并目标分支内容到当前分支,以下两种方式都可以达到目的
git merge branch_name
git会将指定的分支与当前分支进行比较,找出二者最近的一个共同节点base,之后将指定分支在base之后分离的节点合并到当前分支上,实际上是分支之间,差异提交的节点的合并。会保留每个分支的所有历史。
git merge
可能会遇到冲突,此时使用缺点:每次合并会产生新的提交节点,导致分支线混乱;分支关系模糊,无法准确看到哪些是合并产生,哪些来自原始分支。
git rebase branch_name
rebase可以避免merge的交织。
二者的实现机制和对合并后节点造成的影响有很大差异,有着各自的风险。
推荐操作:
次级分支rebase main。
次级分支rebase可以让自己的提交一直处于最前面,保证提交时间的有序性。
main merge次级分支。
可以看到主分支的哪个特性是基于次级分支同步而来。
实际开发中,比如当前自己开发的分支为hunter_test
,主分支为main
。应当通过Rebase 'hunter_test' onto main
(onto,把当前分支的基点移动到master分支的最新提交),同步最新的master分支代码。再将自己的修改提交并push到远程分支,向main分支发起merge request请求。main分支通过Merge 'hunter_test' into 'main'
,将特性分支的更改合入到main分支中。
撤销操作
git reset commit_id
可将工作区内容回退到历史提交节点。IDEA中选择目标分支的对应提交,右键
Reset Current Branch to Here
:- Soft模式:不改变工作目录和暂存区(git add后),将被回退的提交放入暂存区。
- Mixed模式:清空暂存区,将回退的变更和暂存区的内容都放入工作目录。
- Hard模式:回退至指定提交,清空暂存区和工作目录的变更。(清除最彻底的模式)
- Keep模式:保留本地的变更,清除被回退的提交记录。
git checkout .
回退本地所有未提交的修改。这是一条有风险的命令,不给用户任何确认机会。它会取消本地工作区的修改,用暂存区的所有文件直接覆盖本地文件,达到回退内容的目的。
如果仅仅想回退某个文件的未提交改动,可以使用
git checkout -filename
;如果想将工作区回退到某个提交版本,可以使用git checkout commit_id
。
进阶操作
Patch
适用于生成和应用补丁文件,可以在不同的代码库之间传递和应用提交的更改内容。
git format-patch -l -o path
-l
:最近一次提交也可指定数量,搭配提交记录号指定具体的提交。例如
git format-patch -1 提交记录号 -o path
-o
:补丁文件路径
IDEA中的操作方式:
选中需要的提交,右键选择
Create Patch...
可以选择存到文件或剪切板中。
工具栏 - Git - Apply Patch
git cherry-pick
适用于选择性地将单个或多个提交应用到当前分支中,创建一个新的提交。
在当前分支,git cherry-pick 需要的提交记录号
,就能将指定的提交添加到当前分支中。
如果合并指定的提交到当前分支遇到冲突,3种处理方式如下:
- 解决所有冲突之后,通过
git add/rm 更改内容
进行标记,git cherry-pick --continue
。 git cherry-pick --skip
跳过冲突的提交。git cherry-pick --abort
,终止执行,并回到执行cherry-pick之前的状态。
IDEA中的操作方式:
选中目标分支中的目标提交,**右键选择Cherry-Pick
**就能将对应的提交应用到当前分支中。
git stash
git stash
命令将当前本地的所有变更暂存到一个栈中,然后就可以干净地切换分支。git stash save '暂存一些修改'
可以添加注释。git stash list
可以看到stash的所有记录。git stash pop
可以将最新的一次暂存的代码恢复到本地。
revert
代码回退。
IDEA中,选中目标提交,右键点击Revert Commits
,就能进行代码回退,并且会产生新的对应的逆向操作提交。
生成新的逆向操作的提交的好处是,如果后续leader的想法改变,需要保留删除的代码,此时对revert的提交再revert一次就可以了。
解决代码合并冲突
通常在项目中,各种git操作(merge、rebase…)都可能引起代码冲突。在IDEA中中会弹出一个冲突提示框:
有3种处理情况:
点击
Merge...
依次查看处理冲突,进行代码合并。合并不顺利,后悔了不想合并代码,点击
Close
关闭该冲突提示框。此时右下角应该会有一个xxx stopped due to conflicts
弹框。点击
Abort
就能终止执行,并回到执行引起代码冲突的git操作之前的状态。代码已合并完成,在push之前后悔了。在当前代码分支,选择最新的提交记录,右键
Reset Current Branch to Here
,Hard模式(回退至指定提交,清空暂存区和工作目录的变更。(清除最彻底的模式)),就能清除合并记录。