侧边栏壁纸
博主头像
孔子说JAVA博主等级

成功只是一只沦落在鸡窝里的鹰,成功永远属于自信且有毅力的人!

  • 累计撰写 285 篇文章
  • 累计创建 125 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

一文读懂git与svn的区别,git和svn协同工作实战指南

孔子说JAVA
2022-04-25 / 0 评论 / 0 点赞 / 141 阅读 / 13,627 字 / 正在检测是否收录...

本文从 Git介绍入手,通过 Git 与 SVN 的对比以及 Git 核心概念的了解,从根本上理解 Git 特有的概念(如暂存区和本地仓库),最后结合git-svn让git和svn协同工作,充分掌握 Git 的使用方法和技巧。学习完本文后,你会发现 Git 的存在让我们的许多工作变得更易管理,Git许多神乎其神的设计也会让你从此上瘾,一发不可收拾。

1、Git初了解

1.1 Git 简介

Git是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

  • Git管理的文档(文本文档)允许多人对同一个文档进行修改,各自修改的内容很方便地进行合并,并且可以基于当前内容创建新的分支,在新的分支继续进行修改,最后合并到当前分支上,始终保证文档是最新的。

1.2 Git 核心概念

  • 工作区(Workspace), 是电脑中实际的目录。
  • 暂存区(Index), 类似于缓存区域,临时保存你的改动。
  • 仓库区(Repository),分为本地仓库和远程仓库。

从 SVN 切换到 Git,最难理解并且最不能理解的是暂存区和本地仓库。熟练使用 Git 后,会发现这简直是神设计,由于这两者的存在,使许多工作变得易管理。

1.3 Git 提交代码的步骤

  1. git add从工作区提交到暂存区
  2. git commit从暂存区提交到本地仓库(git commit -a 包括了 git add 命令)
  3. git pushgit svn dcommit从本地仓库提交到远程仓库

一般来说,记住以下命令,便可进行日常工作了(图片来源于网络):

1_20220425160731

2、Git与SVN区别

Git与SVN区别的区别有很多,了解这些有助于你更快的理解Git的相关命令,弄懂他背后的原理非常重要。你可以重点关注你所关心的区别点。

1)Git是分布式的,SVN是集中式的

  • 这是Git 和 其他非分布式的版本控制系统(例如:SVN,CVS等) 最核心的区别。若能掌握这个概念,两者区别基本搞懂大半。因为 Git 是分布式的,所以 Git 支持离线工作,在本地可以进行很多操作,包括接下来将要重磅推出的分支功能。而 SVN 必须联网才能正常工作。

集中式的版本控制系统 都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。

  • Subversion原理上只关心文件内容的具体差异。每次记录有哪些文件作了更新,以及都更新了哪些行的什么内容。
  • 冲突解决是一个提交速度的竞赛:手快者,先提交,平安无事;手慢者,后提交,可能遇到麻烦的冲突解决。
  • 好处:每个人都可以一定程度上看到项目中的其他人正在做些什么。而管理员也可以轻松掌控每个开发者的权限。
  • 缺点:中央服务器的单点故障。

分布式的版本控制系统,客户端并不只提取最新版本的文件快照,而是把原始的代码仓库完整地镜像下来。这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。

  • 这类系统都可以指定和若干不同的远端代码仓库进行交互。籍此,你就可以在同一个项目中,分别和不同工作小组的人相互协作。你可以根据需要设定不同的协作流程。
  • 因为Git在本地磁盘上就保存着所有有关当前项目的历史更新,并且Git中的绝大多数操作都只需要访问本地文件和资源,不用连网,所以处理起来速度飞快。用SVN的话,没有网络或者断开VPN你就无法做任何事情。但用Git的话,就算你在飞机或者火车上,都可以非常愉快地频繁提交更新,等到了有网络的时候再上传到远程的镜像仓库。换作其他版本控制系统,这么做几乎不可能,抑或是非常麻烦。
  • Git 有更多的工作模式可以选择,远非 Subversion可比

