Open ghost opened 7 years ago
本文包含的目录:
前言
远程仓库
sourceTree
从远程服务器上克隆项目
修改并提交我的项目
创建Dev分支
删除分支
合并分支
发布新版本
贮藏和修复Bug
多人协作
解决冲突
版本回退
换行符兼容
撤销修改
sourceTree的其他操作
HEAD指针
从SVN迁移到Git
参考教程推荐
本教程主要介绍Git做版本控制的使用方法,着重介绍可视化工具SourceTree,然后以实际例子来讲解项目开发之间的协作。
首先,我们使用sourctree可视化工具来管理Git项目。当然,如果你是Git大神,你也可以使用命令行。实际上在SourcTree中一样也使用命令行。
Git的基本概念,请阅读廖雪峰老师的教程;此处我默认你已经明白了集中式和分布式管理、本地版本库和远程版本库、工作区和暂存区、head、提交、回退、删除、分支、合并等概念。如果实在不知道,那么你跟着我下面的教程做一遍,然后结合SVN的使用经验,你也能很容易的使用SourceTree。
那么,我们现在已经有了SVN做版本库,并且大家已经熟练使用了,为什么我还要推荐使用Git呢?下面给大家介绍一些案例:
案例一:同事A与同事B都从SVN的Dev分支中check out了。这时候,同事A要准备开发一个新功能,但是新功能还在试验阶段,为了不影响同事B的代码,我们通常的做法是新建一个branch。但是,首先你要用权限来操作branch,然后你还要执行copy操作,如果文件较多那么copy的时间也会很长。其次,如果此时,正好连不上服务器怎么办?比如我们的公司的VPN就经常连不上,那多气人。那么有没有办法不需要联网,直接在本地创建分支,不需要拷贝文件,还能进行版本管理的方法呢?有,使用Git。
尤其是Node项目,新检出一个分支,还得又安装一遍依赖,我每次等依赖安装完都是半个小时,超级蛋疼。而且,本地文件系统上存在很多个工作副本,我自己都分辨不出这些副本间有什么差别。
案例二:假设我正在做一个新功能,然后每天下班之前都会习惯性的进行提交,以便能够把每天的工作都纳入版本库,方便跟踪管理。但是,我又不想我提交的代码弄乱了服务端的代码,如果不提交吧,又没有纳入版本管理,如果哪天想吃后悔药,可就入地无门呢,或者万一哪天忘记了保存,恰好机器又被重启了,ps:我就是那种一星期不关机的boy,那这一整天的动作都白费了。频繁的提交,又需要网络连接,commit信息又很难看,提交的代码别人还不能用。那么有没有可以让我们随心所欲,想提交就提交,不想让别人看到他就休想偷窥的方法呢?有,使用Git,它可以帮我们解决这个难题,所以的提交都可以只在本地提交,当机会合适的时候再向服务端提交。
案例三:你有没有试过svn服务器爆炸了?服务器挂了,版本库就丢了,全公司的员工都没法工作了。但是,如果你使用Git,那么你本地就是一个完整的版本库。
关于Git与SVN的更多区别,请参考这篇文章。可以简单总结Git的几个优点:不需要随时联网,本地仓库随时管理;快速分支,解决频繁拉取和安装依赖的麻烦;占用空间少,因为都是指针移动,没有多个文件备份;保证每次提交都是可靠的提交,因为不可靠提交都在自己本地;快速的分支切换,快速的版本回退,因为都是指针的变动;有了Git,你可以吃后悔药。
虽然,每一个人的电脑都可以作为仓库。但是,我们还是需要一个远程仓库,远程仓库可以作为集中管理,也可以作为备份。当然,远程仓库不是必须的。但是,我们在实际的工作中,都会有一个远程仓库。Gitbub就是一个远程仓库,上面托管了大量的代码。
此处,我们使用公司的远程代码托管服务器,http://10.33.4.202:3000,这个和github类似。
打开10.33.4.202:3000:
可以看到,这是一个Go语言实现的Git服务器,首先注册,如果已有账号就直接登录。
这里我使用公司的邮箱注册,注册完成后就能登录。
这里演示作为公司组织来管理项目,点击个人目录切换处的下拉三角形,切换到组织目录。如果没有组织,就自己创建一个组织。这里我创建一个名叫“hx_web”的组织。
个人目录与组织目录稍微有点差别,多了个链接,我们可以进行管理组织。点击“访问hx_web”。
创建一个新的仓库。
仓库语言,授权许可,自述文档都可以随便选。
创建完成后,我们就看到了熟悉的界面。是不是和github长的一样?如果程序员不熟悉这个界面,那你就不是一个合格的程序员。
好,现在远程仓库已经有了,你现在可以邀请其他成员,或者把仓库地址给他,让大家一起来贡献代码。
首先下载sourceTree,sourcetree官方网站https://www.sourcetreeapp.com/,mac和win都支持,如果没有的朋友,可以找我分享。 我这里使用1.9.10.0版本。
安装sourceTree之前,需要先安装Git。Git的下载地址:https://git-for-windows.github.io。
新版sourceTree内嵌了Git,但是,我们一般都会选择自己安装Git。
安装Git之后,在命令行执行Git命令:
如果有上面的显示,表明安装成功,我的Git版本是2.10.0。
然后安装SourceTree。安装完成后,打开,SourceTree为根据你系统的语言来显示中文还是英文,如果是英文,按如下步骤切换到中文:Tools -> General -> Repo setting -> language -> 汉语 -> OK -> 重启。
SourceTree打开后应该是长这样子,我这里项目列表中已经有了三个项目。SourceTree主要是把Git命令进行了可视化,让我们可以直接通过按钮来操作。下面我们就可以使用SourceTree来管理我们的Git项目了。
从远程仓库获取项目的时候,会要求你输入用户名和密码,这个用户名和密码就是你刚才注册的那个,等待他加载完成。
这里演示的是公司的远程代码托管服务器。实际上,也可以从Github等托管服务器上克隆项目。注意,本文说的仓库和项目具有对应关系,你可以理解为一个仓库就是一个项目。
加载完成后,默认是这样子。我们可以查看该仓库下的项目文件,现在从远程仓库克隆的默认应该有三个文件,点击“在文件资源管理器中打开”。该操作会打开操作系统的文件管理器。
切换到“日志/历史”面板。
在本地仓库目录下,去新建一个test.txt文件。
保存,然后在sourceTree的"日志/历史"面板中,查看。
现在会提示你有新的未提交的改动。切换到'文件状态'面板。
该面板也有了变化。这里详细的显示了哪些文件有改动,同时有将改动的文件加入暂存stage、不暂存unstage、提交等选项。
实际上,你点工具栏区的“提交”按钮,也会进入到这个面板。这是因为,sourceTree(Git)会要求你先把修改加入暂存区,然后才能提交。因此,你注意到上面的提交区域的按钮是灰色的吗?
这与Git的运行原理和设定有关,Git存储的是修改,版本的变动,只是一个修改到另一个修改的指针的变化。在这里顺便介绍下Git的工作区和暂存区的概念,详细信息请阅读廖雪峰老师的教程。
工作区:就是我们看到的目录,就是我们实际操作的修改的那些项目文件所在的目录。对应我们这里的LearnGit目录。
版本库:工作区中有一个.Git的目录,通常这是一个隐藏目录。前面已经说过这个文件夹,表示它所在的目录是Git管理的仓库。这个文件夹下,存放就是Git的版本库信息,这就是Git的版本库。
暂存区:打开.git目录,Git版本库中有许多文件,其中最重要的就是称为index(或者stage)的暂存区,还有HEAD指针。而其他分支等信息存放在refs文件夹中。
HEAD指针指向的是我们当前所在的分支,此时,指向的就是默认的master分支。因为,我们只有默认的这一个分支。当然它的指向信息我们是看不到的,但是可以通过sourceTree项目列表中,该项目名称下的分支信息来查看当前HEAD指向的分支。
关于HEAD和分支的详细信息这里不再继续介绍了。下面着重看下暂存区:
暂存区是我们存放修改的地方,所有的修改都必须缓存到这里。当我们执行提交命令时,实际上就是把暂存区的内容提交到HEAD对应的分支上。初始时,暂存区应该是空的,当我们把内容提交到暂存区之后,就像上面这样,暂存区有了内容才能执行commit命令。提交之后,暂存区会被清空,等待下一次的暂存和提交。
从工作区添加修改到暂存区的过程使用的是Git add命令。sourceTree提供了可视化操作,我们直接使用stage ALL 或者stage selected来将修改提交到暂存区。
可以将修改添加到暂存区,当然也可以撤销暂存,对应unStage和unstage selected操作。
下面进行我们的第一次提交。把test.txt文件加入到版本库。
提交成功后,“文件状态”面板又恢复干净了。此时切换到“日志/历史”:
可以看到我们的提交成功了,历史图谱也向前推进了一步。此时,我们的文件已经被Git管理起来了,可以进行版本管理了。
注意,只有加入暂存区的修改才会被提交,因为Git管理的是修改。比如,你先做了第一次修改,然后加入暂存区,接着做了第二次修改,但是第二次修改没有加入暂存区,这时候如果提交,那么你提交的只会是第一次修改的内容。 这是因为Git只是把你第一次放入暂存区的内容情况,而你第二次的修改并没有在暂存区内。要把第二次修改也提交,请重新暂存并提交。
注意,只有加入暂存区的修改才会被提交,因为Git管理的是修改。比如,你先做了第一次修改,然后加入暂存区,接着做了第二次修改,但是第二次修改没有加入暂存区,这时候如果提交,那么你提交的只会是第一次修改的内容。
这是因为Git只是把你第一次放入暂存区的内容情况,而你第二次的修改并没有在暂存区内。要把第二次修改也提交,请重新暂存并提交。
但是,此时我们提交成功,仅仅只是向本地的仓库提交成功了,不信你可以去远程仓库看看有没有最新的提交信息。本地仓库,我们只能在本地玩,虽然也能进行版本管理,但是别人看不到,我们还需要推送到远程仓库,让别人也能看到。
服务端推送,可能也会让你输入用户名和密码。但是,这些都只会输入一次,之后就会被sourceTree记住。
推送成功后,到服务端查看。
我们再做一次修改,在text.txt文件中,添加一句“hello world”,然后提交。
将本次修改推送到远程仓库,然后到远程仓库中去查看是否提交成功。
提交的历史信息图谱中,对应的作者信息,可以自己修改。工具 -> 选项 ->默认用户信息。 同时,保存的用户名及密码等信息在“验证”面板中。可以删除保存的用户密码等信息。 “Git”面板中可以配置SourceTree使用的Git。
提交的历史信息图谱中,对应的作者信息,可以自己修改。工具 -> 选项 ->默认用户信息。
同时,保存的用户名及密码等信息在“验证”面板中。可以删除保存的用户密码等信息。 “Git”面板中可以配置SourceTree使用的Git。
实际的开发中,我们不会像上面那样直接在master分支上操作。我们应该建立一个Dev开发分支。
这个和svn的trunk和branch是一样的。我们实际的开发应该在Dev分支上进行。这样做是有理由的:
比如,我们只有一个master分支,现在已经发布了一个新版本1.0。然后新功能1.1版本也在开发中,但是1.0版本发现一个BUG,这时候我们要如何修复BUG呢?肯定不能舍弃现在正在开发的功能,也不能将现在的代码提交,从而影响已经发布出去的版本,这时候Dev分支就起作用了。
我们的master分支,应该作为主分支,这是一个稳定分支,这个分支应该是作为稳定版本发布的分支。我们的所有的开发工作只在Dev分支上操作,当Dev分支开发完成一个新功能时,再合并到master分支,由master分支发布。master分支有BUG时,从master新建一个临时temp分支,在temp修复BUG,然后合并到Master分支,这样master就可以继续发布。 修复的BUG再合并到Dev分支,这样也保证Dev分支上的代码是稳定的。最后再删除temp分支。
如果服务端有Dev分支,那么我们只需要检出Dev分支即可。这里很明显没有,所有我们要新建一个分支,然后把这个Dev分支也推送到服务端,这样别人也能使用这个Dev分支。
创建新分支是非常快速的,就是1秒钟的事。新分支与被分支的那个分支(这里的master)所处的状态是一样的。
创建新分支后,SourceTree(Git)会默认把HEAD指向新创建的分支,并且新分支与原来的分支所处的状态一样。
如果要切换分支,只需要在需要切换的分支上双击即可。这比使用Git命令切换分支要快很多。
然后把Dev分支推送到服务端。
推送成功后,在sourceTree远程选项的origin中,就会多了一个Dev分支,表明服务端也已经有了Dev分支。
到服务端查看是否创建Dev分支成功。
好,现在我们可以在Dev分支下工作了。切换到Dev分支,然后修改源文件,添加一句“New Dev branch”。
添加成功后,sourceTree的文件状态面板中会提示你有新的更改可以提交了。
注意,此时如果我们还未提交就切换到其他分支,这种修改也会带到其他分支的。直接双击master分支:
此时,我在Dev分支的修改还没提交。就是不管有没有加入暂存区,只要还没commit,那么这种修改在切换分支时,就会带到其他分支。
所以,可能你也注意打了,在切换分支时,sourceTree会发出警告,确定你是否切换分支。并且,在警告中通知你,可以选择清除修改。如果我们不清除修改,那么切换后它就会提示你有新的未提交的更改。这显然不是我们想要的结果。因此,我们在切换分支前,要确保修改已经提交。(还有另外一种方法贮藏,这个后面介绍)
切换回Dev分支,并提交。
提交成功后,Dev分支下就是我们最新的修改了。然后切换回master分支,双击master分支,查看源文件。
可见,master分支确实还处在上一个版本中。
只有一种情况会把修改带到其他分支,就是当前分支与要切换的分支处于同一个节点上。因为此时两个分支实际上他们的指针都指向的同一位置,所以会把修改带到其他分支。 当我们Dev分支有过一次提交,Dev的指针先前移动了一步之后,Dev的指针与master不在同一位置时,如果再次有过修改,然后再切换分支,这时候是会直接报错的。 因此,在切换分支前,无论如何要确保该分支已经被提交。或者使用后面提到的贮藏功能。
只有一种情况会把修改带到其他分支,就是当前分支与要切换的分支处于同一个节点上。因为此时两个分支实际上他们的指针都指向的同一位置,所以会把修改带到其他分支。
当我们Dev分支有过一次提交,Dev的指针先前移动了一步之后,Dev的指针与master不在同一位置时,如果再次有过修改,然后再切换分支,这时候是会直接报错的。
因此,在切换分支前,无论如何要确保该分支已经被提交。或者使用后面提到的贮藏功能。
我们直接从master新建一个temp分支出来,新建分支时,请保证当前的HEAD指向要被分支(master)的那个分支。
新建分支过程不再重复。
新建的分支,应该与它的源分支处于一样的状态。如果不信的话,你可以试试分别切换到master、Dev和temp分支,比较他们的源文件。
删除分支时,要保证HEAD不在要删除的分支上。比如现在,HEAD指向的就是temp分支,我们在temp分支上,右键 -> 删除分支 -> 弹出对话框 -> 确认 ->报错。此时,就会报如下的错误。
把当前分支HEAD指向其他分支,然后执行删除操作。
此时,删除分支成功。
在删除分支时,有时会报如下错误。 就是说要删除的分支有过新的提交,但是还没有进行合并。所以sourceTree会保证你的删除是可靠的,要求你合并之后再删除。如果,你确定不需要合并,那么在删除分支时选择‘强制删除’。
在删除分支时,有时会报如下错误。
就是说要删除的分支有过新的提交,但是还没有进行合并。所以sourceTree会保证你的删除是可靠的,要求你合并之后再删除。如果,你确定不需要合并,那么在删除分支时选择‘强制删除’。
在上面,我们的Dev分支已经超前一个版本。此时,我们确定Dev分支上的修改没有问题,并且可以纳入主分支了,那么我们就要合并分支。
合并分支要到目标分支上去操作,比如我们要把Dev分支上的修改合并到master分支,那么我们就要到master分支上去操作。
合并完成后,我们可以检查master分支下的文件,它已经与Dev分支下的修改一样了。然后将master分支推送到服务端。
注意,这里我的Dev分支我始终没推送到服务端。这只是为了说明,我们在本地的修改是可以不提交到服务端的,这就是我们通常利用分支来修复Bug和开发新功能的方式。 实际情况中,我们的Dev分支还是应该要提交服务端的,因为大家都在Dev分支中工作,而你从Dev分支出去的其他本地分支,是不应该提交到服务器的。 这里不提交Dev分支,只是为了演示可以这么做,而且为后面的功能介绍埋个点。
注意,这里我的Dev分支我始终没推送到服务端。这只是为了说明,我们在本地的修改是可以不提交到服务端的,这就是我们通常利用分支来修复Bug和开发新功能的方式。
实际情况中,我们的Dev分支还是应该要提交服务端的,因为大家都在Dev分支中工作,而你从Dev分支出去的其他本地分支,是不应该提交到服务器的。
这里不提交Dev分支,只是为了演示可以这么做,而且为后面的功能介绍埋个点。
master合并完之后,就可以发布新版本了,我们使用tag标签来表示版本。Tag其实跟分支类似,只不过它是从某一个提交处建立的一个指针副本,因此它不能进行移动,但是可以添加多个tag,也可以删除。
添加完成后,在标签label中就可以看到新添加的标签了。
还可以将标签推送到服务端。
点击确定之后,在服务端查看版本信息。
标签的更多使用这里就不介绍了,其中一个功能就是根据标签回退版本,其实就跟普通的版本回退差不多。一般根据标签的回退情况较少,因为我们的master分支一般都会对应现在已经发布的版本,即使有Bug修复,也会在当前的发布版本上修复Bug,所以一般不会越过很多版本进行回退。
修复Bug的情况,一般出现在对已发布的版本进行Bug修复。也就是对master分支进行Bug修复。
一般的情况是我们工作在Dev分支,然后要切换到master分支进行Bug修复。前面提到过,在切换分支时,要确保该分支已经提交。如果当前Dev分支可以提交,无疑是最好的选择,但是,如果当前不能提交呢?
我们可以使用贮藏功能。贮藏功能就是对现在的更改进行备份,注意仅仅是对更改进行备份。使用贮藏功能后,会让当前分支的工作区恢复到上一次提交的时候,从而使当前工作区变得干净。这叫做贮藏现场。
怎么贮藏现场?
现场贮藏之后,还可以恢复现场:
贮藏功能又分好几种情况。
出现这种情况的原因是因为,此时demo.txt还没有被Git跟踪管理,所以它默认不会被贮藏,从而一直留在文件系统中。如果我们切换到master分支,这个更改(添加新文件也是更改)会被带到master中,sourceTree也会提醒有未提交的更改,提醒你提交这个文件。
为了避免这个文件在master中会被误提交,从而使该文件出现在不应该出现的版本中,我们应该使用下面这种方法。
删除文件操作也需要加入暂存区才能贮藏现场。实际开发中,我们在贮藏现场时,都应该先把文件加入暂存区(主要是避免有新添加文件或删除文件)。
贮藏现场时,如果勾选了“保留暂存的更改”选项,那么已经加入暂存区的内容都会被保留,并且在切换分支时,暂存区的内容也会被带到其他分支去。从而其他分支也能看到所做的更改。
注意,一般情况下,请不要勾选“保留暂存的更改”。因为,这可能会给你带来冲突,除非特殊情况,你确实需要把修改带过去才这么做。
好,现在了解贮藏功能后,就可以进行master分支Bug的修复了。
前面演示的都是一个人开发的情况。下面将演示,多人协作。
首先,从远成仓库新克隆一份代码,取名WorkderB,用来模仿同事B的工作区,之前的LearnGit则用来模仿同事A。
同事B检出Dev分支后,现在Dev分支的代码还停留在helloworld这一步。那是因为同事A还没有把Dev分支推送到服务端。
回到同事A的工作区,把Dev分支也推送到服务端。过程不再演示,然后回到同事B的工作区,看看sourceTree有什么变化。
同事A提交之后,同事B的“拉取”(pull)图标上就会显示一些数字,表示当前有更新,显示的数字,就是服务端超前的版本数。
这个“拉取”图标的提示时间视情况而定,有的人很快就有提示,有的人要等很久,这种情况下我们可以进行手动拉取,而不必等它提示。因此,我们应该在每天上班时,都主动的“拉取”(pull)或者“获取”(fetch),以便获得最新的代码。
“拉取”完成之后,Dev分支下的代码应该和服务端,并且和同事A保持一致了。这个过程中,从服务端获取到的代码,和本地的代码,自动进行了合并。
通过“拉取”按钮获取服务端最新的更改时,可能会发生冲突。比如,同事B在自己的工作区中,对test.txt文件进行了修改,同事A也对test.txt文件进行了修改,并且同事A已经提交到服务端了。因此,同事B在提交时,需要先获取服务端最新的更新,然后才能进行提交,同事B通过“拉取”操作获取服务端最新代码后,就可能在test.txt文件发生冲突。然后,需要我们解决冲突之后,再次提交。
Git提供了一个更加可靠的“拉取”操作,来预测上面可能存在的冲突问题。就是sourceTree工具栏中的“获取”按钮。
“拉取”按钮对应 Git pull命令,“获取”按钮对应 Git fetch命令。 实际上pull和fetch并没有什么特别优缺点,这个可以由程序员自己来决定。fetch的好处是在合并之前可以看到你会更新的是哪些内容,最终决定是否进行合并。无论对于pull还是fetch,合并之后,该产生冲突的地方,还是会产生冲突,fetch并不能在合并之前就修改远程的提交,它只能让你看到有哪些修改,然后预测会不会冲突。当然除非你更改你本地的提交。 个人感觉,平常使用中,程序员用pull较多,而对于代码审核者做code review时使用fetch较多。
“拉取”按钮对应 Git pull命令,“获取”按钮对应 Git fetch命令。
实际上pull和fetch并没有什么特别优缺点,这个可以由程序员自己来决定。fetch的好处是在合并之前可以看到你会更新的是哪些内容,最终决定是否进行合并。无论对于pull还是fetch,合并之后,该产生冲突的地方,还是会产生冲突,fetch并不能在合并之前就修改远程的提交,它只能让你看到有哪些修改,然后预测会不会冲突。当然除非你更改你本地的提交。
个人感觉,平常使用中,程序员用pull较多,而对于代码审核者做code review时使用fetch较多。
为了演示“获取”的功能,同事A先进行一次提交,在test.txt文件中增加一句test,提交命令信息为“test”,然后推送到服务端。
同事B,点击“获取”按钮进行获取。
点击“获取”后,弹出框使用默认的选择即可。
点击确定之后,我们来看看sourceTree有什么变化。
冲突发生的情况,主要是同事A与B都对同一文件的同一位置进行了修改。
产生冲突之后,需要我们解决冲突之后才能提交。这里我们使用一个文件比较工具来进行冲突处理。
这里我们配置一个外部文件比较工具,而放弃使用sourceTree默认的diff工具。这个外部文件比较工具是Beyond Compare。
下载安装Beyond Compare。现在beyond compare最新的版本是4.1.9,但是4.x版本都没有破解版,主要是最近beyond compare公司最近抓的严,我现在是直接使用的是试用30天的,买一个激活码差不多280元左右。
冲突解决完毕,就可以把新的提交推送到服务端了。产生的那个垃圾文件直接删除即可(后面会介绍方法来解决这个垃圾文件)。
另外一种会产生冲突的情况。
实际开发中,我们遇到的第二种情况会多一点。因为,我们鼓励每天上班之前都“拉取”(pull)一下,开始开发之前也“拉取”(pull)一下,以免和服务端相差太远。
解决冲突过程会产生一个垃圾文件,这个文件是冲突的备份文件。可以使用如下命令去去掉:
git config --global mergetool.keepBackup false
不同平台使用的换行符不一样,导致win或者mac或者Linux下,同样的代码因为换行符问题而错误识别为有新更新,甚至不能通过编译的情况。
这里建议在git项目根目录下,创建一个.gitattributes文件,并且添加一句:
* text eol=lf
另外,在命令行运行如下命令:
git config --global core.autocrlf false git config --global core.safecrlf true
并且,建议把编辑器(IDE)的换行符统一更换成Unix格式。
具体问题,这里不演示。
对于,sourceTree的diff文件时,经常显示/No newline at the end of,这个问题的解决方式是,在末尾添加一个空行,这样方便文件比较。
撤销修改其实很少用到,因为,一般的撤销操作都会被编辑器(或者IDE)取代。当然,这并不是说,git的撤销操作就一定不会用到。sourceTree的撤销操作是“丢弃”。
先说什么时候会用到sourceTree(Git)的撤销修改这个操作,一种情况是,自上次提交后,你对源文件做了很多修改,你想一步就退回到初始状态,就是上次提交之后的状态;另外一种情况是,自上次提交之后,你对源文件作了修改,然后添加到了暂存区,但是还没有提交,然后你又做了很多修改,但是你想回到上一次保存到暂存区时的状态。
从上面可以看到,其实sourceTree或者Git的撤销修改虽然很强大,确不太好使用,直接使用命令的话,会容易混淆命令,使用可视化工具sourceTree,又操作麻烦。所以,如果不是特别需要,请直接使用编辑器的撤销操作。
在前面我一直强调Git只是指针的移动,那么Git的指针到底是什么,它到底如果移动的?
前面已经提到过,Git中的指针叫HEAD,它用来指向当前分支。
我们已经知道,git的每一次提交都会把他串成一条线,这条线是一条时间线,一条时间线就是一条分支。所以,一开始时,我们只有一个master分支,也只有一条时间线,所以,我们的HEAD指向master,然后master又指向我们的提交线。
这里有个概念要弄明白,HEAD指向的并不是提交,而是指向分支,master才是指向提交的,所以,HEAD指向的就是当前分支。由此可见,HEAD和master其实都是指针。
当有新提交时,时间线节点增加一个,master向前移动一步,然后HEAD也会跟着移动。
当创建新分支dev时,实际上是新创建了一个dev指针,但是,dev是从master分出去的,所有,初始时,dev和master在同一个节点。
然后HEAD指向了dev。可以看出,创建一个新分支是多么的简单,仅仅只是创建一个新指针,然后HEAD改变下指向,没有文件的拷贝,所以,它在1s内就能完成新分支的创建。
创建新分支后,HEAD指向了新分支,这时候的提交操作,就对应dev了。
在dev上的提交,仅仅只是dev向前移动了一步,而master还在原来的地方没动。
那么,我们的合并操作又是怎么办的呢?合并操作,其实仅仅只是把master指向了dev当前所在的提交,这还是一个指针移动过程。
所以,git的合并同样非常快速,工作区的内容没改变(其实只有很小的改变,因为要切换回master操作,这会使文件发生一些改变),然后就是指针的移动而已。
删除分支,也非常简单。仅仅只是指针的移除,没有文件系统的改变。
删除分支后,已经合并的master分支并没有任何影响,仅仅只是指针的移除。
从SVN迁移到Git,不仅需要源代码迁移,同时我们还希望SVN上的commit信息也能迁移。这里我们使用Subgit工具。
进入subgit的官网,下载subgit的zip包。
下载完成后,解压。然后把解压出来的bin目录添加到环境变量。
然后,新建一个空目录,建立一个authors.txt文件。
authors.txt文件的作用是从svn导出commit信息时,将svn用户信息对应到git用户。它的格式如下:
svnUser = Git User <user@example.com>
前面是svn用户的用户名,然后是对应的git用户名和邮箱。我这里已经配好了我们公司的用户信息mapping文件:
liuxb = liuxb <xingbangl@XXX.com> liaoct = liaoct <liaoct@XXX.com> kangm = liaoct <liaoct@XXX.com> zhuangtj = JesseZhuang <XXX.com> chenlh = chenlh <chenlh@XXX.com> zhoujia = zhoujia <zhoujia@XXX.com>
上面的邮箱地址,我隐藏掉了,用户可以自己去配。本公司的员工可以来找我分享。
然后在这个目录下执行如下命令:
subgit import --non-interactive --authors-file authors.txt --svn-url https://svnurl/hxycf ycf.git
上面的svnurl请替换成相应的svn地址,ycf.git是我们从svn拷贝过来的源码和一些依赖等文件的存放目录,名字可以自己定义,等待subgit执行完毕。
执行完毕之后,还需要一步操作,修改ycf.git\subgit目录下的authors.txt文件,把我们刚才建立的那个authors.txt文件内容拷贝过来即可。这里主要是为了保证用户信息彻底匹配成功。
然后,还是在刚才那个目录下继续执行如下命令:
git clone ycf.git com.ycf.git
这个操作主要是把刚才下载下来的那些文件,初始化为一个干净的本地git仓库。这个仓库的名字叫com.ycf.git。
执行完毕后,现在的com.ycf.git中的内容就是svn中trunk分支的内容了。有了本地仓库,然后将本地仓库与远程仓库链接起来。
建立一个远程仓库,过程不再重复。然后执行如下命令:
git remote set-url origin http://xxx/ycf_new.git
这一步,是把当前本地仓库的url设置为远程仓库的地址,从而把本地仓库和远程仓库链接起来。然后将本地仓库的代码推送到远程仓库:
git push -u origin master
然后查看远程仓库。
已经迁移成功了,再在sourceTree中查看下。
完美,源代码和提交信息都完整的迁移了,enjoy。
Git(sourceTree)使用教程
本文包含的目录:
前言
远程仓库
sourceTree
从远程服务器上克隆项目
修改并提交我的项目
创建Dev分支
删除分支
合并分支
发布新版本
贮藏和修复Bug
多人协作
解决冲突
版本回退
换行符兼容
撤销修改
sourceTree的其他操作
HEAD指针
从SVN迁移到Git
参考教程推荐
前言
本教程主要介绍Git做版本控制的使用方法,着重介绍可视化工具SourceTree,然后以实际例子来讲解项目开发之间的协作。
首先,我们使用sourctree可视化工具来管理Git项目。当然,如果你是Git大神,你也可以使用命令行。实际上在SourcTree中一样也使用命令行。
Git的基本概念,请阅读廖雪峰老师的教程;此处我默认你已经明白了集中式和分布式管理、本地版本库和远程版本库、工作区和暂存区、head、提交、回退、删除、分支、合并等概念。如果实在不知道,那么你跟着我下面的教程做一遍,然后结合SVN的使用经验,你也能很容易的使用SourceTree。
那么,我们现在已经有了SVN做版本库,并且大家已经熟练使用了,为什么我还要推荐使用Git呢?下面给大家介绍一些案例:
案例一:同事A与同事B都从SVN的Dev分支中check out了。这时候,同事A要准备开发一个新功能,但是新功能还在试验阶段,为了不影响同事B的代码,我们通常的做法是新建一个branch。但是,首先你要用权限来操作branch,然后你还要执行copy操作,如果文件较多那么copy的时间也会很长。其次,如果此时,正好连不上服务器怎么办?比如我们的公司的VPN就经常连不上,那多气人。那么有没有办法不需要联网,直接在本地创建分支,不需要拷贝文件,还能进行版本管理的方法呢?有,使用Git。
案例二:假设我正在做一个新功能,然后每天下班之前都会习惯性的进行提交,以便能够把每天的工作都纳入版本库,方便跟踪管理。但是,我又不想我提交的代码弄乱了服务端的代码,如果不提交吧,又没有纳入版本管理,如果哪天想吃后悔药,可就入地无门呢,或者万一哪天忘记了保存,恰好机器又被重启了,ps:我就是那种一星期不关机的boy,那这一整天的动作都白费了。频繁的提交,又需要网络连接,commit信息又很难看,提交的代码别人还不能用。那么有没有可以让我们随心所欲,想提交就提交,不想让别人看到他就休想偷窥的方法呢?有,使用Git,它可以帮我们解决这个难题,所以的提交都可以只在本地提交,当机会合适的时候再向服务端提交。
案例三:你有没有试过svn服务器爆炸了?服务器挂了,版本库就丢了,全公司的员工都没法工作了。但是,如果你使用Git,那么你本地就是一个完整的版本库。
关于Git与SVN的更多区别,请参考这篇文章。可以简单总结Git的几个优点:不需要随时联网,本地仓库随时管理;快速分支,解决频繁拉取和安装依赖的麻烦;占用空间少,因为都是指针移动,没有多个文件备份;保证每次提交都是可靠的提交,因为不可靠提交都在自己本地;快速的分支切换,快速的版本回退,因为都是指针的变动;有了Git,你可以吃后悔药。
远程仓库
虽然,每一个人的电脑都可以作为仓库。但是,我们还是需要一个远程仓库,远程仓库可以作为集中管理,也可以作为备份。当然,远程仓库不是必须的。但是,我们在实际的工作中,都会有一个远程仓库。Gitbub就是一个远程仓库,上面托管了大量的代码。
此处,我们使用公司的远程代码托管服务器,http://10.33.4.202:3000,这个和github类似。
打开10.33.4.202:3000:
可以看到,这是一个Go语言实现的Git服务器,首先注册,如果已有账号就直接登录。
这里我使用公司的邮箱注册,注册完成后就能登录。
这里演示作为公司组织来管理项目,点击个人目录切换处的下拉三角形,切换到组织目录。如果没有组织,就自己创建一个组织。这里我创建一个名叫“hx_web”的组织。
个人目录与组织目录稍微有点差别,多了个链接,我们可以进行管理组织。点击“访问hx_web”。
创建一个新的仓库。
仓库语言,授权许可,自述文档都可以随便选。
创建完成后,我们就看到了熟悉的界面。是不是和github长的一样?如果程序员不熟悉这个界面,那你就不是一个合格的程序员。
好,现在远程仓库已经有了,你现在可以邀请其他成员,或者把仓库地址给他,让大家一起来贡献代码。
SourceTree
首先下载sourceTree,sourcetree官方网站https://www.sourcetreeapp.com/,mac和win都支持,如果没有的朋友,可以找我分享。 我这里使用1.9.10.0版本。
安装sourceTree之前,需要先安装Git。Git的下载地址:https://git-for-windows.github.io。
安装Git之后,在命令行执行Git命令:
如果有上面的显示,表明安装成功,我的Git版本是2.10.0。
然后安装SourceTree。安装完成后,打开,SourceTree为根据你系统的语言来显示中文还是英文,如果是英文,按如下步骤切换到中文:Tools -> General -> Repo setting -> language -> 汉语 -> OK -> 重启。
SourceTree打开后应该是长这样子,我这里项目列表中已经有了三个项目。SourceTree主要是把Git命令进行了可视化,让我们可以直接通过按钮来操作。下面我们就可以使用SourceTree来管理我们的Git项目了。
从远程服务器上克隆项目
从远程仓库获取项目的时候,会要求你输入用户名和密码,这个用户名和密码就是你刚才注册的那个,等待他加载完成。
加载完成后,默认是这样子。我们可以查看该仓库下的项目文件,现在从远程仓库克隆的默认应该有三个文件,点击“在文件资源管理器中打开”。该操作会打开操作系统的文件管理器。
切换到“日志/历史”面板。
修改并提交我的项目
在本地仓库目录下,去新建一个test.txt文件。
保存,然后在sourceTree的"日志/历史"面板中,查看。
现在会提示你有新的未提交的改动。切换到'文件状态'面板。
该面板也有了变化。这里详细的显示了哪些文件有改动,同时有将改动的文件加入暂存stage、不暂存unstage、提交等选项。
实际上,你点工具栏区的“提交”按钮,也会进入到这个面板。这是因为,sourceTree(Git)会要求你先把修改加入暂存区,然后才能提交。因此,你注意到上面的提交区域的按钮是灰色的吗?
这与Git的运行原理和设定有关,Git存储的是修改,版本的变动,只是一个修改到另一个修改的指针的变化。在这里顺便介绍下Git的工作区和暂存区的概念,详细信息请阅读廖雪峰老师的教程。
工作区:就是我们看到的目录,就是我们实际操作的修改的那些项目文件所在的目录。对应我们这里的LearnGit目录。
版本库:工作区中有一个.Git的目录,通常这是一个隐藏目录。前面已经说过这个文件夹,表示它所在的目录是Git管理的仓库。这个文件夹下,存放就是Git的版本库信息,这就是Git的版本库。
暂存区:打开.git目录,Git版本库中有许多文件,其中最重要的就是称为index(或者stage)的暂存区,还有HEAD指针。而其他分支等信息存放在refs文件夹中。
HEAD指针指向的是我们当前所在的分支,此时,指向的就是默认的master分支。因为,我们只有默认的这一个分支。当然它的指向信息我们是看不到的,但是可以通过sourceTree项目列表中,该项目名称下的分支信息来查看当前HEAD指向的分支。
关于HEAD和分支的详细信息这里不再继续介绍了。下面着重看下暂存区:
暂存区是我们存放修改的地方,所有的修改都必须缓存到这里。当我们执行提交命令时,实际上就是把暂存区的内容提交到HEAD对应的分支上。初始时,暂存区应该是空的,当我们把内容提交到暂存区之后,就像上面这样,暂存区有了内容才能执行commit命令。提交之后,暂存区会被清空,等待下一次的暂存和提交。
从工作区添加修改到暂存区的过程使用的是Git add命令。sourceTree提供了可视化操作,我们直接使用stage ALL 或者stage selected来将修改提交到暂存区。
可以将修改添加到暂存区,当然也可以撤销暂存,对应unStage和unstage selected操作。
下面进行我们的第一次提交。把test.txt文件加入到版本库。
提交成功后,“文件状态”面板又恢复干净了。此时切换到“日志/历史”:
可以看到我们的提交成功了,历史图谱也向前推进了一步。此时,我们的文件已经被Git管理起来了,可以进行版本管理了。
但是,此时我们提交成功,仅仅只是向本地的仓库提交成功了,不信你可以去远程仓库看看有没有最新的提交信息。本地仓库,我们只能在本地玩,虽然也能进行版本管理,但是别人看不到,我们还需要推送到远程仓库,让别人也能看到。
服务端推送,可能也会让你输入用户名和密码。但是,这些都只会输入一次,之后就会被sourceTree记住。
推送成功后,到服务端查看。
我们再做一次修改,在text.txt文件中,添加一句“hello world”,然后提交。
将本次修改推送到远程仓库,然后到远程仓库中去查看是否提交成功。
创建Dev分支
实际的开发中,我们不会像上面那样直接在master分支上操作。我们应该建立一个Dev开发分支。
这个和svn的trunk和branch是一样的。我们实际的开发应该在Dev分支上进行。这样做是有理由的:
比如,我们只有一个master分支,现在已经发布了一个新版本1.0。然后新功能1.1版本也在开发中,但是1.0版本发现一个BUG,这时候我们要如何修复BUG呢?肯定不能舍弃现在正在开发的功能,也不能将现在的代码提交,从而影响已经发布出去的版本,这时候Dev分支就起作用了。
我们的master分支,应该作为主分支,这是一个稳定分支,这个分支应该是作为稳定版本发布的分支。我们的所有的开发工作只在Dev分支上操作,当Dev分支开发完成一个新功能时,再合并到master分支,由master分支发布。master分支有BUG时,从master新建一个临时temp分支,在temp修复BUG,然后合并到Master分支,这样master就可以继续发布。 修复的BUG再合并到Dev分支,这样也保证Dev分支上的代码是稳定的。最后再删除temp分支。
如果服务端有Dev分支,那么我们只需要检出Dev分支即可。这里很明显没有,所有我们要新建一个分支,然后把这个Dev分支也推送到服务端,这样别人也能使用这个Dev分支。
创建新分支是非常快速的,就是1秒钟的事。新分支与被分支的那个分支(这里的master)所处的状态是一样的。
创建新分支后,SourceTree(Git)会默认把HEAD指向新创建的分支,并且新分支与原来的分支所处的状态一样。
如果要切换分支,只需要在需要切换的分支上双击即可。这比使用Git命令切换分支要快很多。
然后把Dev分支推送到服务端。
推送成功后,在sourceTree远程选项的origin中,就会多了一个Dev分支,表明服务端也已经有了Dev分支。
到服务端查看是否创建Dev分支成功。
好,现在我们可以在Dev分支下工作了。切换到Dev分支,然后修改源文件,添加一句“New Dev branch”。
添加成功后,sourceTree的文件状态面板中会提示你有新的更改可以提交了。
注意,此时如果我们还未提交就切换到其他分支,这种修改也会带到其他分支的。直接双击master分支:
此时,我在Dev分支的修改还没提交。就是不管有没有加入暂存区,只要还没commit,那么这种修改在切换分支时,就会带到其他分支。
所以,可能你也注意打了,在切换分支时,sourceTree会发出警告,确定你是否切换分支。并且,在警告中通知你,可以选择清除修改。如果我们不清除修改,那么切换后它就会提示你有新的未提交的更改。这显然不是我们想要的结果。因此,我们在切换分支前,要确保修改已经提交。(还有另外一种方法贮藏,这个后面介绍)
切换回Dev分支,并提交。
提交成功后,Dev分支下就是我们最新的修改了。然后切换回master分支,双击master分支,查看源文件。
可见,master分支确实还处在上一个版本中。
删除分支
我们直接从master新建一个temp分支出来,新建分支时,请保证当前的HEAD指向要被分支(master)的那个分支。
新建分支过程不再重复。
新建的分支,应该与它的源分支处于一样的状态。如果不信的话,你可以试试分别切换到master、Dev和temp分支,比较他们的源文件。
删除分支时,要保证HEAD不在要删除的分支上。比如现在,HEAD指向的就是temp分支,我们在temp分支上,右键 -> 删除分支 -> 弹出对话框 -> 确认 ->报错。此时,就会报如下的错误。
把当前分支HEAD指向其他分支,然后执行删除操作。
此时,删除分支成功。
合并分支
在上面,我们的Dev分支已经超前一个版本。此时,我们确定Dev分支上的修改没有问题,并且可以纳入主分支了,那么我们就要合并分支。
合并分支要到目标分支上去操作,比如我们要把Dev分支上的修改合并到master分支,那么我们就要到master分支上去操作。
合并完成后,我们可以检查master分支下的文件,它已经与Dev分支下的修改一样了。然后将master分支推送到服务端。
发布新版本
master合并完之后,就可以发布新版本了,我们使用tag标签来表示版本。Tag其实跟分支类似,只不过它是从某一个提交处建立的一个指针副本,因此它不能进行移动,但是可以添加多个tag,也可以删除。
添加完成后,在标签label中就可以看到新添加的标签了。
还可以将标签推送到服务端。
点击确定之后,在服务端查看版本信息。
贮藏和修复Bug
修复Bug的情况,一般出现在对已发布的版本进行Bug修复。也就是对master分支进行Bug修复。
一般的情况是我们工作在Dev分支,然后要切换到master分支进行Bug修复。前面提到过,在切换分支时,要确保该分支已经提交。如果当前Dev分支可以提交,无疑是最好的选择,但是,如果当前不能提交呢?
我们可以使用贮藏功能。贮藏功能就是对现在的更改进行备份,注意仅仅是对更改进行备份。使用贮藏功能后,会让当前分支的工作区恢复到上一次提交的时候,从而使当前工作区变得干净。这叫做贮藏现场。
怎么贮藏现场?
现场贮藏之后,还可以恢复现场:
贮藏功能又分好几种情况。
出现这种情况的原因是因为,此时demo.txt还没有被Git跟踪管理,所以它默认不会被贮藏,从而一直留在文件系统中。如果我们切换到master分支,这个更改(添加新文件也是更改)会被带到master中,sourceTree也会提醒有未提交的更改,提醒你提交这个文件。
为了避免这个文件在master中会被误提交,从而使该文件出现在不应该出现的版本中,我们应该使用下面这种方法。
删除文件操作也需要加入暂存区才能贮藏现场。实际开发中,我们在贮藏现场时,都应该先把文件加入暂存区(主要是避免有新添加文件或删除文件)。
贮藏现场时,如果勾选了“保留暂存的更改”选项,那么已经加入暂存区的内容都会被保留,并且在切换分支时,暂存区的内容也会被带到其他分支去。从而其他分支也能看到所做的更改。
注意,一般情况下,请不要勾选“保留暂存的更改”。因为,这可能会给你带来冲突,除非特殊情况,你确实需要把修改带过去才这么做。
好,现在了解贮藏功能后,就可以进行master分支Bug的修复了。
多人协作
前面演示的都是一个人开发的情况。下面将演示,多人协作。
首先,从远成仓库新克隆一份代码,取名WorkderB,用来模仿同事B的工作区,之前的LearnGit则用来模仿同事A。
同事B检出Dev分支后,现在Dev分支的代码还停留在helloworld这一步。那是因为同事A还没有把Dev分支推送到服务端。
回到同事A的工作区,把Dev分支也推送到服务端。过程不再演示,然后回到同事B的工作区,看看sourceTree有什么变化。
同事A提交之后,同事B的“拉取”(pull)图标上就会显示一些数字,表示当前有更新,显示的数字,就是服务端超前的版本数。
“拉取”完成之后,Dev分支下的代码应该和服务端,并且和同事A保持一致了。这个过程中,从服务端获取到的代码,和本地的代码,自动进行了合并。
通过“拉取”按钮获取服务端最新的更改时,可能会发生冲突。比如,同事B在自己的工作区中,对test.txt文件进行了修改,同事A也对test.txt文件进行了修改,并且同事A已经提交到服务端了。因此,同事B在提交时,需要先获取服务端最新的更新,然后才能进行提交,同事B通过“拉取”操作获取服务端最新代码后,就可能在test.txt文件发生冲突。然后,需要我们解决冲突之后,再次提交。
Git提供了一个更加可靠的“拉取”操作,来预测上面可能存在的冲突问题。就是sourceTree工具栏中的“获取”按钮。
为了演示“获取”的功能,同事A先进行一次提交,在test.txt文件中增加一句test,提交命令信息为“test”,然后推送到服务端。
同事B,点击“获取”按钮进行获取。
点击“获取”后,弹出框使用默认的选择即可。
点击确定之后,我们来看看sourceTree有什么变化。
解决冲突
冲突发生的情况,主要是同事A与B都对同一文件的同一位置进行了修改。
产生冲突之后,需要我们解决冲突之后才能提交。这里我们使用一个文件比较工具来进行冲突处理。
这里我们配置一个外部文件比较工具,而放弃使用sourceTree默认的diff工具。这个外部文件比较工具是Beyond Compare。
下载安装Beyond Compare。现在beyond compare最新的版本是4.1.9,但是4.x版本都没有破解版,主要是最近beyond compare公司最近抓的严,我现在是直接使用的是试用30天的,买一个激活码差不多280元左右。
冲突解决完毕,就可以把新的提交推送到服务端了。产生的那个垃圾文件直接删除即可(后面会介绍方法来解决这个垃圾文件)。
另外一种会产生冲突的情况。
实际开发中,我们遇到的第二种情况会多一点。因为,我们鼓励每天上班之前都“拉取”(pull)一下,开始开发之前也“拉取”(pull)一下,以免和服务端相差太远。
解决冲突过程会产生一个垃圾文件,这个文件是冲突的备份文件。可以使用如下命令去去掉:
版本回退
换行符兼容
不同平台使用的换行符不一样,导致win或者mac或者Linux下,同样的代码因为换行符问题而错误识别为有新更新,甚至不能通过编译的情况。
这里建议在git项目根目录下,创建一个.gitattributes文件,并且添加一句:
另外,在命令行运行如下命令:
并且,建议把编辑器(IDE)的换行符统一更换成Unix格式。
具体问题,这里不演示。
对于,sourceTree的diff文件时,经常显示/No newline at the end of,这个问题的解决方式是,在末尾添加一个空行,这样方便文件比较。
撤销修改
撤销修改其实很少用到,因为,一般的撤销操作都会被编辑器(或者IDE)取代。当然,这并不是说,git的撤销操作就一定不会用到。sourceTree的撤销操作是“丢弃”。
先说什么时候会用到sourceTree(Git)的撤销修改这个操作,一种情况是,自上次提交后,你对源文件做了很多修改,你想一步就退回到初始状态,就是上次提交之后的状态;另外一种情况是,自上次提交之后,你对源文件作了修改,然后添加到了暂存区,但是还没有提交,然后你又做了很多修改,但是你想回到上一次保存到暂存区时的状态。
从上面可以看到,其实sourceTree或者Git的撤销修改虽然很强大,确不太好使用,直接使用命令的话,会容易混淆命令,使用可视化工具sourceTree,又操作麻烦。所以,如果不是特别需要,请直接使用编辑器的撤销操作。
sourceTree的其他操作
HEAD指针
在前面我一直强调Git只是指针的移动,那么Git的指针到底是什么,它到底如果移动的?
前面已经提到过,Git中的指针叫HEAD,它用来指向当前分支。
我们已经知道,git的每一次提交都会把他串成一条线,这条线是一条时间线,一条时间线就是一条分支。所以,一开始时,我们只有一个master分支,也只有一条时间线,所以,我们的HEAD指向master,然后master又指向我们的提交线。
这里有个概念要弄明白,HEAD指向的并不是提交,而是指向分支,master才是指向提交的,所以,HEAD指向的就是当前分支。由此可见,HEAD和master其实都是指针。
当有新提交时,时间线节点增加一个,master向前移动一步,然后HEAD也会跟着移动。
当创建新分支dev时,实际上是新创建了一个dev指针,但是,dev是从master分出去的,所有,初始时,dev和master在同一个节点。
然后HEAD指向了dev。可以看出,创建一个新分支是多么的简单,仅仅只是创建一个新指针,然后HEAD改变下指向,没有文件的拷贝,所以,它在1s内就能完成新分支的创建。
创建新分支后,HEAD指向了新分支,这时候的提交操作,就对应dev了。
在dev上的提交,仅仅只是dev向前移动了一步,而master还在原来的地方没动。
那么,我们的合并操作又是怎么办的呢?合并操作,其实仅仅只是把master指向了dev当前所在的提交,这还是一个指针移动过程。
所以,git的合并同样非常快速,工作区的内容没改变(其实只有很小的改变,因为要切换回master操作,这会使文件发生一些改变),然后就是指针的移动而已。
删除分支,也非常简单。仅仅只是指针的移除,没有文件系统的改变。
删除分支后,已经合并的master分支并没有任何影响,仅仅只是指针的移除。
从SVN迁移到Git
从SVN迁移到Git,不仅需要源代码迁移,同时我们还希望SVN上的commit信息也能迁移。这里我们使用Subgit工具。
进入subgit的官网,下载subgit的zip包。
下载完成后,解压。然后把解压出来的bin目录添加到环境变量。
然后,新建一个空目录,建立一个authors.txt文件。
authors.txt文件的作用是从svn导出commit信息时,将svn用户信息对应到git用户。它的格式如下:
前面是svn用户的用户名,然后是对应的git用户名和邮箱。我这里已经配好了我们公司的用户信息mapping文件:
上面的邮箱地址,我隐藏掉了,用户可以自己去配。本公司的员工可以来找我分享。
然后在这个目录下执行如下命令:
上面的svnurl请替换成相应的svn地址,ycf.git是我们从svn拷贝过来的源码和一些依赖等文件的存放目录,名字可以自己定义,等待subgit执行完毕。
执行完毕之后,还需要一步操作,修改ycf.git\subgit目录下的authors.txt文件,把我们刚才建立的那个authors.txt文件内容拷贝过来即可。这里主要是为了保证用户信息彻底匹配成功。
然后,还是在刚才那个目录下继续执行如下命令:
这个操作主要是把刚才下载下来的那些文件,初始化为一个干净的本地git仓库。这个仓库的名字叫com.ycf.git。
执行完毕后,现在的com.ycf.git中的内容就是svn中trunk分支的内容了。有了本地仓库,然后将本地仓库与远程仓库链接起来。
建立一个远程仓库,过程不再重复。然后执行如下命令:
这一步,是把当前本地仓库的url设置为远程仓库的地址,从而把本地仓库和远程仓库链接起来。然后将本地仓库的代码推送到远程仓库:
然后查看远程仓库。
已经迁移成功了,再在sourceTree中查看下。
完美,源代码和提交信息都完整的迁移了,enjoy。
参考教程推荐