Git学习
Git下载
Git官网下载地址:https://git-scm.com/download
Git配置
查看配置git config -l
查看系统配置git config --system -l
#在安装目录的etc文件目录下
查看全局配置
#在C盘的用户目录下git config --global --list
用户配置git config --global user.name "username" #名称 git config --global user.email "xxxxxxxxx@qq.com" #邮箱
初始化仓库
1 | git init |
克隆仓库
1 | #克隆一个项目和它的整个代码历史(版本信息) |
Git文件操作
文件的4种状态
版本控制就是对文件的版本控制,要对文件进行修改,提交等操作,首先要知道文件当前在什么状态,不然可能会提交了现在还不想提交的文件,或者提交了的文件没提交上。
- Untracked:未跟踪,此文件在文件夹中,但并没有加入到git仓库,不参与版本控制,通过
git add
状态变为Staged。 - Unmodify:文件已经入库,未修改,即版本库中的文件快照内容与文件夹中完全一致,这种类型的文件有两种去处,如果它被修改,而变为Modified,如果使用
git rm
移出版本库,则成为Untracked文件。 - Modified:文件已修改,仅仅是修改,并没有进行其他的操作,这个文件也有两个去处,通过
git add
可进入暂存staged状态,使用git checkout
则丢弃修改过,返回到unmodify状态,这个git checkout
即从库中取出文件,覆盖当前修改! - Staged:暂存状态,执行
git commit
则将修改同步到库中,这时库中的文件和本地文件又变为一致,文件为Unmodify状态,执行git reset HEAD filename
取消暂存,文件状态改为Modified
工作区:就是电脑上看到的目录,比如目录下testgit里的文件(.git隐藏目录版本库除外)。或者以后需要再新建的目录文件等等都属于工作区范畴。
版本库(Repository):工作区有一个隐藏目录.git,这个不属于工作区,这是版本库。其中版本库里面存了很多东西,其中最重要的就是stage(暂存区)(或者叫index),还有Git为我们自动创建了第一个分支master,以及指向master的一个指针HEAD。
使用Git提交文件到版本库有两步:
第一步:是使用 git add
把文件添加进去,实际上就是把文件添加到暂存区。
第二步:使用git commit
提交更改,实际上就是把暂存区的所有内容提交到当前分支上。
(这些都是在本地仓的操作)
查看文件状态
上面说文件有4种状态,通过如下命令可以查看到文件的状态:
1 | #查看所有文件的状态 |
版本恢复:
通过上面的显示我们可以知道,增加内容3333333的版本号是 b8a7cf3.我们现在可以使用命令
git reset --hard b8a7cf3
来恢复了。演示如下:
可以看到目前已经是最新的版本了。
提交文件
1 | #提交修改到暂存区 |
撤销修改和删除文件
1 | #丢弃工作区的修改 |
两种情况如下:
- file自动修改后,还没有放到暂存区,使用 撤销修改就回到和版本库一模一样的状态。
- 另外一种是file已经放入暂存区了,接着又作了修改,撤销修改就回到添加暂存区后的状态。
1 | #删除工作区的文件 |
这是有两种选择:
git commit
提交删除修改到版本库git restore-- [file]
从版本库中恢复文件
远程仓库
前面已经介绍了本地仓库的基本操作和原理
接下来可以创建一个远程仓库可用来备份本地仓库
常用仓库可来自github或gitee
创建好远程仓库后,要将本地仓和远程仓连接同步,常用有ssh和https两种同步方式。
- https:很简单基本不需要配置就可以使用,但是每次提交代码和下载代码时都需要输入用户名和密码。
- ssh:需要客户端先生成一个密钥对,即一个公钥一个私钥。然后还需要把公钥放到github的服务器上。
何为SSH?
SSH 为 Secure Shell(安全外壳协议)的缩写,由 IETF 的网络小组(Network Working Group)所制定。 SSH 是目前较可靠,专为远程登录会话和其他网络服务提供安全性的协议。 利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题。
基于密钥的安全验证
使用ssh协议通信时,推荐使用基于密钥的验证方式。你必须为自己创建一对密匙,并把公用密匙放在需要访问的服务器上。 如果你要连接到SSH服务器上,客户端软件就会向服务器发出请求,请求用你的密匙进行安全验证。服务器收到请求之后,先在该服务器上你的主目录下寻找你的公用密匙,然后把它和你发送过来的公用密匙进行比较。 如果两个密匙一致,服务器就用公用密匙加密“质询”(challenge)并把它发送给客户端软件。 客户端软件收到“质询”之后就可以用你的私人密匙解密再把它发送给服务器。
ssh密钥生成
- 创建SSH Key。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果有的话,直接跳过此如下命令,如果没有的话,打开命令行,输入如下命令生命公钥和私钥:ssh-keygen -t rsa一路回车,默认配置。
在用户主目录下生成了.ssh文件夹内包含id._rsa(私钥)和id_rsa.pub(公钥)文件
在gitee(或github)中添加公钥
将id_rsa.pub中的内容复制到上面
连接远程仓库
1. 若是在远程仓的基础上连接,直接拿远程仓库对应的ssh
在本地想要建立仓库的位置打开bash输入如下命令即建立连接
1 | #克隆远程仓并建立ssh连接 |
2. 若是在本地仓的基础上连接
1 | #初始化建立本地仓 |
则首先在想要建立本地仓的位置初始化
若出现如下错误:
则说明该本地仓已连接远程仓
可以执行如下命令先把连接断开再连接新的远程仓
1 | git remote rm origin |
同步本地仓版本到远程仓
1 | git push -u origin master |
若出现如下错误:
则说明本地仓无远程仓的README.txt
则应先从远程仓拉取文件合并
1 | #拉取文件合并 |
把本地库的内容推送到远程,使用git push命令,实际上是把当前分支master推送到远程。
由于远程库是空的,我们第一次推送master分支时,加上了 –u 参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
从现在起,只要本地作了提交,就可以通过如下命令:git push origin master
把本地master分支的最新修改推送到github上了,现在你就拥有了真正的分布式版本库了。
创建与合并分支
创建、切换分支
在版本回填退里,你已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。
首先,我们来创建dev分支,然后切换到dev分支上。如下操作:
1 | #切换分支 |
我们接着在dev分支操作:
切换回master分支会发现内容并未改变:
这是因为这个改变仅是发生在dev分支的,这就方便了多人协作开发,每个人的分支不同,提交不影响其他人的版本。
合并分支
把dev分支上的内容合并到master分支上:
在master分支上执行如下命令:
1 | #将指定分支合并到当前分支上 |
可看到,和dev分支最新提交的完全一样
注意到上面的Fast-forward信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。
分支命令总结:
1 | #查看分支 |
冲突
dev分支提交新内容 4444444444
master分支添加内容 55555555
则此时在master合并dev会出现冲突:
此时状态:
Git用<<<<<<<
,=======
,>>>>>>>
标记出不同分支的内容,其中<<<HEAD
是指主分支修改的内容,>>>>>dev
是指dev上修改的内容,我们可以修改下如下后保存:
则此时有两个分支的内容,自己调整即可:
查看分支合并情况
1 | #查看分支合并情况 |
分支管理策略
通常合并分支时,git一般使用"Fast forward"
模式,在这种模式下,删除分支后,会丢掉分支信息,现在我们来使用带参数 –no-ff来禁用"Fast forward"
模式。首先我们来做demo演示下:
- 切换到dev分支。
- 修改test.txt内容。
- 添加到暂存区。
- 切换回主分支(master)。
- 合并dev分支,使用命令
git merge –-no-ff -m [注释] dev
- 查看历史记录
删除dev分支后版本仍在
分支策略:首先master主分支应该是非常稳定的,也就是用来发布新版本,一般情况下不允许在上面干活,干活一般情况下在新建的dev分支上干活,干完后,比如上要发布,或者说dev分支代码稳定后可以合并到主分支master上来。
bug分支
在开发中,会经常遇到bug问题,那么有了bug就需要恢复,在Git中,分支是很强大的,每个bug都可以通过一个临时分支来修复,修复完成后,合并分支,然后将临时的分支删除掉。
比如在开发中接到一个404 bug时,我们可以创建一个404分支来修复它,但是,当前的dev分支上的工作还没有提交,且未完成dev分支上的工作。那么我们要放弃dev分支的工作或先暂放404的bug修复吗?
不然,Git提供了一个stash功能,可以把当前的工作现场“隐藏起来”,等以后恢复现场后继续工作git stash
:
那么现在就可以创建issue-404分支来修复bug了。
首先我们要确定在哪个分支上修复bug,比如现在是在主分支master上修复的,现在就要在master分支上创建一个临时分支:
修复完成后,切换到master分支上,并完成合并,最后删除issue-404分支:
此时master分支上的内容和issue-404内容一致。
删除issue-404分支:
现在,回到dev分支上继续干活!
目前工作区状态是干净的。
可以使用git stash list
查看:
工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,可以使用如下两个方法:
git stash apply
:恢复后,stash内容并不删除,你需要使用命令git stash drop
来删除。git stash pop
:恢复的同时把stash的内容也删除了。
演示:
多人协作
当你从远程仓克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来,并且远程仓的默认名称为origin。
- 要查看远程仓的信息,使用
git remote
- 要查看远程仓的详细信息,使用
git remote -v
推送分支
推送分支就是把该分支所有本地提交到远程仓中,推送时,要指定本地分支,这样,Git就会把该分支推送到远程仓对应的远程分支上:
比如我要推送本地仓master分支上的内容,目前远程仓上master分支的Test.txt内容如下:
推送本地仓master分支上的内容,使用git push origin master
命令:
推送成功,此时远程仓master分支的Test.txt文件内容如下:
而dev分支的内容是这样的:
且本次推送并没有推送dev分支:
若想推送dev分支的内容则执行命令git push origin dev
:
成功将dev分支推送到远程仓!
注意:
- master分支是主分支,因此要时刻与远程同步。
- 一些修复bug的分支不需要推送到远程去,可以先合并到主分支,然后把主分支master推送到远程去。
抓取分支
多人协作时,大家都会忘master分支上推送各自的修改。现在我们可以模拟另外一个同事,可以在另一台电脑上(注意要把SSH Key添加到github或gitee上)或者在同一台电脑上另外一个目录克隆,新建一个目录名字叫Git_Test2
从远程仓克隆内容:
将整个远程仓内容以文件夹的形式克隆到本地仓:
如果要在dev分支上开发,就必须要把origin上的dev分支克隆本地,则使用命令创建本地dev分支:
1 | git checkout -b dev origin/dev |
可以看到远程仓的dev分支上的内容已经被clone到本地了。
完成向origin/dev分支的推送。
而我们在目录文件下也对同样的文件的同个地方进行修改,也试图推送到远程仓时,如下:
由于不同的人推同样的文件,修改同一个文件的同一个地方报错!解决的方法也很简单,上面提示我们,先用git pull
把最新的提交从origin/dev抓下来,然后在本地合并,解决冲突,再推送。
git pull
成功了,但是合并有冲突,需要手动解决,解决的方法和分支管理中的解决冲突完全一样,解决后,提交,再push。
原Test.txt:
手动解决后,在提交并push到远程仓:
因此,多人协作工作模式一般是这样的:
- 首先,可以试图用
git push origin branch-name
推送自己的修改。 - 如果推送失败,则因为远程分支比你本地更新早,需要先用
git pull
试图合并。 - 如果合并有冲突,则需要解决冲突,并在本地提交。再用
git push origin branch-name
推送。
Git 命令总结
基本命令
1 | #清除面板内容 |
文件操作
1 | #查看XX文件内容 |
分支操作
1 | #查看分支 |
远程仓库
1 | #本地生成ssh公钥和私钥 |
补充
抓取命令git fetch [remote name] [branch name]
:
- 抓取命令就是将远程仓里的更新都抓到本地,不会进行合并。
- 如果不指定远端名称和分支名称,则抓取所有分支。
拉取命令git pull [remote name] [branch name]
:
- 拉取命令就是将远程仓的修改更新拉倒本地并自动进行合并,等同于
fetch + merge
。 - 如果不指定远端名称和分至名称,则抓取所有并更新当前分支。
git pull
和git pull --rebase
的区别:
git pull
= git fetch
+ git merge
git pull --rebase
= git fetch
+ git rebase
所以两者区别主要是远程与本地代码的合并上:
git merge
:将远端master的代码和本地的代码在新增的节点合并,之前的提交会分开显示。
git --rebase
:将两个分支融合成一个线性的提交,不会形成新节点。
简单来讲就是正常的解决冲突过程是
git add
git commit -m "..."
git push
时因为本地仓库代码与远程仓代码有冲突,所以接下来git pull
拉取远程代码,而冲突需要手动解决- 解决好后重新进行
git add
git commit -m".."
git push
而git pull
这一步如果加上了--rebase
的选项,那么第5步操作将变成如下
git add
git rebase --continue
git push
所以git pull --rebase
用在合并代码的时候其作用就是在一个随机创建的分支上处理冲突,避免了直接污染原来的分区。