2)Git复杂概念多,SVN简单易上手

  • 所有同时掌握 Git 和 SVN 的开发者都必须承认,Git 的命令实在太多了,日常工作需要掌握add,commit,status,fetch,push,rebase等,若要熟练掌握,还必须掌握rebasemerge的区别,fetchpull的区别等,除此之外,还有cherry-picksubmodulestash等功能,仅是这些名词听着都很绕。
  • 在易用性方面,SVN 简单易上手,对新手很友好。但是从另外一方面看,Git 命令多意味着功能多,若我们能掌握大部分 Git 的功能,体会到其中的奥妙,会发现再也回不去 SVN 的时代了。

3)Git版本库和工作区如影随形,SVN是分离的

Subversion的工作区和版本库是截然分开的,而Git的工作区和版本库是如影随形的。

SVN

  • Subversion 的工作区和版本库物理上分开:Subversion的版本库和工作区是存储在不同路径下,一般是在不同的主机中,Subversion的企业级部署中,版本库在服务器上,只能通过 https, http, svn 等协议访问,而不能直接被用户接触到。
  • Subversion的工作区是一份版本库在某个历史状态下的快照,如:版本库最新的数据检出到工作区。
  • Subversion的工作区中每一个目录下都包含一个名为 .svn 的控制目录(隐藏的目录),该目录的作用是:① 标识工作区和版本库的对应关系。② 包含一份该子目录下检出文件的原始拷贝。当文件改动的差异比较或者本地改动的回退时,可以直接参考原始拷贝而无须通过网络访问远程版本库。

Git

  • Git 的版本库和工作区在同一个目录下,工作区的根目录有一个 .git 的子目录,这个名为 .git 的目录就是版本库本身,它是 Git 用来保存元数据和对象数据库的地方。该目录非常重要,每次克隆镜像仓库的时候,实际拷贝的就是这个目录里面的数据。所以千万要小心删除这个文件。
  • 版本库可以脱离工作区而存在,成为 bare(赤裸)版本库。可以用 –bare 参数来创建。但是工作区不能脱离版本库而存在,即工作区的根目录下必须有一个名为 .git 的版本库克隆文件。
  • Git 的工作区中只在工作区的根目录下有一个 .git 目录,此外再无任何控制目录。Git 工作区下唯一的 .git 目录是版本库,并非 .svn 的等价物,如果删除了 .git 目录,而又没有该版本库的其他镜像(克隆)的话,你就破坏了整个历史,版本库也永远的失去了。
  • Git 在本地的 .git 版本库,提供了完全的改动历史。除了和其他人数据交换外,任何版本库相关的操作都在本地完成,更多的本地操作,避免了冗长的网络延迟,大大节省了时间。例如:查看 log,切换到任何历史版本等操作都无须连接网络。

Git如何保证安全

本地创建一个Git库,因为工作区和库是在同一个目录中,如果工作区删除了,或者所在的磁盘分区格式化了,数据不是全都没有了么?其实我们可以这样做:

  • ① 在一个磁盘分区中创建版本库(最好是用 –bare 参数创建),然后在另外的磁盘分区中克隆一个新的作为工作区。在工作区的提交要不时的PUSH到另外分区的版本库,这样就实现了本地的数据镜像。你甚至可以在本地创建更多的版本库镜像,安全性要比Subversion的一个库加上一个工作区安全。
  • ② 另一个办法:把你的版本库共享给他人,当他人克隆了你的版本库时,你就拥有了一个异地备份。

4)Git存储元数据,SVN存储文件

  • Git 把内容按元数据方式存储,而 SVN 是按文件存储。
  • 所有的资源控制系统都是把文件的元信息隐藏在一个类似 .git.svn.cvs 等的文件夹里。
  • Git 的内容完整性要优于SVN,Git 的内容存储使用的是 SHA-1 的哈希算法,这能确保代码内容的完整性,确保在遇到磁盘故障和网络问题时降低对版本库的破坏。

5)Git分支廉价,SVN分支昂贵

在版本管理里,分支是很常使用的功能。在发布版本前,需要发布分支,进行大需求开发,需要 feature 分支,大团队还会有开发分支,稳定分支等。在大团队开发过程中,常常存在创建分支,切换分支的需求。

  • Git 分支是指针指向某次提交,而 SVN 分支是拷贝的目录(即版本库中的另外一个目录)。这个特性使 Git 的分支切换非常迅速,且创建成本非常低。
  • Git 有本地分支,SVN 无本地分支。在实际开发过程中,经常会遇到有些代码没写完,但是需紧急处理其他问题,若我们使用 Git,便可以创建本地分支存储没写完的代码,待问题处理完后,再回到本地分支继续完成代码。

