git branch,fork,fetch,merge,rebase和clone之间有什么区别?


502

我想了解Git中的分支,分支和克隆之间的区别吗?

同样,我做a git fetch而不是a 意味着什么git pull

另外,rebase与相比意味着什么merge

我该如何压制个人共同致力于?

它们如何使用,为什么使用以及它们代表什么?

GitHub如何体现?


19
您可以将接受的答案更改为迈克尔·杜兰特的答案吗?
siride

11
他当然可以,但是这必须是他的选择,坦率地说,大多数来到这里的人(如我)想要更简洁的东西,就像他选择的答案一样,这在当时是一个人=)
user1271772

Answers:


366

克隆只是存储库的副本。从表面上看,其结果与等效svn checkout,您可以从其他存储库下载源代码。集中式VCS(例如Subversion)和DVCS(例如Git)之间的区别在于,在Git中,克隆时,您实际上是在复制整个源存储库,包括所有历史记录和分支。现在,您的计算机上有了一个新的存储库,您所做的任何提交都进入该存储库。在您将这些提交推送到另一个存储库(或原始存储库)之前,或者直到有人从您的存储库中提取提交(如果它是可公开访问的)之前,没人会看到任何更改。

分支是存储库中的东西。从概念上讲,它代表着发展的线程。通常,您有一个master分支,但是您可能也有一个分支,您正在其中从事某些功能xyz的工作,而另一个分支则用于修复错误abc。签出分支后,所做的所有提交都将保留在该分支上,并且与其他分支合并或将它们重新建立到相关分支之前,不会与其他分支共享。当然,在谈到分支之前,Git似乎有点怪异,直到您了解实现分支的基础模型为止。我不会自己解释它(我已经说了太多,methinks),而是链接到有关Git如何建模分支和提交的“计算机科学”解释,该解释取自Git网站:

http://eagain.net/articles/git-for-computer-scientists/

叉子实际上并不是Git的概念,而是一个政治/社会概念。也就是说,如果某些人对项目的发展方式不满意,他们可以独立于原始开发人员来获取源代码并自行处理。那将被认为是叉子。Git使分叉变得容易,因为每个人都已经拥有了自己的源代码“主”副本,因此就像与原始项目开发人员建立联系一样简单,并且不需要像使用SVN那样从共享存储库中导出历史记录。

编辑:由于我不知道GitHub等站点使用的“ fork”的现代定义,请查看下面的注释以及我下面的Michael Durrant的答案以获取更多信息。


125
分叉并不一定意味着开发人员对主仓库不满意。通常,这意味着另一位开发人员已读取但未写入该存储库。开发人员可以分叉存储库,进行更改,但是由于他无法写主存储库,因此必须将其更改作为补丁提交。因此,分叉也是一种在不授予写访问权限的情况下鼓励协作的方法。
brycemcd

5
我想是真的。我只见过在创建新的,可能具有竞争性的项目版本的上下文中使用过“叉子”。
siride

32
您可能会说,叉子是一个分支,预计不会在上游合并
masonk,2010年

6
Git Hub使用“ fork”作为叉子。这是一个存储在github上的新存储库,与原始存储库分开。但是,github也使实现拉取请求变得非常简单。从本质上讲,拉取请求要求原始存储库的所有者将更改从回购的分支“拉回”到源中。这样,每个人都可以使用源代码管理并拥有所有更改(包括其更改)的历史记录,但并非每个人都需要对原始存储库的写权限。
mklauber 2012年

4
我已经更新了答案,以告诉人们更多关于github模型的信息。
siride

531

吉特

这个答案包括GitHub,正如许多人也问过的那样。

本地存储库

Git(本地)有一个目录(.git),您将文件提交到该目录,这是您的“本地存储库”。这与SVN等系统不同,在该系统中,您立即添加并提交到远程存储库。

Git存储通过保存整个文件而更改的文件的每个版本。在这方面,它与SVN也有所不同,因为您可以转到任何单独的版本,而无需通过增量更改“重新创建”它。

Git根本不“锁定”文件,因此避免了编辑的“排他锁定”功能(想到像pvcs这样的旧系统),因此即使脱机也可以始终编辑所有文件。实际上,在对远程存储库(例如GitHub)的拉取或提取/推送过程中,将文件更改(在同一文件中!)合并在一起的工作确实非常出色。唯一需要进行手动更改(实际上是编辑文件)的时间是,如果两个更改涉及同一行代码。


