Git教程
Git介绍
git命令思维导图:
分布式:Git版本控制系统是一个分布式的系统,是用来保存工程源代码历史状态的命令行工具。
保存点:Git的保存点可以追踪源码中的文件, 并能得到某一个时间点上的整个工程项目的状态;可以在该保存点将多人提交的源码合并, 也可以回退到某一个保存点上。
Git离线操作性:Git可以离线进行代码提交,因此它称得上是完全的分布式处理,Git所有的操作不需要在线进行;这意味着Git的速度要比SVN等工具快得多,因为SVN等工具需要在线时才能操作,如果网络环境不好, 提交代码会变得非常缓慢。
Git****基于快照:SVN等老式版本控制工具是将提交点保存成补丁文件,Git提交是将提交点指向提交时的项目快照,提交的东西包含一些元数据(作者,日期,GPG等)。
Git****的分支和合并:分支模型是Git最显著的特点,因为这改变了开发者的开发模式,SVN等版本控制工具将每个分支都要放在不同的目录中,Git可以在同一个目录中切换不同的分支。
分支即时性:创建和切换分支几乎是同时进行的,用户可以上传一部分分支,另外一部分分支可以隐藏在本地,不必将所有的分支都上传到GitHub中去。
分支灵活性:用户可以随时创建、合并、删除分支,多人实现不同的功能,可以创建多个分支进行开发,之后进行分支合并,这种方式使开发变得快速、简单、安全。
Git工作流程
从远程仓库中克隆 Git 资源作为本地仓库。
从本地仓库中checkout代码然后进行代码修改
在提交前先将代码提交到暂存区。
提交修改。提交到本地仓库。本地仓库中保存修改的各个历史版本。
在修改完成后,需要和团队成员共享代码时,可以将代码push到远程仓库。
Git安装
官网下载地址:https://git-scm.com/download
Windows
下载相应git版本,默认安装即可
默认使用Git Bash即可
选择提交的时候换行格式
(1)检查出windows格式转换为unix格式:将windows格式的换行转为unix格式的换行再进行提交。
(2)检查出原来格式转为unix格式:不管什么格式的,一律转为unix格式的换行再进行提交。
(3)不进行格式转换 : 不进行转换,检查出什么,就提交什么。
Linux
1 | sudo apt-get install git |
常用配置
用户、邮件配置
1 | #1、查询当前的Git配置 |
设置大小写敏感
Windows上的Git默认是大小写不敏感的。
1 | git config core.ignorecase false |
远程仓库
GitHub
创建仓库
SSH
Github支持两种同步方式“https”
和“ssh”
。
如果使用https
很简单基本不需要配置就可以使用,但是每次提交代码和下载代码时都需要输入用户名和密码。
如果使用ssh
方式就需要客户端先生成一个密钥对,即一个公钥一个私钥。然后还需要把公钥放到githib的服务器上。
SSH(Secure Shell):安全外壳协议
基于密匙的安全验证
使用ssh协议通信时,推荐使用基于密钥的验证方式。你必须为自己创建一对密匙,并把公用密匙放在需要访问的服务器上。
如果你要连接到SSH服务器上,客户端软件就会向服务器发出请求,请求用你的密匙进行安全验证。服务器收到请求之后,先在该服务器上你的主目录下寻找你的公用密匙,然后把它和你发送过来的公用密匙进行比较。
如果两个密匙一致,服务器就用公用密匙加密“质询”(challenge)并把它发送给客户端软件。
客户端软件收到“质询”之后就可以用你的私人密匙解密再把它发送给服务器。
ssh密钥生成
Windows下ssh秘钥路径:C:\Users\用户名\.ssh
秘钥文件:
id_rsa 私钥
id_rsa.pub 公钥
如果没有秘钥文件,就打开命令行工具生成:
1 | ssh-keygen -t rsa |
ssh密钥配置
进入 Settings 页面:
在key部分将 id_rsa.pub 文件内容添加进去,然后点击 “Add SSH key” 按钮完成配置。
ssh多个私钥管理
使用本地托管多个个ssh的密钥,不同的账号用不同的密匙。
生成SSH Key
1 | # 1、Creates a new ssh key using the provided email Generating public/private rsa key pair. |
识别新的私钥
默认SSH只会读取id_rsa,所以为了让SSH识别新的私钥,需要将其添加到SSH agent。
1 | $ ssh-add ~/.ssh/id_rsa_work |
修改config文件
- Linux
- /etc/.gitconfig 文件:包含了适用于系统所有用户和所有库的值。传递参数选项’–system’ ,读和写这个文件。
- ~/.gitconfig 文件 :具体到用户。传递–global 选项使Git 读或写这个特定的文件。
- .git/config文件:局部配置文件,在.git/config中的值覆盖了在/etc/gitconfig中的同一个值。
该文件用于配置私钥对应的服务器。
1 | # Default github (默认的) |
这样配置,也就是使用hostname为github.com会根据用户名的不同,去使用不用的private key。github上,也可以添加对应的公钥。
- Windows
Git在$HOME目录中查找.gitconfig文件(通常位于C:\Documents and Settings$USER下)。
将SSH key输入到GitHub网站中
将生成的id_rsa_work.pub输入到GitHub网站中。
注意:github根据配置文件的user.email来获取github帐号显示author信息,所以对于多帐号用户一定要记得将user.email改为相应的email
1 | # 设置局部的user.name和user.email |
Git常用命令
命令列表
1 |
版本管理
远程同步
查看状态
1 | # 显示所有远程仓库 |
从远程仓库克隆
1 | # 增加一个新的远程仓库,并命名 |
从远程仓库拉取
1 | # 取回远程仓库的变化,并与本地分支合并 |
推送到远程仓库
1 | git push <remote 名字> <本地分支的名字> : <远程库的名字> |
关联远程仓库
1 | #1、把这个目录变成git可以管理的仓库 |
查看命令
查看状态
1 | # 显示有变更的文件 |
查看日志
1 | # 显示当前分支的版本历史 |
查看差异
1 | # 显示暂存区和工作区的差异 |
1 | #1、查看仓库状态 |
撤销
reset
撤销某次提交,但是此次之后的修改都会被退回到暂存区,把HEAD向后移动了一下。
1 | # 重置暂存区的指定文件,与上一次commit保持一致,但工作区不变 |
revert
用一次新的commit来回滚之前的commit,HEAD继续前进。
1 | # 新建一个commit,用来撤销指定commit,后者的所有变化都将被前者抵消,并且应用到当前分支 |
checkout
1 | # 恢复暂存区的指定文件到工作区(撤销未提交的修改) |
stash
1 | # 暂时将未提交的变化移除,稍后再移入 |
添加文件
1 | # 1、添加指定文件到暂存区 |
提交
提交到本地库
1 | # 1、提交暂存区到仓库区 |
追加修改
1 | # 1、使用一次新的commit,替代上一次提交 |
提交到远程库
删除
删除工作区文件
1 | # 删除工作区文件,并且将这次删除放入暂存区 |
停止追踪指定文件
1 | # 停止追踪指定文件,但该文件会保留在工作区 |
改名文件
1 | # 改名文件,并且将这个改名放入暂存区 |
删除未添加到版本中的文件或者文件夹
1 | # 删除 untracked files |
隐藏的文件
1 | #1、把当前的工作隐藏起来 等以后恢复现场后继续工作 |
分支管理
查看分支
1 | # 1、查看本地所有的分支 |
创建分支
1 | # 1、新建一个分支,但依然停留在当前分支 |
删除分支
1 | #1、删除分支 |
切换分支
1 | # 切换到指定分支,并更新工作区 |
推送分支
1 | #1、把当前新增的dev分支推送到远程库(远程仓库没有该分支则会新建立该分支) |
拉取分支
1 | #方法一 |
合并分支
1 | # 1、合并指定分支到当前分支 |
通常合并分支时,git一般使用”Fast forward”
模式,在这种模式下,删除分支后,会丢掉分支信息,现在我们来使用带参数 –no-ff来禁用”Fast forward”
模式。
1 | git merge –-no-ff -m “注释” dev |
合并过程:
1 | #1、切换到develop分支 |
冲突解决
根据提示冲突文件解决冲突。
标签管理
查看tag
1 | # 列出所有tag |
新建tag
1 | # 新建一个tag在当前commit |
提交tag
1 | # 提交指定tag |
删除tag
1 | # 删除本地tag |
其它
1 | # 生成一个可供发布的压缩包 |
Git分支管理策略
主分支Master
代码库应该有一个、且仅有一个主分支。所有提供给用户使用的正式版本,都在这个主分支上发布。
Git主分支的名字,默认叫做Master。它是自动建立的,版本库初始化以后,默认就是在主分支在进行开发。
开发分支Develop
主分支只用来分布重大版本,日常开发应该在另一条分支上完成。把开发用的分支,叫做Develop。
这个分支可以用来生成代码的最新隔夜版本(nightly)。如果想正式对外发布,就在Master分支上,对Develop分支进行”合并”(merge)。
1 | # 创建Develop分支 |
默认情况下,Git执行”快进式合并”(fast-farward merge),会直接将Master分支指向Develop分支。
使用–no-ff参数后,会执行正常合并,在Master分支上生成一个新节点。
临时性分支】
临时性分支,用于应对一些特定目的的版本开发。临时性分支主要有三种:
1 | * 功能(feature)分支 |
功能分支
功能分支,是为了开发某种特定功能,从Develop分支上面分出来的。开发完成后,要再并入Develop。
1 | # 创建一个功能分支: |
预发布分支
预发布分支,是指发布正式版本之前(即合并到Master分支之前),可能需要有一个预发布的版本进行测试。
预发布分支是从Develop分支上面分出来的,预发布结束以后,必须合并进Develop和Master分支。
1 | # 创建一个预发布分支: |
修补bug分支
修补bug分支。软件正式发布以后,难免会出现bug。这时就需要创建一个分支,进行bug修补。
修补bug分支是从Master分支上面分出来的。修补结束以后,再合并进Master和Develop分支。
1 | # 创建一个修补bug分支: |
忽略文件 .gitignore
.gitignore 配置文件用于配置不需要加入版本管理的文件。
配置语法:
“/“ 开头表示目录;
“?” 通配单个字符;
“[]” 包含单个字符的匹配列表;
“!” 表示不忽略(跟踪)匹配到的文件或目录;
说明:git 对于 .ignore 配置文件是按行从上到下进行规则匹配的,意味着如果前面的规则匹配的范围更大,则后面的规则将不会生效;
编辑 .gitignore 文件:
1 | # 1、忽略目录foder下的全部内容(根目录、某个子目录) |
注意问题: .gitignore文件只对还没有加入版本管理的文件起作用,如果之前已经用git把要忽略的文件纳入了版本库,就不起作用了。
git 打补丁
patch与diff
- .diff:git diff生成的UNIX标准补丁文件,只记录文件改变的内容,不带有commit记录信息,多个commit可以合并成一个diff文件。
- .patch:git format-patch生成的Git专用.patch 文件,带有记录文件改变的内容,也带有commit记录信息,每个commit对应一个patch文件。
创建patch与diff
创建patch文件
1 | 1、某次提交(含)之前的几次提交的patch |
创建diff文件
1 | git diff 【commit sha1 id】 【commit sha1 id】 > 【diff文件名】 |
应用patch与diff
检查patch/diff是否能正常打入
1
2git apply --check 【path/to/xxx.patch】
git apply --check 【path/to/xxx.diff】打入patch/diff
1
2
3
4
5git apply 【path/to/xxx.patch】
git apply 【path/to/xxx.diff】
或者
git am 【--s --signoff】 【path/to/xxx.patch】
git am 【--whitespace=fix】 【path/to/xxx.patch】
冲突解决
使用 以下命令行,自动合入 patch 中不冲突的代码改动,同时保留冲突的部分:
1
git apply --reject xxxx.patch
同时会生成后缀为 .rej 的文件,保存没有合并进去的部分的内容,可以参考这个进行冲突解决。
解决完冲突后删除后缀为 .rej 的文件,并执行
git add.
添加改动到暂存区.继续冲突合入
1
2
3git am --resolved
或者
git am --continue
合入冲突:
1 | 跳过此次冲突,也可以执行 |
更改某个提交内容
可以创建一个分支,用于rebase:
1 | git checkout -b rebase_tmp |
rebase 要指定parent commitID。
直接更改某次提交
1 | # 1、HEAD移到需要更改的commit上: |
将工作空间中的改动追加到某次提交上
1 | # 1、保存工作空间中的改动 |
Git常见问题
window与linux的换行符问题
1 | git config --global core.autocrlf false |
AutoCRLF:
1 | 提交时转换为LF,检出时转换为CRLF |
修改文件权限后文件状态修改
1 | 1、修改文件夹权限 |
拉取仓库中某个目录
1 | #1、开启 Git 的稀疏签出功能, 开启之后方能限制 pull Or push 时规定的某一个目录 |
Github访问速度慢
优化思路:通过绕过DNS解析,直接在本地绑定host
查询DNS
DNS查询网站:
查询 github 相关网址域名
1 | github.com |
修改hosts
windows下打开文件:C:\Windows\System32\drivers\etc\hosts
末尾追加内容:
1 | 140.82.112.3 github.com |
刷新DNS
windows下刷新DNS:
1 | ipconfig /flushdns |
切换git 命令提示中文到英文
1 | #出现全中文的提示,切换到中文 |
git push警告
解决办法:‘matching’ 参数是 Git 1.x 的默认行为,如果你执行 git push 但没有指定分支,它将 push 所有你本地的分支到远程仓库中对应匹配的分支。而 Git 2.x 默认的是 simple,意味着执行 git push 没有指定分支时,只有当前分支会被 push 到你使用 git pull 获取的代码。
根据提示,修改git push:
1 | git config --global push.default matching |
再次执行git push。
当前分支没有追踪信息
There is no tracking information for the current branch…
则说明本地分支和远程分支的链接关系没有创建,用命令:
1 | git branch --set-upstream branch-name origin/branch-name |
冲突,推送失败
![rejected] dev -> dev (non-fast-forward) … Updates were rejected because the tip of your current branch
推送失败,因为远程代码的最新提交和你试图推送的提交有冲突,解决办法:
先用git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推送。
OpenSSL SSL_read
OpenSSL SSL_read: Connection was reset, errno 10054
修改设置,解除ssl验证
1 | git config --global http.sslVerify false |
不能追踪某个文件夹下的修改
fatal: Pathspec ‘xxx’ is in submodule
1 | git rm -rf --cached folder |
检测不到文件变化
git 提交之后,在git上某个文件有后缀@b4c4u7之类的。
本地 git status 的时候检测不到文件的变化:
1 | 从.git/index中删除所有变更过的文件最后再正常提交 |
Git - svn
SVN是集中式版本控制系统,版本库是集中放在中央服务器的。
Git是分布式版本控制系统,那么它就没有中央服务器的,每个人的电脑就是一个完整的版本库。
安装
1 | sudo apt-get install git-svn |
下载svn代码
1 | git svn clone url |
这个操作会从第一个版本开始同步,若版本迭代太多会很费时,优化处理是检出最近的n个版本:
1 | #1、查询最后的版本号为 No |
更新svn仓库到本地
1 | git svn rebase |
本地修改提交到svn仓库
1 | git svn dcommit |
提交冲突解决
1 | #0、提交发生冲突 |
查看log
1 | #1、显示每次修改提交的文件 |
svn
常用命令
1 | #svn常命令 |
添加
1 | # 添加文件或目录 |
拉取代码
1 | # 获取svn代码 |
更新
1 | svn up # 简写 |
提交
1 | # 提交代码修改 |
删除文件
1 | svn delete (del, remove, rm) |
撤销
1 | # 撤销本地修改 |
合并
1 | # 合并svn和本地代码 |
查看
查看状态
1 | # 查看本地修改情况:列出本地修改或增加的文件信息 |
“ ” 无修改
“A” 新增
“C” 冲突
“D” 删除
“G” 合并
“I” 忽略
“M” 改变
“R” 替换
“X” 未纳入版本控制,但被外部定义所用
“?” 未纳入版本控制
“!” 该项目已遗失 (被非 svn 命令所删除) 或是不完整
查看日志
1 | # 查看提交日志 |
查看信息
1 | # 查看当前的svn信息,会显示svn库的URL,最新版本和最后提交时间 |
查看差异
1 | # 将本地代码和svn上进行对比,可指定文件 |
查看指定版本某文件内容
1 | # 显示特定版本的某文件内容 |
查看目录列表
1 | # 显示svn下目录列表 |
查看帮助
1 | # 查看svn帮助,或特定命令帮助 |
属性
获取属性
1 | svn propget(pg,pget) |
设置属性
1 | svn propset(ps,pset) |
编辑属性
1 | svn propedit(pe,pedit) svn:ignore 目录名称 |
恢复属性
在不影响内容更改的情况下还原所有属性更改:
1 | svn revert `svn status | grep '^ M' | sed 's/^ M \+//g'` |
忽略不必要的文件和文件夹
propset(ps,pset) 用于设置属性的值;**propget(pg,pget) **用于获取属性的值。
svn pg svn:ignore #获取属性值
svn ps svn:ignore ‘value’ path #设置属性值
忽略文件夹
1 | # 1.配置SVN默认编辑器 |
设置忽略目录或文件:
svn propedit svn:ignore . #最后的点号表示当前目录不能少
此时会打开vim编辑器,编辑这个文件,即告诉svn哪些目录或者目录应该被忽略,可能会有报错:
svn: None of the environment variables SVN_EDITOR, VISUAL or EDITOR are set, and no ‘editor-cmd’ run-time configuration option was found
说明没有给svn的忽略目录设置文件指定使用什么来编辑,可执行如下命令,或者将这行命令写入到启动脚本: ~/.bash_profile 中
export SVN_EDITOR=vim
也可以直接修改SVN的配置文件:修改这行为:editor-cmd=vim 即可实现。
如写到启动脚本保存退出,则可执行命令 source ~/.bash_profile 来使配置文件立即生效。成功打开文件后一行编写一个忽略的目录或文件即可。保存后会有提示svn:ignore已经修改,此时再执行svn commit提交即可。
清空忽略内容
1 | # 清空svn:ignore的值 |
提交空文件夹
提交文件夹 忽略文件夹内容(前提是文件夹未在版本控制内)
1 | svn propset svn:ignore '*' test |
忽略已提交的文件夹
已经创建了文件夹,并加入了版本控制,现在想忽略这个文件夹,但要保持文件夹的内容
1 | # 导出一个不受版本控制的目录 |
忽略多个目录
给属性设置多个值
1 | # 设置 |
通配符
属性值也可以使用通配符,但是通配符不可以加在末尾,只能加在前面。
1 | # 通配符加在末尾会报错 |