6)Git全球版本号,SVN全局版本号

SVN的全局版本号和CVS的每个文件都独立维护一套版本号相比,是一个非常大的进步。在看似简单的全局版本号的背后,是Subversion提供对于事物处理的支持,每一个事物处理(即一次提交)都具有整个版本库全局唯一的版本号。

  • SVN 的版本号是连续的,可以预判下一个版本号,因为 subversion 是集中式版本控制,很容易实现版本号的连续性。而 Git 的版本号则不是。

Git的版本号则更进一步,版本号是全球唯一的。Git 对于每一次提交,通过对文件的内容或目录的结构计算出一个 SHA-1 哈希值,得到一个40位的十六进制字符串,Git将此字符串作为版本号。

  • Git 采用 40 位长的哈希值作为版本号,而不是靠文件名。每个人的提交都是各自独立完成的,没有先后之分(即使提交有先后之分,也由于PUSH/PULL的方向和时机而不同)。Git 的版本号虽然不连续,但是是有线索的,即每一个版本都有对应的父版本(一个或者两个),进而可以形成一个复杂的提交链。
  • 使用哈希值作版本号的好处就是对于一个分布式的版本控制系统,每个人每次提交后形成的版本号都不会出现重复。另一好处是保证数据的完整性,因为哈希值是根据内容或目录结构计算出来的,所以我们还可以据此来判断数据内容是否被篡改。
  • Git 的版本号简化:Git 可以使用从左面开始任意长度的字串作为简化版本号,只要该简化的版本号不产生歧义。一般采用7位的短版本号(只要不会出现重复的,你也可以使用更短的版本号)。

7)Git全部检出,SVN部分检出

Subversion可以将整个库检出到工作区,也可以将某个目录检出到工作区。对于要使用一个庞大、臃肿的版本库的用户来说,部分检出是非常方便和实际的。但是Git只能全部检出,不支持按照目录进行部分检出。

SVN的部分检出

  • 在SVN中,从仓库checkout的一个工作树,每个子目录下都维护着自己的 .svn目录,记录着该目录中文件的修改情况以及和服务器端仓库的对应关系。所以SVN可以checkout部分路径下的内容(部分检出),而不用checkout整个版本库或分支。
  • Subversion 有一条命令:svn export ,可以将 subversion 版本库的一个目录下所有内容导出到指定的目录下。Subversion 需要 svn export 命令是因为该命令可以导出一个干净的目录,即不包含 .svn 目录(包含配置文件和文件原始拷贝)。

Git的检出

  • Git 没有部分检出,这并不是说只有将整个库克隆下来才能查看文件。有很多 git 工具,提供直接浏览git库的功能,例如 gitweb, trac 的 git 版本库浏览, redmine 的 git 版本库浏览。
  • Git-submodule 可以实现版本库的模块化:Git 通过子模块处理这个问题。子模块允许你将一个Git 仓库当作另外一个Git仓库的子目录。这允许你克隆另外一个仓库到你的项目中并且保持你的提交相对独立。
  • Git 为什么没有实现 svn export 的功能?由于git的本地仓库信息完全维护在project根目录的 .git 目录下,(不像svn一样,每个子目录下都有单独的 .svn 目录)。所以,只要clonecheckout然后删除.git目录就可以了。

8)更新操作

  • 在SVN中,因为只有一个中心仓库,所以所谓的远程更新,也就是svn update ,通过此命令来使工作区和版本库保持同步。

  • 对于git来说,别人的改动是存在于远程仓库上的,所以 git checkout 命令尽管在某些功能上和svn中的 update 类似(例如取仓库特定版本的内容),但是在远程更新这一点上,还是不同的,不属于 git checkout 的功能涵盖范围。 Git使用 git fetchgit pull 来完成远程更新任务,fetch 操作只是将远程数据库的object拷贝到本地,然后更新 remotes head的refsgit pull 的操作则是在 git fetch 的基础上对当前分支外加 merge 操作。