分行

分支允许您保留主代码(“ master”分支),进行复制(新分支),然后在该新分支中工作。如果自创建分支以来工作花费了一段时间或master进行了很多更新,则应该对master分支进行合并或重新定型(通常是更好的历史记录和更容易解决冲突的首选)。完成后,将分支中所做的更改合并回主存储库。无论是功能,错误还是杂项,许多组织都为每个工作使用分支。其他组织仅将分支用于主要更改,例如版本升级。

Fork:使用分支可以控制和管理分支,而使用fork则可以由其他人控制重新接受代码。

广义地说,进行分支有两种主要方法。首先是将大多数更改保留在master分支上,仅将分支用于较大和运行时间较长的事情,例如版本更改,而您希望拥有两个可用于不同需求的分支。第二种方法是,您基本上为每个功能请求,错误修复或杂项创建一个分支,然后手动决定何时将这些分支实际合并到主master分支中。尽管这听起来很乏味,但这是一种常见的方法,也是我当前使用和推荐的方法,因为这可以使master分支保持清洁,并且它是我们升级到生产环境的master,所以我们只希望通过重新定级和合并分支。

将分支“引入”母带的标准方法是执行merge。分支也可以“重新设置”以“清理”历史记录。它不会影响当前状态,并且可以提供“清除”历史记录。

基本上,您的想法是从某个点(通常是从主节点)分支出来。自从分支以来,“ master”本身已从该分支点向前移动。如果您在分支机构中进行的所有更改都与母版的当前状态及其所有最新更改相对应,那么它将“更干净”(更容易解决问题,更容易理解历史记录)。因此,过程是:保存更改;获取“新”母版,然后重新应用更改(这是重新设置部分)。请注意,像合并一样,重新设置基准可能会导致您必须手动解决(例如,编辑和修复)冲突。

需要注意的一条准则:
仅当分支是本地分支并且尚未将其推送到远程分支时才重新设置基准
这主要是因为重新定基可以改变其他人看到的历史,其中可能包括他们自己的提交。

跟踪分支

这些是已命名的分支origin/branch_name(与just相对branch_name)。当您将代码推送到远程存储库或从远程存储库中拉出代码时,这实际上就是发生这种情况的机制。例如,当您git push的分支名为时building_groups,您的分支首先到达origin/building_groups,然后再到达远程存储库。同样,如果执行git fetch building_groups,则检索到的文件将放置在origin/building_groups分支中。然后,您可以选择将此分支合并到本地副本中。我们的做法是始终进行git fetch和手动合并,而不是仅进行合并git pull(一步完成上述两项操作)。

获取新分支。

获取新分支:在克隆的最初,您将拥有所有分支。但是,如果其他开发人员添加了分支并将其推送到远程,则需要一种“了解”这些分支及其名称的方法,以便能够在本地将其下拉。这是通过a完成的git fetch,它将使用跟踪分支(例如origin/)将所有新的和更改的分支都放入本地存储库。一旦fetchED,人们可以git branch --remote列出跟踪分行和git checkout [branch]实际切换到任何给定的一个。

合并中

合并是合并来自不同分支或来自同一分支的不同版本的代码更改的过程(例如,当本地分支与远程不同步时)。如果已经在分支机构中开发了工作,并且该工作已经完成,准备就绪并经过了测试,则可以将其合并到master分支机构中。这是通过git checkout master切换到master分支来完成的,然后git merge your_branch。合并会将所有不同的文件,甚至对同一文件的不同更改都放在一起。这意味着它将实际更改文件中的代码以合并所有更改。

进行时checkoutmaster还建议您执行,git pull origin master以将最新版本的远程主服务器合并到本地主服务器中。如果远程主服务器发生更改,即,moved forward您将在此期间看到反映该信息的信息git pull。如果是这样的话(主变),建议您git checkout your_branch,然后rebase它来掌握,这样的更改实际得到的“新”高手“的顶部重播”。然后,您将继续更新母版,如下一段所示。

