了解SVN和Git之间的分支差异


44

我是SVN的用户,现在我正在学习Git。

在SVN中,我通常在本地计算机上签出一个仓库,其中包括项目中的所有分支,并且我曾经为我感兴趣的分支选择文件夹并在其中工作。

我发现使用Git有所不同。

目前,我正在克隆一个仓库,并使用gitk克隆一个特定的分支。

项目文件夹仅包含该分支的内容,而我看不到SVN中的所有分支,这对我来说有点困惑。

我找不到使用Git查看本地存储库中所有分支的简便方法。

  • 我想知道我描述的Git流程是否是“标准”的,是否有些正确,或者我缺少一些东西。

  • 另外,我想知道如何处理需要同时在两个分支上工作的流程,以防万一,例如,我需要在master上进行修补,但还要保留另一个分支的内容。

  • 建议使用什么名称约定来制作包含从Git中的仓库中克隆的分支的文件夹myproject-branchname


8
有趣的是-通常使用SVN,您只会签出您正在处理的主干或分支,但我明白您的意思。
HorusKol

20
您在SVN中破坏了工作流程,现在您尝试将其镜像到Git(即使良好的SVN工作流程也仅部分适用于Git)。最好的解决方案- 忘记所有SVN习惯,从头开始在Git中
Lazy Badger

6
git clone比起。更像svnadmin hotcopysvnrdump+ 。有了,你不要求从点点滴滴信息库; 您可以复制整个存储库并在本地使用它,并在需要时将更改推回“源”存储库。Git和Subversion使用两个完全不同的模型进行源代码控制。svnadmin loadsvn checkoutgit
chepner,2017年

1
关于此修补程序,请考虑使用git-flow
Bakuriu

5
@LazyBadger如果可以促进开发并提供价值,那么它就不会中断工作流程。没有使用分支的正确方法。
Dietbuddha

Answers:


67

我是SVN的用户,现在我正在学习GIT。

欢迎来到帮派!

SVN再教育

在SVN中,我通常[...]

等一下 尽管CVS和SVN以及其他传统的(即集中式)版本控制系统实现了(大部分)与现代(即分布式)版本控制系统(例如Mercurial和Git)相同的目的,但从头开始学习Git会比从头开始学习更好尝试将您的SVN工作流程转移到Git。

Joel Spolsky(Stack Exchange的一位创始人之一)的http://hginit.com在archive.org上查看)是一本有关水墨学而不是Git的教程,但它是第零章,“ Subversion Re-education”是对于从SVN切换到任何分布式版本控制系统的人们很有用,因为它告诉您必须(暂时)取消学习(或如Git用户可能所说的那样stash离开)什么SVN概念才能将您的头缠绕在分布式版本控制系统的概念以及与之配合使用的惯用工作流程。

因此,您可以阅读第零章,并且大多只是将“ Mercurial”一词替换为“ Git”,从而为Git做好了自己的准备。

精美印刷

(您现在可以略过此内容。)尽管Mercury和Git彼此之间的相似度远高于SVN,但它们之间在概念上有所不同,因此“ Subversion Re-Education”中的某些陈述和建议在技术上将是错误的用“ Git”替换“ Mercurial”时:

  • 就像Subversion一样,Mercurial内部跟踪并存储变更集,而Git内部跟踪并存储修订(即目录树内容的状态)。但是, 除了Subversion之外, Git通过分别查看每个涉及的分支与一个共同的祖先修订版(真正的三点合并)之间的差异来执行合并,因此结果与Mercurial的结果几乎相同:合并更容易且错误更少-比SVN中更容易出现。
  • 虽然您可以通过克隆存储库在Git中进行分支(如通常的做法),但在Git存储库中创建新分支更为普遍。(这是因为Git分支只是简单地(移动)指向修订的指针,而Mercurial分支是应用于每个修订的永久标签。这些永久标签通常是不需要的,因此Mercurial工作流通常通过克隆完整的存储库以进行分散开发来工作。)

在SVN中,所有内容都是一个目录(但是您不必一定要这样处理)

但是我一直在打扰你。你在说什么

在SVN中,我通常在本地计算机上签出一个仓库,其中包括项目中的所有分支,并且我曾经为我感兴趣的分支选择文件夹并在其中工作。

如果那意味着您已经签出SVN信息库的根文件夹(trunk或与一个或多个分支相对应的其他任何文件夹,例如,在常规SVN repo布局中branches包含所有非中继分支的文件夹),我敢说,你可能已经使用SVN错误(ISH),或至少被滥用了一下事实,树干,树枝和标签都与目录的折叠成一个单一的(虽然分层)一起命名空间的修订/代码库。