8)提交操作

对于SVN来说,由于是中心式的仓库管理形式,所以并不存在特殊的远程提交的概念,所有的 commit 操作都可以认为是对远程仓库的更新动作。在工作区中对文件进行添加、修改、删除操作要同步到版本库,必须使用 commit 命令。

  • add 命令,是将未标记为版本控制状态的文件标记为添加状态,并在下次提交时入库。
  • delete 命令,是通过SVN来删除文件,并在下次提交后有效。
  • Subversion 有提交列表功能,即将某些文件加入一个修改列表,提交可以只提交处于该列表的文件。

Git 管理项目时,文件在三个工作区域中流转:Git 的本地数据目录,工作目录以及 暂存区域(stage) 。暂存区域(stage)是介于 workcopy 和 版本库 HEAD 版本的一种中间状态。

  • 所谓的暂存区域只不过是个简单的文件,一般都放在git 目录中。有时候人们会把这个文件叫做索引文件,不过标准说法还是叫暂存区域。
  • 要将一个文件纳入版本管理的范畴,首先是要用 git add 将文件纳入 stage 的监控范围,只有更新到 stage 中的内容才会在 commit 的时候被提交。
  • 文件本身的改动并不会自动更新到stage中,每次的任何修改都必须重新更新到 stage 中去才会被提交。
  • 工作区的文件改动(新增文件,修改文件,删除文件),必须用 git add 或者 git rm 命令标识,使得改动进入 stage,提交只对加入 stage 的改动进行提交。
  • 如果一个文件改动加入 stage 后再次改动,则后续改动不改变 stage。即该文件的改动有两个状态,一个是标记到 stage 中并将在下次提交时入库的改动,另外的后续改动则不被提交,除非再次使用 git add 命令将改动加入到 stage 中。
  • Git的stage让你在提交的时候清楚的知道git将要提交哪些改动。除非提交的时候使用 -a 参数(不建议使用)。
  • 可以从文件所处的位置来判断其状态:如果是git目录中保存着的特定版本文件,就属于已提交状态;如果作了修改并已放入暂存区域,就属于已暂存状态;如果自上次取出后,作了修改但还没有放到暂存区域,就是已修改状态,如果取出后未进行修改则是未修改状态
  • 在git中,因为有本地仓库和remote仓库之分,所以也就区别于 commit 操作,存在额外的 push 命令,用于将本地仓库的数据更新到远程仓库中去。git push 可以选择需要提交的、更新的分支以及制定该分支在远程仓库上的名字。

9)分支和里程碑

几乎每一种版本控制系统都以某种形式支持分支。使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作。在很多版本控制系统中,这是个昂贵的过程,常常需要创建一个源代码目录的完整副本,对大型项目来说会花费很长时间。

轻量级分支/里程碑的含义是,创建分支/里程碑的复杂度是o(1),不会因为版本库的愈加庞大而变得缓慢。在CVS中,创建分支的复杂度是o(n)的,导致大的版本库的的分支创建非常缓慢。

  • Svn 创建分支,其实就是创建了一个新的文件夹(目录)并拥有实际的文件的。相当于拷贝了一份源文件。如果一个成员创建了一个分支,将会影响所有的人。那么所有的人都将拥有同样的分支。

  • Git创建分支,并没有创建文件夹,你甚至看不到任何的改变。用户可以在同一个文件夹中,快速的切换不同的分支。创建一个分支,就是多了一个索引文件,记录这个分支的变化。占用很小的空间。每个分支,都是独立的,在这个分支里想做什么都可以,对其他分支没有一点影响。

既然这样,大家就应该能想象得到。一个svn项目创建了几个分支,就相当于把源码复制拷贝了多少次。而git项目创建几个分支,仅仅是多了几个索引,占用很小的空间。所以在git管理项目中,我们可以创建任意多的分支,(开支小)。所以,clone新的项目的时候,git也比svn项目快的太多了。