如果没有冲突,则master将添加新的更改。如果存在冲突,则意味着相同文件的相似代码行具有更改,因此无法自动合并。在这种情况下,git merge new_branch将报告存在要解决的冲突。您可以通过编辑文件(其中将同时包含两个更改),选择所需的更改,从字面上删除不需要的更改的行并保存文件来“解决”它们。这些变化都标有分离器,如========<<<<<<<<

一旦您解决任何冲突,那么你将再次git addgit commit这些变化将继续合并(你会在这个过程中,引导你从git的反馈)。

当该过程无法正常运行时,您会发现git merge --abort重新设置非常方便。

交互式重新基准化和压缩/重新排序/删除提交

如果您以许多小步骤完成工作,例如,每天将代码提交为“进行中的工作”,则可能需要将许多小的提交“压缩”为几个较大的提交。当您想与同事进行代码审查时,这特别有用。您不想重播您执行的所有“步骤”(通过提交),而只想说这是一次提交中我所做的所有更改的最终效果(差异)。

在考虑是否要执行此操作时,评估的关键因素是针对同一文件还是多次提交多个提交(在这种情况下,最好压缩提交)。这是通过交互式变基工具完成的。此工具可让您压缩提交,删除提交,重新编写消息等。例如,git rebase -i HEAD~10请注意:这是一个~,不是a-)显示以下内容:

Git中的交互式变基

但是请务必小心,并“谨慎”使用此工具。一次执行一次压入/删除/重新排序,退出并保存该提交,然后重新进入该工具。如果提交不连续,则可以对其重新排序(然后根据需要压缩)。您实际上也可以在此处删除提交,但是您确实需要确定自己在做什么!

前叉

Git存储库中有两种主要的协作方法。上面详细介绍的第一个方法是直接通过人们从/向/向下拉的分支。这些协作者的SSH密钥已在远程存储库中注册。这将使他们直接推送到该存储库。缺点是您必须维护用户列表。另一种方法-分叉-允许任何人“分叉”存储库,基本上是在自己的Git存储库帐户中创建本地副本。然后,他们可以进行更改,并在完成后发送一个“拉动请求”(实际上更多是来自他们的“推”和对实际存储库维护者的“拉动”请求)以使代码被接受。

第二种方法,使用叉子,并没有需要专人维护用户存储库的列表。


的GitHub

GitHub(一个远程存储库)是一个远程源,如果您拥有(或添加到)这样的存储库,通常会将那些提交的更改推入或拉出,因此本地和远程实际上是完全不同的。考虑远程存储库的另一种方法是,它是.git位于远程服务器上的目录结构。

当你“叉” -在GitHub的Web浏览器界面,你可以点击这个按钮叉子按钮的图像-您在创建代码的副本(“克隆”),您的 GitHub的帐户。初次执行时可能会有些微妙,因此请确保查看代码库位于谁的存储库下-原始所有者或“源于”,例如:

分叉存储库名称的图像

拥有本地副本后,您可以根据需要进行更改(通过将其拉入并推入本地计算机)。完成后,您将向原始存储库所有者/管理员提交“拉动请求”(听起来不错,但实际上您只是单击此:),然后拉取请求按钮的图像他们将它们“拉入”。

对于团队一起工作的代码,更常见的是“克隆”存储库(单击存储库主屏幕上的“复制”图标)。然后,在本地键入git clone并粘贴。这将在本地设置您,并且您还可以推拉到(共享的)GitHub位置。

无性系

如GitHub部分所述,克隆是存储库的副本。当您拥有远程存储库时,请git clone针对其URL 发出命令,然后最终得到存储库的本地副本或克隆。此克隆具有所有内容,文件,master分支,其他分支,所有现有的提交以及整个shebang。正是您对其进行添加和提交的克隆,然后远程存储库本身就是将这些提交推送到的对象。正是这种本地/远程概念使Git(以及类似的系统,例如Mercurial)成为DVCS(分布式版本控制系统),而不是像SVN,PVCS,CVS等更传统的CVS(代码版本控制系统)。您直接提交到远程存储库。

可视化

可以在
http://marklodato.github.com/visual-git-guide/index-en.htmlhttp://ndpsoftware.com/git-cheatsheet.html#loc=index上看到核心概念的可视化