虽然可能很想并行更改几个SVN分支,但这是AFAIK而不是打算使用SVN的方式。(尽管我不确定像这样工作的具体弊端。)

在Git中,只有目录是目录

Git存储库的每个克隆本身就是Git存储库:默认情况下,它将获取原始存储库历史的完整副本,包括所有修订版,分支和标签。但这将保留您的所有方式:Git将其存储在基于文件的各种数据库中,该数据库位于存储库的根文件夹的隐藏.git/子文件夹中。

但是,您在存储库文件夹中看到的非隐藏文件是什么?

当您git clone使用存储库时,Git会执行几项操作。大致:

  1. 它创建目标文件夹,并在其中创建.git/带有“数据库” 的子文件夹。
  2. 它传输原始存储库数据库的引用(标记,分支等),并在新数据库中创建它们的副本,为它们提供经过修改的名称,将其标记为“远程”引用。
  3. 它将这些引用所指向的所有修订(即文件树状态)以及这些修订所指向的所有修订(直接或间接地)(其父母和祖先)都转移到新数据库并存储它们,以便新的远程引用实际上指向新存储库中可用的内容。
  4. 它创建一个本地分支,该分支跟踪与原始存储库的默认分支(通常为master)相对应的远程修订。
  5. 它签出该本地分支。

最后一步意味着Git查找该分支所指向的修订版,并将存储在那里的文件树解压缩(数据库使用某种压缩和重复数据删除方法)到存储库的根文件夹中。该根文件夹及其所有子文件夹(不包括特殊.git子文件夹)被称为存储库的“工作副本”。在这里,您可以与当前已检出的修订/分支的内容进行交互。它们只是普通的文件夹和文件。但是,要与存储库本身(修订和参考的“数据库”)交互,请使用git命令。

查看Git分支并与Git分支进行交互

目前,我正在克隆一个仓库,并使用gitk克隆一个特定的分支。

gitk我的版本无法克隆存储库。它只能查看回购历史记录并创建分支并签出分支。另外,没有“克隆”分支。您只能克隆存储库。

您是说要使用克隆仓库git clone ...,然后使用gitk检出分支?

项目文件夹仅包含该分支的内容,而我看不到SVN中的所有分支,这对我来说有点困惑。

[...]

  • 我想知道我描述的git进程是否为“标准”,以及某些正确性[...]

是的,这很标准:

  • 使用克隆一个仓库 git clone ...
  • 签出您要git checkout ...使用的分支或使用诸如gikt

我找不到一种简单的方法来使用GIT查看本地存储库中的所有分支。

  • [...]或我错过了smt。

也许:

  • 您可以列出本地分支机构 git branch
  • 您可以列出远程分支机构git branch -r或所有分支机构git branch -a
  • 您可以gitk通过以下方式调用它来查看完整的历史记录(本地存储库知道的所有分支标签等)

    gitk --all
    

如何并行处理多个分支

  • 另外,我想知道如何处理需要同时在两个分支上工作的流程,以防万一,例如,我需要在master上进行修补,但还要保留另一个分支的内容。

这里有不同的场景:

需要将新的(尚未创建)更改应用于多个分支

使用此工作流程:

  1. c从已经存在于所有这些分支的修订版本中创建一个新分支(例如,当更改将是错误修正时引入了该错误的修订版本),或者从一个可接受的版本(包括其所有祖先)中引入一个修订版本。所有这些分支。
  2. 在新分支上进行更改并提交c
  3. 对于b需要更改的每个分支:

    1. 签出b

      git checkout b
      
    2. 合并cb

      git merge c
      
  4. 删除分支c

    git branch --delete c
    

需要在其他分支上进行现有更改

(...但未对更改所在的位置进行其他更改)

  1. 签出需要更改的分支
  2. 按顺序挑选要进行更改的修订版本

在一个分支上a,您想要将一个或某些文件更改为它们在另一分支上的确切状态b

  1. 查看 a
  2. 从分支获取文件内容b

    git checkout b -- path/to/a/file.txt path/to/another/file.cpp or/even/a/complete/directory/ ...
    

    (除了git checkout没有传递路径外,它不会切换到分支b,只会从那里获取请求的文件内容。这些文件可能存在或可能不存在a。如果存在,则它们的内容将被覆盖b。)

在一个分支上工作时,您想看看另一分支上的情况

签出您要处理的分支。