SVN的分支/里程碑

  • Subversion轻量级分支和里程碑的实现是通过svn cp命令,即带历史的拷贝就是创建快速创建分支和里程碑的秘籍。
  • Subversion的版本库有特殊的设计,当你复制一个目录,你不需要担心版本库会变得十分巨大—Subversion并不是拷贝所有的数据,相反,它只是建立了一个已存在目录树的入口。这种“廉价的拷贝”就是创建分支/里程碑是轻量级的原因。
  • 由于Svn的分支和标签是来自目录拷贝,约定俗成是拷贝在 branches/和tags/目录下。所谓分支,tag等概念都只是仓库中不同路径上的一个对象或索引而已,和普通的路径并没有什么本质的区别,谁也不能阻止在一个提交中同时修改不同分支中的数据。
  • 里程碑是对某个历史提交所起的一个别名,作为历史的标记,是不应该被更改的。svn的里程碑要建立到 tags/目录下,要求不要在tags/下的里程碑目录下进行提交。但是谁也阻止不了对未进行权限控制的里程碑的篡改。

Git 的轻量级分支和里程碑

  • Git中的分支实际上仅是一个包含所指对象校验和(40个字符长度SHA-1 哈希值)的文件,所以创建和销毁一个分支就变得非常廉价。说白了,新建一个分支就是向一个文件写入41个字节(版本号外加一个换行符)那么简单,自然速度就很快了。 Git的实现与项目复杂度无关,它永远可以在几毫秒的时间内完成分支的创建和切换。这和大多数版本控制系统形成了鲜明对比。
  • Git的分支是完全隔离的,而Subversion则没有。分支本来就应该是相对独立的命名空间,一个提交一般只能发生在一个分支中。在Git中,其内部的对象层级依赖关系或许和SVN类似,但是其工作树的视图表现形式和SVN完全不同。工作树永远是一个完整的分支,不同的分支由不同的head索引去构建,你不可能在工作树中同时获得多个分支的内容。
  • Git使用的标签有两种类型:轻量级的(lightweight)和含附注的(annotated)。① 轻量级标签就像是个不会变化的分支,实际上它就是个指向特定提交对象的引用。② 而含附注标签,实际上是存储在仓库中的一个独立对象,它有自身的校验和信息,包含着标签的名字,电子邮件地址和日期,以及标签说明,标签本身也允许使用GNU Privacy Guard (GPG) 来签署或验证。
  • Git的里程碑是只读的,Git完全遵守历史不可更改这一时空法则。用户不能向git的里程碑中提交,否则里程碑就不是标记,而成了一个分支。当然Git允许用户删除里程碑再重新创建指定到不同历史提交。

10)多分支间的切换

  • SVN中提供了一个功能 switch,使用 switch可以在同一个工作树上,在不同的分支中进行切换。
  • Git在分支中进行切换使用的命令是 checkout

11)分支与合并

Git 和 Svn 的分支实现机制完全的不同,这也直接导致了 SVN 在分支合并中困难重重。尽管在 SVN 1.5 之后,通过 svn:mergeinfo 属性引入了合并追踪机制,但是在特定情况下,合并仍会出现很多困难。

SVN的分支合并

  • 当你在一个分支上工作数周或几个月之后,主干的修改也同时在进行着,两条线的开发会区别巨大,当你想合并分支回主干,可能因为太多冲突,已经无法轻易合并你的分支和主干的修改。
  • 另一个问题,Subversion不会记录任何合并操作,当你提交本地修改,版本库并不能判断出你是通过svn merge还是手工修改得到这些文件。所以你必须手工记录这些信息(说明合并的特定版本号或是版本号的范围)。

要解决以上的问题只有通过有规律的将主干合并到分支来避免,制定这样一个政策:每周将上周的修改合并到分支,注意这样做时需要小心,你必须手工记录合并的过程,以避免重复的合并,你需要小心的撰写合并的日志信息,精确的描述合并包括的范围。这样做看起来有点像是胁迫。

  • SVN 的版本号是连续的版本号。每一次新的提交都会版本号+1 ,而无论这个提交是在哪个分支中进行的。SVN一个提交可以同时修改不同分支的不同文件,因为提交命令可以在 /trunk, /branches, /tags 的上一级目录执行。
  • SVN 的提交是单线索的,每一个提交(最原始的提交0除外)都只有一个父节点(版本号小一个的提交节点)。SVN 的提交链只有一条,仅从版本号和提交说明,我们无法获得分支图
  • SVN 的分支图在某些工具(如乌龟SVN)可以提供,那是需要对提交内容进行检查,对目录拷贝动作视为分支,对 svn:mergeinfo 的改动视为合并,但这会由于目录管理的灵活性,导致千奇百怪的分支图表。