如果您想直观显示更改的工作方式,则无法使用我称之为“地铁地图”(尤其是伦敦地铁)的GUI 击败可视工具gitggitx对于macOS),非常适合显示谁做了什么,事情如何变化,分歧和融合等

您也可以使用它来添加,提交和管理您的更改!

gitg / gitx界面图片

尽管gitg / gitx相当小,但GUI工具的数量仍在继续增加。许多Mac用户使用brotherbard的gitx分支,对于Linux,一个不错的选择是smart-git,它具有直观而强大的界面:

smart-git GUI的图像

请注意,即使使用GUI工具,您也可能会在命令行上执行很多命令。

为此,我在~/.bash_aliases文件中有以下别名(~/.bashrc每个终端会话从文件中调用该别名):

# git
alias g='git status'
alias gcob='git checkout -b '
alias gcom='git checkout master'
alias gd='git diff'
alias gf='git fetch'
alias gfrm='git fetch; git reset --hard origin/master'
alias gg='git grep '
alias gits='alias | grep "^alias g.*git.*$"'
alias gl='git log'
alias gl1='git log --oneline'
alias glf='git log --name-status'
alias glp='git log -p'
alias gpull='git pull '
alias gpush='git push '

并且我的文件中包含以下“ git别名” ~/.gitconfig-为什么要使用这些别名?
这样分支完成(使用TAB键)就可以了!

所以这些是:

[alias]
  co = checkout
  cob = checkout -b

用法示例:git co [branch]<-分支的制表符补全将起作用。

GUI学习工具

您可能会发现https://learngitbranching.js.org/对于学习一些基本概念很有用。屏幕截图: 视频:https//youtu.be/23JqqcLPss0在此处输入图片说明

最后,有7个主要的救星!

  1. 您进行更改,添加并提交(但不要推送),然后哦!您意识到自己是主人!

    git reset [filename(s)]
    git checkout -b [name_for_a_new_branch]
    git add [file(s)]
    git commit -m "A useful message"
    
    Voila!  You've moved that 'master' commit to its own branch !
  2. 您在本地分支机构工作时会弄乱一些文件,只是想回到上一次执行的操作git pull

    git reset --hard origin/master  # You will need to be comfortable doing this!
  3. 您开始在本地进行更改,编辑了六个文件,然后,天哪,您仍在master(或另一个)分支中:

    git checkout -b new_branch_name  # just create a new branch
    git add .                      # add the changes files
    git commit -m"your message"    # and commit them
  4. 您将当前分支中的一个特定文件弄乱了,并希望基本上将该文件“重置”(丢失更改)为上次从远程存储库中提取该文件的方式:

    git checkout your/directories/filename

    实际上,这会重置文件(就像许多Git命令一样,由于此处执行的操作而没有很好地命名)。

  5. 你做出一些改变局部,你要确保,而你做你不会失去他们git resetrebase:我常常使整个项目的手动副本(cp -r ../my_project ~/)时,我不知道如果我可能搞砸了Git中或丢失重要变化。

  6. 您正在重新定级,但事情变得一团糟:

    git rebase --abort # To abandon interactive rebase and merge issues
  7. 将Git分支添加到PS1提示符(请参阅https://unix.stackexchange.com/a/127800/10043),例如

    提示图片

    分支是selenium_rspec_conversion



1
12/6/16添加了有关克隆的部分,以使其更加完整。
Michael Durrant 2012年

4
这么多文字!我会坚持简单的Subversion :-)
Jonny

6
?? Subversion用户还可以编写有关使用Subversion的书。我认为,Subversion是一种较旧的技术,功能较少。我个人觉得git非常易于使用。ymmv
Michael Durrant

3
哇,米歇尔!SO就是共享知识。感谢您的出色工作,绝对是+1
Michiel 2014年

143

这是奥利弗·斯蒂尔(Oliver Steele)关于如何将它们组合在一起的图像:

在此处输入图片说明


6
可以更新此图像以添加“ git clone”,我相信大多数人无论如何都会熟悉它。
Contango

3
@Gravitas,我真的很喜欢这张图片,但是它没有告诉我文件何时被覆盖以及何时被合并。您能否让我知道这些命令中的哪个?也许驱动器顶部的覆盖命令和驱动器下方的合并命令?谢谢。
zylstra 2013年