然后,要查看另一个分支,

  • 要么使用允许您查看当前未检出修订的内容的图形工具(例如,gitk尝试将单选按钮从“补丁”切换到“树”)
  • 或将存储库克隆到一个临时目录,然后签出那里的另一个分支
  • 或用于git worktree创建同一存储库的单独工作目录(即,也使用.git/当前本地存储库目录中的数据库),您可以在其中签出其他分支

对于最后一个工作流程,stash是理想的。
CAD97

@ CAD97没有,如果你想继续在第一分支上工作,而看第二参考并行git stash最好将未完成的工作移开,例如切换分支机构,然后再回来。
das-g

1
“ Mercurial工作流通常通过克隆完整的存储库以进行分散开发来工作”-嗯,我听说过,但是大多数想要Git分支的人只是使用书签而不是克隆整个仓库。这要容易得多。
凯文(Kevin)

@Kevin可能是。前一段时间我上次使用水银,所以那时可能就不一样了。(或者也许只是我使用过的社区的工作流程是这样的。)
das-g

也许在这方面也应更新Hg Init文本“ [...],因为您确实应该通过克隆存储库来分支Mercurial [...]”。
das-g

31

在SVN中,我通常在本地计算机上签出一个仓库,其中包括项目中的所有分支,并且我曾经为我感兴趣的分支选择文件夹并在其中工作。

除非您签出主干上方的目录,否则在Subversion中通常不会在本地拥有所有可用分支。在Git中,所有内容(提交,消息,分支等)总是克隆到每个副本中。

目前,我正在克隆一个仓库,并使用gitk克隆一个特定的分支。

不可能,请参见上文。您可以git checkout branch-name,但不能git clone something branch-name。在Subversion中,分支是文件夹。在Git中,分支是指向提交的指针。

我找不到一种简单的方法来使用GIT查看本地存储库中的所有分支。

运行git branch。默认情况下,它仅显示本地分支。使用git branch --remote查看远程分支机构。


4
“默认情况下,它仅显示本地分支。” 听起来好像还有其他本地分支。但是您也会说:“在Git中,所有内容(提交,消息,分支等)总是克隆到每个副本中。” 。我发现这有点令人困惑,因为如果所有分支都克隆到您的副本中,那么那些神秘的非本地分支是什么?在评论字段中回答可能太复杂了。

2
@pipe提交更改时,可以通过创建本地提交来执行此操作,该更改将更改分支指向的提交。如果希望其他人获得这些更改,则需要将这些更改推送到远程存储库。这导致远程分支指向此新提交。现在,其他所有人都可以从那里提取这些更改,因此每个人最终都将获得存储库的完整副本
Frozn

9
@pipe首先,您实际上可以仅使用克隆分支--single-branch(甚至仅使用克隆尖端--depth 1)。git知道的本地和远程分支之间的区别仅仅是一种标签。远程分支的前缀是远程源的名称(通常为origin)。本地分支没有该前缀。但最后,数据在本地可用(除非您这样做--single-branch或类似的操作)。当git checkout $branchname使用没有本地分支但远程分支存在的分支运行时,git会自动设置“跟踪”远程的本地分支。
乔纳斯·谢弗(JonasSchäfer)

“除非您签出主干上方的目录”-我的经验是,这很普遍,因为它使合并变得容易得多。(尽管我们使用单个“活动”分支而不是版本标签,所以它通常仅相当于代码的2-3个副本)
Izkata

1
@Izkata,“它使合并变得容易得多”,对吗?
HorusKol

3

因为这是用标签的,所以我希望我对SVN的了解可以忽略不计。

目前,我正在克隆一个仓库,并使用gitk克隆一个特定的分支。

您正在克隆整个远程存储库,而不仅仅是一个特定的分支。

最好将存储库想象成一个数据库,因此您正在克隆远程数据库的当前状态。但是在那之后,您将在自己的数据库副本上工作。如果提交,则更改本地数据库。

fetch命令用于使本地数据库与远程数据库保持同步。

通常从该本地数据库中,签出要处理的分支。这与git的内部标记不同,它是您当前的工作开始的地方。

假设您正在开发一个简单的存储库,除了之外没有分支master,您可以查看一下.git文件夹以显示“魔术”:

假设您的上一次提交master182e8220b404437b9e43eb78149d31af79040c66,您将在下找到确切的内容cat .git/refs/heads/master

从该分支分支到新分支git checkout -b mybranch,您将在文件中找到完全相同的指针cat .git/refs/heads/mybranch

分支不过是“指针”。“工作”标记称为HEAD

如果您想知道自己HEAD的位置:

cat .git/HEAD上面写着例如ref: refs/heads/mybranch,这反过来将(cat .git/refs/heads/mybranch)指向提交哈希78a8a6eb6f82eae21b156b68d553dd143c6d3e6f