Git的分支合并

在 git 版本库中创建分支的成本几乎为零,所以,不必吝啬多创建几个分支。当第一次执行 git-init 时,系统就会创建一个名为 master 的分支。 而其它分支则通过手工创建。下面列举一些常见的分支策略。

  1. 创建一个属于自己的个人工作分支,以避免对主分支 master 造成太多的干扰,也方便与他人交流协作。
  2. 当进行高风险的工作时,创建一个试验性的分支,扔掉一个烂摊子总比收拾一个烂摊子好得多。
  3. 合并别人修改的时候,最好创建一个临时的分支用来合并,合并完成后再“fetch”到自己的分支。

Git分支相关的操作命令:

查看分支列表:git branch
创建一个名为“dev”的分支:git branch dev
切换到dev分支:git checkout dev
创建并切换到dev分支:git checkout -b dev
合并dev分支:git merge dev
删除dev分支:git branch -d dev

12)撤消操作

  • 在Subversion中一旦完成向服务器的数据提交,你就没有办法再从客户端追回,只能在后续的提交中修正(回退或者修改)等。因为Subversion作为集中式的版本控制,不能允许个人对已提交的数据进行篡改。Subversion具有一个非常重要的特性就是它的信息从不丢失,即使当你删除了文件或目录,它也许从最新版本中消失了 ,但这个对象依然存在于历史的早期版本中。

  • Git则不同,Git是分布式版本控制系统,代码库是属于个人,允许任意修改。Git通过对提交建立数字摘要来保证提交的唯一性和不可更改性,通过版本库在多人之间的多份拷贝来保障数据的安全性。Git可以丢弃最新的一个或几个提交,使用 git reset –hard命令可以永远丢弃最新的一个或者几个提交。

13)提交说明的修改

提交后如果对提交说明不满意,如何实现对提交说明的修改:

Git可以使用命令 git commit –amend 修改提交说明:

  1. Git可以修改最后一次提交说明,并不是说不能修改历史版本的提交说明,只是修改最后一个版本提交说明拥有最简单的命令;
  2. Git修改提交说明,会改变提交的commit-id。即修改提交说明后,将产生一个新的提交;
  3. Git可以通过git reset –hard ,git commit –amend,git rebase onto 等命令来实现对历史提交的修改;
  4. 使用stg工具可以更为简单的修改历史提交的提交说明,包括提交内容。

Subversion也可以修改提交说明,是通过修改提交的svn:log版本属性实现的:

  1. 不但可以修改最后一次提交的说明,并且可以修改历史提交的提交说明;
  2. Subversion修改提交说明是不可逆的操作,可能会造成说明被恶意修改;
  3. Subversion缺省关闭修改提交说明的功能。管理员在设置了提交说明更改的邮件通知后,才可以打开该功能。

14)修改和重构历史提交

  • Git可以修改和重构历史提交:使用Git本身的 reset 以及 rebase 命令可以修改或者重整/重构历史提交,非常灵活。使用强大的 stg 可以使得历史提交的重构更为简洁,如果您对 stg 或者 Hg/MQ 熟悉的话。
  • Subversion 修改历史提交,只能由管理员完成。Subversion 是集中式版本控制系统,从客户端一旦完成提交,就没有办法从客户端撤销提交。但是管理员可以在服务器端完成提交的撤销和修改,但是操作过程和代价较大。

15)权限管理

Subversion通过对文件目录授权来实现权限管理,子目录默认继承父目录的权限。但是也有缺憾,即权限不能在分支中继承,不能对单个文件授权。例如为 /trunk 及其子目录的授权,不能继承到分支或者标签中相应的目录下。

Git 的授权做不到Subversion那样精细。Git的授权模型只能实现非零即壹式的授权,要么拥有全部的写权限,要么没有写权限,要么拥有整个版本库的读权限,要么禁用。