据我了解,git pull会从一个远程下拉列表,无论您提出什么要求(因此,无论您要求什么中继),并在发出请求时立即将其合并到您所在的分支中。Pull是一个高级请求,默认情况下将运行“获取”然后运行“合并”,或使用“ -rebase”进行重新设置。您可以没有它,这只是一个方便。
Contango

git clone在该图中到底在哪里?还git合并?我是git的新手,但我喜欢这张照片。
Mishelle

2
我将查看是否可以更新该图。
康坦戈2015年

8

叉与 克隆-两个词都意味着复制

请看这个 图。 (最初来自http://www.dataschool.io/content/images/2014/Mar/github1.png)。

.-------------------------.     1. Fork     .-------------------------.
| Your GitHub repo        | <-------------- | Joe's GitHub repo       |
| github.com/you/coolgame |                 | github.com/joe/coolgame |
| ----------------------- | 7. Pull Request | ----------------------- |
| master -> c224ff7       | --------------> | master -> c224ff7 (c)   |
| anidea -> 884faa1 (a)   |                 | anidea -> 884faa1 (b)   |
'-------------------------'                 '-------------------------'
    |                 ^
    | 2. Clone        |
    |                 |
    |                 |
    |                 |
    |                 |
    |                 | 6. Push (anidea => origin/anidea)
    v                 |
.-------------------------.
| Your computer           |  3. Create branch 'anidea'
| $HOME/coolgame          |
| ----------------------- |  4. Update a file
| master -> c224ff7       |
| anidea -> 884faa1       |  5. Commit (to 'anidea')
'-------------------------'

(a) - after you have pushed it
(b) - after Joe has accepted it
(c) - eventually Joe might merge 'anidea' (make 'master -> 884faa1')

叉子

  • 副本到您的远程存储库(云),并将其链接到Joe的
  • 然后可以将副本克隆到本地存储库并F *%$-up
  • 完成后,您可以返回到遥控器
  • 然后,您可以通过单击pull-request询问Joe是否要在项目中使用它。

克隆

  • 复制到本地存储库(硬盘)

请注意,DVCS的真正优势在于,您不需要对Joe的存储库任何特定的访问权限即可执行此操作。如果Joe希望您增加捐款次数,他可以授予您推送访问权:您可以将anidea其推送到他的仓库,并省去了保持最新状态的繁琐工作。OTOH如果您无法与Joe达成协议,则可以继续开发和使用分叉(并查看是否可以让他稍后改变主意)。
Alois Mahdal

6

只是为了补充给别人,一个关于分叉的注释。

很好地认识到,从技术上讲,克隆仓库和分叉仓库是同一回事。做:

git clone $some_other_repo

您可以在背面轻按一下自己-您刚刚派出了一些其他仓库。

实际上,作为VCS的Git与克隆分叉有关。除了使用cgit之类的远程UI进行“仅浏览”之外,与git repo几乎没有关系,它不涉及派生在某个时候克隆该repo。

然而,

  • 当某人说我分叉了仓库X时,他们的意思是说他们在其他地方创建了仓库的克隆,目的是公开给其他人,例如进行一些实验或应用不同的访问控制机制(例如,允许没有可以访问Github,但可以与公司内部帐户进行协作)。

    事实:回购很可能是由除 git clone最有可能托管在服务器上而不是某人的笔记本电脑上,并且格式可能稍有不同(这是“裸回购”,即没有工作树)只是技术细节。

    它很可能包含不同的分支,标签或提交集的事实很可能是他们首先这样做的原因。

    (Github在您单击“叉子”时所做的只是克隆添加的糖:它会为您克隆存储库,将其放入您的帐户下,记录“来自”的分支,在远程添加“上游”,最重要的是,播放漂亮的动画。)

  • 当有人说我克隆了repo X时,他们的意思是说他们已经在笔记本电脑或台式机上本地创建了该存储库的副本,意在对其进行研究,使用,对其进行贡献或从其源代码中构建某些东西。

Git的优点在于可以使它们完美地结合在一起:所有这些存储库共享提交链的公共部分,因此可以安全地(请参阅下面的说明)在您认为合适的所有这些存储库之间来回合并更改。


注意:只要您不重写链的公共部分,并且只要更改不冲突就可以“安全”。

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.