git使用心得体会
最近在孟宁老师的课上学习了git的使用方法,今天借鉴老师的文章:https://mp.weixin.qq.com/s/Km5KuXPETvG0wCGHrvj9Vg,通过实际操作练习一下git的使用方法。
git是一个版本控制系统,能很好的管理我们的代码。github是一个使用git来管理代码的网页版版本控制系统,本次练习就通过使用git和github来学习如何在团队合作控制代码。
一、版本库初始化
开始之前需要在电脑中安装git,安装git可以去git的官方网站:https://git-scm.com/downloads 下载安装。下面的所有操作都是在windows上进行的。
首先打开git bash,新建一个空白文件夹learngit,然后使用 git init 命令创建一个空的版本库:

在learngit文件夹中,会出现一个.git的文件夹,这个文件夹就是我们的版本库,里面有我们操作的所有记录,所以一般情况不要操作这个文件夹。
然后我们在版本库中新建一个文件 readme.txt:

然后使用 git add readme.txt 将工作区的这个文件添加到暂存区中,再使用 git commit readme.txt -m "this is a readme.txt" 将暂存区修改的代码加入到版本库中:

这里的我们先不讲解暂存区和工作区 版本库之间的关系,等到下一节详细展开。
将文件添加到暂存区有两种方法:
git add FILES # FILES是指定文件或文件列表
git add . # 用“.”表示当前目录
我们可以将暂存区的内容删除:
git reset HEAD FILES # FILES指定文件或文件列表
git reset HEAD #当前暂存区内的所有文件
这里使用的HEAD我们会留到后文讲。
我们也可以将文件从暂存区恢复到工作区中:
git checkout -- FILES # 不要忘记“--” ,不写就把FILES当分支名了
git checkout .
将暂存区的内容提交到版版本库中我们使用 git commit -m " " 命令,这里" "之间需要写你将文件提交到版本库中时加的注释,这样当我们回看代码提交记录的时候就能快速回忆起这次提交的意义。
如果这时我们将readme.txt文件中的内容修改如下:

我们使用 git status 可以查看当前仓库的状态:

提示我们readme.txt的内容被修改过。
我们也可以使用 git diff 来比较修改前后的内容:

这里提示我们文件中有一行文本不一样。
最后,我们使用add和commit将这次修改的文件提交到仓库:
二、工作区、暂存区和版本库
刚才在文中我提到了工作区、暂存区和版本库,为什么我们要将一个文本提交变得如此复杂呢?
这就要说到git的前辈svn--集中式源代码管理工具。svn最重要的特性之一就是原子性提交,每一个提交都是由多个文件的修改组成,而且这个提交是原子性的,要么这些修改全部成功,要么全部失败。而SVN提交操作的时候是使用GUI界面的,要想在命令行中实现这个操作比较复杂,所以linus在commit前面,发明了一个暂存区的概念,这个暂存区是可以随意的将各种文件的修改放进去的,这样我们就可以用多个指令精确的挑选出我们需要提交的所有修改,然后再一次性的(原子性的)提交到版本库。问题就完美解决了。
其关系如图所示:

所以这里我们在工作区对文件的修改首先要提交到暂存区中,再将暂存区的文件提交到本版库中。
这时有一个问题需要进行思考:我们每一次提交的文件是将整个文件都提交到版本库中吗?
假设我刚开始的时候有一个大小为100M的文件,这时我对这个文件修改了一行代码,我再将这个文件提交到版本库时,需要将一个大小为100M的文件全部提交上去吗?
这显然是很浪费空间和时间的,git在这里使用了按行对比的方法,我们对版本库提交的每一次修改都是按行对比的,只需要将要修改的行加入版本库就可以,极大的简便了操作。
比如刚才我们对readme.txt修改以后:

git就能清楚的知道我们的修改是什么,这里就是将两个文件按行对比得出的结果。
三、github的使用
github是一个完全使用git版本管理的远程系统,我们可以在上面创建自己的远程版本库,也可以在上面看到别人的代码版本库。
为了能让本地的git和github连接,我们使用 ssh-keygen -t rsa -C "邮箱名" 进行连接,这里需要在github中找到你账户的ssh的公钥。
这是我们在github中创建一个learngit仓库,将本地的仓库拷贝到github上的仓库,使用
git remote add origin git@github.com:tjdjl/learngit.git git push -u origin master
将本地仓库拷贝到了github上:

在github中如图所示:

我们可以使用 git pull 将github上的仓库同步至本地。
四、分支操作
到现在为止,我们都是使用的单人操作,但在实际操作中,往往是多人同时并行操作,那如何去管理代码呢?
我们的每一次提交按照时间排序排成一个分支,但我们的代码最终肯定要合并成一个代码,这么多人的分支如何合并呢?
这就要回到我们前文讲过的,我们将每一个提交简化成了一个修改记录,那如果我们将所有人的修改记录合到一起,不就是一个最终合并好的代码吗?
这里我们当前只有一个分支master,一个head指针指向master。
我们可以创建另一个分值my_master:
使用 git branch my_master 创建my_master分支
使用 git checkout my_master 将head转移到my_master分支