从技术上将,Git可能永远也做不到类似SVN的路径授权(读授权):

  • 如果允许按照路径授权,则各个克隆的关系将不再是平等的关系,有的内容多,有的内容少,分布式的理念被破坏
  • 如果只有部分路径可读,则克隆出来的提交和原始提交的提交ID可能不同。因为提交ID是和提交内容有关的,克隆中提交的部分内容被丢弃,势必提交的ID也要重新计算
  • 允许全部代码可读,只允许部分代码可写,在版本控制的管理下,是没有多大实际意义的,而且导致了提交的逻辑上的不完整。

那么有什么办法来解决授权的问题?

  1. 公司内部代码开放。即代码在公司内部,对项目组成员一视同仁的开放。
  2. 公司对代码库进行合理分解,对每个代码库分别授权。即某个代码库对团队成员完全开放,对其它团队完全封闭。
  3. 公司使用Subversion做集中式的版本控制,个人或团队使用 Git-svn。这样在无法改变公司版本控制策略时,程序员可以采用的变通之法。
  4. Git服务器的部署实际上可以使用钩子对分支和路径进行写授权,即可以控制谁能够创建分支,能够写特定文件。

3、Git与SVN优缺点比较

3.1 SVN优缺点

SVN更适用于项目管理。一个研发队伍的成员正常包括:需求分析、设计、美工、程序员、测试、实施、运维,每个成员在工作中都有产出物,包括了文档、设计代码、程序代码,这些都需要按项目集中进行管理的。SVN能清楚的按目录进行分类管理,使项目组的管理处于有序高效的状态。

优点:

  • 管理方便,逻辑明确,符合一般人思维习惯。
  • 易于管理,集中式服务器更能保证安全性。
  • 代码一致性非常高。
  • 适合开发人数不多的项目开发。

缺点:

  • 服务器压力太大,数据库容量暴增。
  • 如果不能连接到服务器上,基本上不可以工作,如果服务器不能连接上,就不能提交,还原,对比等等。
  • 不适合开源开发(开发人数非常非常多,但是Google app engine就是用svn的)。但是一般集中式管理的有非常明确的权限管理机制(例如分支访问限制),可以实现分层管理,从而很好的解决开发人数众多的问题。

3.2 Git优缺点

Git更适用于代码管理。

优点:

  • 适合分布式开发,强调个体。
  • 公共服务器压力和数据量都不会太大。
  • 速度快、灵活。
  • 任意两个开发者之间可以很容易的解决冲突。
  • 离线工作。

缺点:

  • 学习周期相对而言比较长。
  • 不符合常规思维。
  • 代码保密性差,一旦开发者把整个库克隆下来就可以完全公开所有代码和版本信息。

4、git-svn让git和svn协同工作

若服务器使用的 SVN,但是本地想要体验 Git 的本地分支,离线操作等功能,可以使用 Git-SVN 功能。

  • 支持去中心化,是Git与生俱来的特性,它在本地保留了从中心服务器clone出来的源码库的全部信息,这样,你在本地修改完代码后便可以直接提交到本地 的代码版本库中。本地代码的备份和版本管理的问题就这样被Git轻而一举的就解决了。而本地源码库与SVN中心源码库的同步操作则是由Git提供的 git-svn 工具来完成的。

1_20220425110325

4.1 Git-SVN

# 下载一个 SVN 项目和它的整个代码历史,并初始化为 Git 代码库
$ git svn clone -s [repository]
# 查看当前版本库情况
$ git svn info
# 取回远程仓库所有分支的变化
$ git svn fetch
# 取回远程仓库当前分支的变化,并与本地分支变基合并
$ git svn rebase 
# 上传当前分支的本地仓库到远程仓库
$ git svn dcommit
# 拉取新分支,并提交到远程仓库
$ svn copy [remote_branch] [new_remote_branch] -m [message]
# 创建远程分支对应的本地分支
$ git checkout -b [local_branch] [remote_branch]

4.2 初始化

以下命令均适用于 Git 与 Git-SVN。

# 在当前目录新建一个Git代码库
$ git init
# 下载一个项目和它的整个代码历史 [Git only]
$ git clone [url]