实际的提交存储在objects文件夹下(其主题如何)。

项目文件夹仅包含该分支的内容,而我看不到SVN中的所有分支,这对我来说有点困惑。

请勿将其working directory与整个“ git-database” 混淆。如上所述,您的工作目录只是(可能是)子集的快照。

假设您有不同的分支,则您的工作目录专用于仅在该分支上工作(尽管您可以将工作从那里放在其他地方)。

通常,如果要查看为项目定义了哪些分支,则可以

  • git branch 对于当地分支机构
  • git branch --remote 用于远程分支
  • git branch -a 对彼此而言

(或git branch -v

由于git是一个分布式版本控制系统,因此不仅可以而且可以在本地/远程创建不同的分支。

我典型的工作流程是:

  • 分支功能分支
  • 从那分支一个WIP(进行中的)分支
  • 就像您想要的那样工作-即使您在一行之后提交;没关系

功能完成后:

  • 压扁/重做WIP分支(具有交互式重定基)=从中进行单个提交
  • WIP分支合并到功能分支中,并提供(如果您使用github,该提议将被称为“拉取请求”)以集成到稳定(主)分支中。

另外,我想知道如何处理需要同时在两个分支上进行wprl的进程,以防万一,例如,我需要在master上进行修补,但还要保留另一个分支的内容。

这取决于项目的结构:

假设您有一个稳定的主人。而且功能仅是从该稳定分支中开发的,因此它通常位于功能分支的后面。然后,您将对master进行最后一次提交,这将是功能分支的根。

然后,您将在master分支上进行提交,并可以决定是两个分支合并在一起还是将其变基(对于有高级需求的用户来说,这是一种合并)。

或者,您始终可以在分支上进行更改(例如master),然后将其选择到其他分支上。

建议使用什么名称约定来制作包含从GIT仓库中克隆的分支的文件夹,例如myproject-branchname

它是由你决定。

通常,您以存储库名称结尾。

但是在某些情况下,不需要这样做:

例如,您克隆oh-my-zsh,其中git clone git://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh Here .oh-my-zsh被明确命名为目标。


2

Git clone 实际上会克隆整个存储库,但会将您的工作目录设置为默认目录(通常是主目录)。

您可以看到其他分支git branch用于查看本地分支或git branch -r查看远程分支,然后git checkout切换到现有分支或基于当前分支创建新分支。

您应该阅读git文档以获取更多详细信息,Atlassian也有一些不错的文章。


0

git和svn中的分支本质上是不同的。

在svn中,分支(或标签)是仓库中的目录。

在git中,分支(或标签)是指向提交的指针。

使用svn可以检查出仓库的根目录。这意味着您可以立即检出每个分支和标记。注意,这不是使用svn的正常方法。

git分支不是目录,因此没有“检出存储库根目录”的等效条件。对多个工作树有一些支持,所以我想如果您确实想要的话,您可以拼凑一个脚本来同时签出每个分支,但这是一个非常不寻常的想法。

此外,使用SVN,只有一个回购。有了git,每个开发人员都有自己的仓库。这意味着开发人员可以脱机工作,但这也意味着不同的开发人员对每个分支上的内容可能会有不同的想法。

由于是目录,并且借助svn的简单线性历史记录模型,svn分支具有可靠的历史记录。如果您想知道日期y在分支x上的内容,则可以轻松地提出该问题。

另一方面,Git分支实际上没有历史记录。有“引用日志”,但它旨在作为一种灾难恢复机制,而不是长期的历史记录。特别是,reflog不能被远程读取,默认情况下,裸回购被禁用。

提交当然有历史记录,但是这些历史记录不足以回答“日期z的回购y的分支x上是什么”的问题。

我找不到使用Git查看本地存储库中所有分支的简便方法。

您可以通过键入“ git branch”列出所有本地分支。

您可以使用“ git branch -a”列出所有本地和远程分支。

另外,我想知道如何处理需要同时在两个分支上工作的流程,以防万一,例如,我需要在master上进行修补,但还要保留另一个分支的内容。

有两个选择。

您可以在“其他分支”上提交更改,切换到master在那里进行工作,然后再切换回去。

您还可以创建一个额外的工作树。谷歌“ git-worktree”获取有关语法的详细信息。

建议使用什么名称约定来制作包含从Git仓库中克隆的分支的文件夹,例如myproject-branchname?

我认为没有既定惯例。一次检查出多个工作树是例外,而不是规则。


2
这个答案看起来不完整,为什么呢?
蚊蚋
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.