这里需要解释一下,我们在刚创建的时候,git会默认创建一个master分支,我们刚才的操作都是在master上进行的,现在我想分出来一个分支,叫my_master,这里git是如何区分我当前的操作是在什么分支上的呢?
git使用了一个概念,叫head指针,刚开始这个head指向的是master分支,如果我创建了一个新分支,然后将head指向了新分支,操作就会在新分支上进行。
使用 git branch 可以查看当前分支:

现在我们在my_branch中修改readme.txt文件:

将修改提交至仓库:

此时使用 git merge master 将master分支和my_master分支合并到master分支中:

我们这里使用的合并是快进式合并,即将两个分支合并会合并到同一个时间线上,我们也可以使用 git merge --no-ff my_master 关闭快进式合并。
下面是快进式合并后的结果:

如果我们关闭快进式合并,生成的代码线如下图:

此时我们就可以删除my_master了

这里会出现一个问题,比如对于同一个文件A版本,一个分支修改成了B版本,另一个分支修改成了C版本,如果两个版本想要同时合并到A版本上该怎么办?
这就要求我们能手动解决冲突,在git执行merge操作就会不成功,并提示我们哪里有冲突,让我们修改后再执行merge操作。
比如说,我现在创建一个my_branch,在readme.txt中修改为:

并提交至本地仓库

然后我们切换至master分支,并将readme.txt改成

然后将readme.txt提交至本地仓库

这时我们使用git merge my_branch

会提示我们合并发送了冲突,需要解决
这时,我们使用 git status 会提示我们冲突发生在哪里

这里readme.txt内变成了

在git中使用<<<、===、>>>告诉我们冲突发生在什么地方
我们将文本改成

这样再使用将文本提交

这里使用 git log 也可以查看当前的情况

这时,我们需要清楚git分支合并背后的工作原理,才能更好的理解刚才的过程。

git这里把代码按行进行对比得到一个差异部分,这部分叫增量补丁,我们每一次的add操作都会按行对比,得出一个增量补丁,而我们前文的git commit操作就是将我们本地仓库的所有修改合并成一个commit。
在commit时,我们在提交时会生成一个40位的哈希值,这个哈希值中包含了我们提交的时间,这就保证了我们每一次提交都能被追溯到,保证了数据可以被完全信任。将每一个commit串起来,就是一个分支。而我们平常用的tag标记,v1.0,v2.1这种就是一个别名,是为了方便好记。
比如:

这里,我们如果想要得到H,只需要将B D F与G的增量补丁合并以后,解决冲突后的版本就是H。
最后,这里我们如果想将本地的仓库和远程的仓库同步一下,可以使用 git pull 将本地的仓库推送至远程仓库


这里,我们就使用了git的几个常见操作,这里需要整理一下git的使用操作图:

git分为远程仓库、本地仓库和工作区三部分
我们使用add将工作区的内容放置到暂存区
使用commit将暂存区的内容放置到本地仓库
使用checkout将本地仓库的内容放置到工作区
使用push操作将本地仓库的内容推送到远程仓库
使用fetch/clone将远程仓库的内容同步到本地仓库
使用pull将远程仓库的内容同步到工作区
五、git rebase操作
代码管理最重要的就是简洁,我们的每一条commit最好对应一个功能的操作,所以在合并和push以前,我们最好整理一下自己的commit记录,以便在将来能更好的回顾。这里可以使用rebase操作对自己的commit做一个整理
git rebase -i [startpoint] [endpoint]
这里的startpoint和endpoint指定的是add的编辑区间,如果不指定endpoint,默认是到当前的head节点。
我们也可以使用^,表示前一个节点,^^,~5等多种操作指定编辑区间。
如果我们输入 git rebase -i HEAD^^ ,表示从head节点的前两个节点进行查看,得到如下图所示:

这时可以通过文本操作删除this is a my_branch's modify这行,这里的文本操作是vim中的基本操作,使用dd删除一行,使用:wq保存。

操作结果如下所示:

假如说我们当前的分支线为:
A->B->C
这时,删除B节点以后,和两个分支合并会冲突一样,可能会对C节点造成冲突,我们就必须手动解决冲突。
六、Fork + Pull request
在github的使用中,我们看到了别人的代码想要将其代码拉取到我的仓库中时,可以使用fork操作,相当于在自己的仓库复制了一份别人的代码。
我们在自己的仓库中对代码进行修改是独立于别人的仓库的,如果我们想要将修改加入别人的代码中时,可以使用github中的Pull request按钮将自己的代码提交给原仓库拥有者,当其同意我的代码加入其仓库时,我修改的代码就会更新至我fork的仓库,这样做主要是因为在github上程序员的代码水平层次不齐,这样操作能更好的管理自己的代码仓库,防止别人对自己仓库的代码进行修改。

浙公网安备 33010602011771号