4.3 配置

  1. Git 用户的配置文件位于 ~/.gitconfig
  2. Git 单个仓库的配置文件位于 ~/$PROJECT_PATH/.git/config
# 列举所有配置
$ git config -l
# 为命令配置别名
$ git config --global alias.co checkout
$ git config --global alias.ci commit
$ git config --global alias.st status
$ git config --global alias.br branch
# 设置提交代码时的用户信息
$ git config [--global] user.name "[name]"
$ git config [--global] user.email "[email address]"

4.4 增删文件

  • 把文件名 file1 添加到 .gitignore 文件里,Git 会停止跟踪 file1 的状态。
# 添加当前目录的所有文件到暂存区
$ git add .
# 添加指定文件到暂存区
$ git add <file1> <file2> ...
# 添加指定目录到暂存区,包括其子目录
$ git add <dir>
# 删除工作区文件,并且将这次删除放入暂存区
$ git rm [file1] [file2] ...
# 停止追踪指定文件,但该文件会保留在工作区
$ git rm --cached [file]
# 改名文件,并且将这个改名放入暂存区
$ git mv [file-original] [file-renamed]

4.5 分支

# 列出所有本地分支
$ git branch
# 列出所有本地分支和远程分支
$ git branch -a
# 新建一个分支,但依然停留在当前分支
$ git branch [branch-name]
# 新建一个分支,并切换到该分支
$ git checkout -b [new_branch] [remote-branch]
# 切换到指定分支,并更新工作区
$ git checkout [branch-name]
# 合并指定分支到当前分支
$ git merge [branch]
# 选择一个 commit,合并进当前分支
$ git cherry-pick [commit]
# 删除本地分支,-D 参数强制删除分支
$ git branch -d [branch-name]
# 删除远程分支
$ git push [remote] :[remote-branch]

4.6 提交

# 提交暂存区到仓库区
$ git commit -m [message]
# 提交工作区与暂存区的变化直接到仓库区
$ git commit -a
# 提交时显示所有 diff 信息
$ git commit -v
# 提交暂存区修改到仓库区,合并到上次修改,并修改上次的提交信息
$ git commit --amend -m [message]
# 上传本地指定分支到远程仓库
$ git push [remote] [remote-branch]

4.7 拉取

# 下载远程仓库的所有变动 (Git only)
$ git fetch [remote]
# 显示所有远程仓库 (Git only)
$ git remote -v
# 显示某个远程仓库的信息 (Git only)
$ git remote show [remote]
# 增加一个新的远程仓库,并命名 (Git only)
$ git remote add [remote-name] [url]
# 取回远程仓库的变化,并与本地分支合并,(Git only), 若使用 Git-SVN,请查看第三节
$ git pull [remote] [branch]
# 取回远程仓库的变化,并与本地分支变基合并,(Git only), 若使用 Git-SVN,请查看第三节
$ git pull --rebase [remote] [branch]

4.8 撤销

# 恢复暂存区的指定文件到工作区
$ git checkout [file]
# 恢复暂存区当前目录的所有文件到工作区
$ git checkout .
# 恢复工作区到指定 commit
$ git checkout [commit]
# 重置暂存区的指定文件,与上一次 commit 保持一致,但工作区不变
$ git reset [file]
# 重置暂存区与工作区,与上一次 commit 保持一致
$ git reset --hard
# 重置当前分支的指针为指定 commit,同时重置暂存区,但工作区不变
$ git reset [commit]
# 重置当前分支的HEAD为指定 commit,同时重置暂存区和工作区,与指定 commit 一致
$ git reset --hard [commit]
# 新建一个 commit,用于撤销指定 commit
$ git revert [commit]
# 将未提交的变化放在储藏区
$ git stash
# 将储藏区的内容恢复到当前工作区
$ git stash pop

4.9 查询

# 查看工作区文件修改状态
$ git status 
# 查看工作区文件修改具体内容 
$ git diff [file]
# 查看暂存区文件修改内容
$ git diff --cached [file] 
# 查看版本库修改记录
$ git log 
# 查看某人提交记录
$ git log --author=someone 
# 查看某个文件的历史具体修改内容
$ git log -p [file] 
# 查看某次提交具体修改内容
$ git show [commit]
0

评论区