首页 文章

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

提问于
浏览
483

有人可以帮我理解Git中分支,分支和克隆之间的区别吗?

同样,当我做 git fetch 而不是 git pull 时,它意味着什么?

另外,与 merge 相比, rebase 的意思是什么?

我怎样才能将各个提交自己压缩在一起?

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

GitHub如何计算?

5 回答

  • 519

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

    分支是存储库中的东西 . 从概念上讲,它代表了一个发展的线索 . 您通常有一个主分支,但您可能还有一个分支,您正在处理某些功能xyz,另一个用于修复bug abc . 当您签出分支时,您所做的任何提交都将保留在该分支上,并且不会与其他分支共享,直到您将它们合并或将它们重新绑定到相关分支上 . 当然,对于分支来说,Git看起来有点奇怪,直到你看到分支实现的基础模型 . 而不是自己解释(我已经说得太多了,我已经说过了),我将链接到Git模型分支和提交的“计算机科学”解释,取自Git网站:

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

    叉子确实不是Git概念,它更像是一种政治/社会观念 . 也就是说,如果某些人对项目的运行方式不满意,他们可以将源代码与原始开发人员分开处理 . 这将被视为一个分叉 . Git使得分叉变得容易,因为每个人都有自己的源代码“主”副本,所以它就像切断与原始项目开发人员的联系一样简单,并且不需要从共享存储库导出历史记录,就像你可能与SVN一样 .

    编辑:因为我不知道像GitHub这样的网站所使用的"fork"的现代定义,请查看我的评论以及我下面的Michael Durrant's answer以获取更多信息 .

  • 358

    Git

    我的答案包括github,因为很多人都对此问过 .

    本地存储库

    git(local)有一个你提交文件的目录(.git),这是你的“本地存储库” . 这与svn等系统不同,您可以立即添加并提交到远程存储库 .

    git通过保存整个文件来存储更改的文件的每个版本 . 它在这方面也与svn不同,因为你可以访问任何单个版本,而无需通过delta更改“重新创建”它 .

    git根本没有“锁定”文件,因此避免了编辑的“独占锁定”功能(像pvcs这样的旧系统),所以即使离线也可以编辑所有文件 . 它实际上在拉取或提取/推送到远程存储库(如github)期间将文件更改(在同一文件中!)合并在一起 . 您需要进行手动更改(实际编辑文件)的唯一时间是两次更改涉及相同的代码行 .


    分行

    分支允许您保留主代码('master'分支),制作副本(新分支),然后在该新分支中工作 . 如果工作需要一段时间,或者master自获得分支以来获得了大量更新,那么应该对主分支进行合并或重新定位(通常优选更好的历史记录并且更容易解决冲突) . 完成后,将分支中所做的更改合并到主存储库中 . 许多组织为每个工作使用分支,无论它是功能,错误还是杂项 . 其他组织仅使用分支进行主要更改,例如版本升级 . Fork:使用分支控制和管理分支,而使用fork,其他人控制接受代码 .
    从广义上讲,分支机构有两种主要方法 . 首先是保持主分支上的大多数更改,仅使用分支来处理更大和更长时间运行的事情,例如版本更改,您希望有两个分支可用于不同的需求 . 第二个是你基本上为每个功能请求,错误修复或杂项创建一个分支,然后手动决定何时实际将这些分支合并到主主分支 . 虽然这听起来很乏味,但这是一种常见的方法,也是我目前使用和推荐的方法,因为这使得主分支更清洁,而且它是我们提升到 生产环境 的主人,所以我们只需要通过变基和合并分支机构 .

    将分支"in"置于主站的标准方法是执行 merge . 分支也可以 rebase d到'clean up'历史 . 它没有't affect the current state and is done to give a '清洁' history. Basically the idea is that you branched from a certain point (usually from master). Since you branched '大师'本身已经向前迈进了 . 因此,如果您在分支中完成的所有更改都是针对最近的主人进行的,并且所有更改都会更新,那么这将更加清晰 . 所以过程是:保存更改;获取"new" master,然后再次重新应用更改 . 请注意,与合并一样,rebase可能会导致您必须手动解决(编辑)的冲突 .

    一个'guideline'注意: Only rebase if the branch is local and you haven't pushed it to remote yet! 这主要是因为变基可以改变其他人看到的可能包括他们自己的提交的历史 .

    跟踪分支机构

    这些是名为origin / branch_name的分支(而不仅仅是branch_name) . 当您将代码推送到远程存储库或从远程存储库中提取代码时,这实际上是发生这种情况的机制 . 例如,当您 git push 一个名为'building_groups'的分支时,您的分支首先进入origin / building_groups,然后进入远程存储库(实际上这是一个过度简化但现在已经足够了) . 同样,如果您执行 git fetch building_groups ,则检索到的文件将放置在origin / building_groups分支中 . 然后,您可以选择将此分支合并到本地副本中 . 我们的做法是始终进行git fetch和手动合并,而不仅仅是git pull(在一步中完成上述两个操作) .

    获取新分支 .

    获得新分支:在克隆的初始阶段,您将拥有所有分支 . 但是,如果其他开发人员添加分支并将其推送到远程,则需要有一种关于这些分支及其名称的方法,以便能够在本地将它们拉下来 . 这是通过 git fetch 完成的,它将使用跟踪分支(例如origin /)将所有新的和更改的分支到达本地存储库 . 一旦 fetch 编辑,可以 git branch --remote 列出跟踪分支, git checkout [branch] 实际切换到任何给定分支 .

    合并

    合并是组合来自不同分支或来自同一分支的不同版本的代码更改的过程(例如,当本地分支和远程不同步时) . 如果已经在分支中开发了工作并且工作已完成,准备就绪并且已经过测试,那么它可以合并到 master 分支中 . 这是由 git checkout master 完成切换到 master 分支,然后是 git merge your_branch . 合并将把所有不同的文件甚至不同的更改带到同一个文件中 . 这意味着它实际上将更改文件中的代码以合并所有更改 . 在执行 checkout master 时,还建议执行 git pull origin master 以将最新版本的远程主服务器合并到本地主服务器中 . 如果远程主站更改,即 moved forward ,您将看到在 git pull 期间反映该信息的信息 . 如果是这种情况(主服务器已更改),建议您使用 git checkout your_branch 然后 rebase 来掌握它,以便您的更改实际上在"new"主服务器上获得"replayed" . 然后,您将继续获取最新的主数据,如下一段所示 .

    如果没有冲突,那么master将添加新的更改 . 如果存在冲突,这意味着相同的文件在类似的代码行周围发生了变化,无法自动合并 . 在这种情况下, git merge new_branch 将报告's conflict(s) to resolve. You '解析' them by editing the files (which will have both changes in them), selecting the changes you want, literally deleting the lines of the changes you don' t想要然后保存文件 . 更改标有分隔符,例如 ========<<<<<<<<

    一旦你解决了任何冲突,你将再次 git addgit commit 这些更改继续合并(你'll get feedback from git during this process to guide you). When the process doesn' t工作得很好,你会发现 git merge --abort 非常方便重置事情 .

    互动重新定位和压缩/重新排序/删除提交

    如果您已经完成了许多小步骤的工作,例如你每天都将代码提交为'work-in-progress',你可能希望"squash"那么多小提交进入一些较大的提交 . 当您想与同事进行代码审查时,这可能特别有用 . 你没有(通过提交),你想在这里说这是我在一次提交中对这项工作的所有更改的最终效果(差异) . 在考虑是否这样做时要评估的关键因素是多次提交是否多次针对同一个文件或文件(在这种情况下更好地压缩提交) . 这是通过交互式变基工具完成的 . 此工具允许您压缩提交,删除提交,重新编写消息等 . 例如 git rebase -i HEAD~10 注意, ~ 不是 - 会显示以下内容:

    interactive rebasing in Git
    请注意并使用此工具'gingerly' . 一次进行一次压缩/删除/重新排序,退出并保存该提交,然后重新输入该工具 . 如果提交不连续,您可以重新排序(然后根据需要压缩) . 你实际上也可以在这里删除提交,但是当你这样做时,你真的需要确定你在做什么!

    福克斯

    在git存储库中有两种主要的协作方法 . 第一个,上面详述的是直接通过人们从/向推拉的分支 . 这些协作者将他们的ssh密钥注册到远程存储库 . 这将让他们直接推送到该存储库 . 缺点是你必须维护用户列表 . 另一种方法 - 分叉 - 允许任何人'fork'存储库,基本上在他们自己的git存储库帐户中制作本地副本 . 然后他们可以进行更改,并在完成后发送'pull request'(实际上是对实际存储库维护者的请求)以获取代码 .
    第二种方法使用分叉,不需要有人维护存储库的用户列表 .


    Github github(一个远程存储库)是一个远程源,如果你已经(或被添加到)这样的存储库,你通常会推送和提取这些已提交的更改,因此本地和远程实际上是非常不同的 . 另一种思考远程存储库的方法是它是一个位于远程服务器上的.git目录结构 .

    当你'fork' - 在github网页浏览器中你可以点击
    enter image description here

    • 你在你的github帐户中创建一个代码的副本('clone') . 第一次执行此操作时可能会有点微妙,因此请务必确保查看其下方列出的代码库的存储库 - 原始所有者或'forked from'以及您,例如
      enter image description here

    获得本地副本后,您可以根据需要进行更改(通过拉动并将其推送到本地计算机) . 当你完成后,你提交'pull request'到原始存储库所有者/管理员(听起来很花哨,但实际上你只需点击这个: -
    enter image description here
    ),他们'pull'它 .
    对于一起处理代码的团队来说,更常见的是'clone'存储库(单击存储库主屏幕上的'copy'图标) . 然后,本地输入git clone [paste]这将在本地设置你,你也可以推送到(共享)github位置 .

    克隆

    如github一节所示,克隆是存储库的副本 . 当您拥有远程存储库时,可以针对其URL发出git clone命令,然后最终获得本地副本或克隆存储库 . 这个克隆有 everything ,文件,主分支,其他分支,所有现有的提交,整个shebang . 您正在添加和提交此克隆,然后远程存储库本身就是您推送这些提交的内容 . 正是这种本地/远程概念使得git(以及与Mercurial类似的系统)成为DVCS( Distributed 版本控制系统),而不是更传统的CVS(代码版本控制系统),如SVN,PVCS,CVS等 . 您直接提交到远程存储库 .

    可视化

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

    如果你想要一个关于变化如何工作的视觉显示,你不能用我称之为“地铁 Map ”(特别是伦敦地铁)的gui击败视觉工具gitg(gitx for mac),非常适合展示谁做了什么,事情如何变化,分歧和合并等等

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

    gitg/gitx interface

    虽然gitg / gitx相当小,在过去的2 - 3年(2009-2012)中,gui工具的数量继续扩大 . 许多Mac用户使用brotherbard的gitx分支和Linux,一个很好的选择是smart-git,具有直观而强大的界面:

    smart-git GUI

    请注意,即使使用gui工具,您也可能会在命令行执行大量命令 .
    为此,我在〜/ .bash_aliases文件中有以下别名(从我的〜/ .bashrc文件中为每个终端会话调用:

    # git
    alias gst='git status' # Warning: gst conflicts with gnu-smalltalk (when used).
    alias gb='git branch'
    alias gco='git checkout'
    alias gcob='git checkout -b '
    alias ga='git add '
    alias gc='git commit'
    alias gg='git grep ' #  A great very FAST search option, easier then `find`
    

    最后,6个关键救生员:

    1)你弄乱了你的本地分支,只想回到你上一次做git pull时所拥有的东西:

    git reset --hard origin/master  # You will need to be comfortable doing this!
    

    2)你开始在本地进行更改,你编辑了6个文件然后,哦,废话,你仍然在主(或另一个)分支:

    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
    

    3)你搞乱了当前分支中的一个特定文件,并希望基本上'reset'该文件(丢失更改)是从上次从远程存储库中取出它的方式: git checkout your/directories/filename 这实际上重置了文件(就像许多git命令一样)它没有很好地命名它在这里做什么) .

    4)你在本地进行了一些更改,你想确保在进行git重置或rebase时不要丢失它们:当我不确定是否会弄乱时,我经常制作整个项目的手动副本( cp -r ../my_project ~/ )在git或失去重要的变化 .

    5)你正在变形,但事情搞砸了:

    git rebase --abort # To abandon interactive rebase and merge issues
    

    6)将你的git分支添加到PS1提示符(参见https://unix.stackexchange.com/a/127800/10043),例如
    enter image description here

    该分支是 selenium_rspec_conversion

  • 140

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

    enter image description here

  • 7

    Fork Vs. Clone - two words that both mean copy

    请参阅diagram.(最初来自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')
    

    Fork

    • 复制到您的远程仓库( Cloud ),将其链接到Joe的

    • 然后您可以复制到本地仓库和F *%$ - up的副本

    • 完成后,您可以回到遥控器

    • 然后,您可以通过单击pull-request询问Joe是否要在项目中使用它

    Clone

    • 复制到您当地的仓库(硬盘)
  • 6

    只是添加到其他人,一个特定于分叉的注释 .

    很高兴认识到,从技术上来说,克隆回购和分销回购是一回事 . 做:

    git clone $some_other_repo
    

    你可以在后面敲击自己---你刚刚分开了一些其他的回购 .

    作为VCS,Git实际上都是关于克隆分叉的 . 除了"just browsing"使用远程用户界面如cgit之外,与git repo几乎没有什么关系,它不涉及在某些时候克隆回购 .

    然而,

    • 当有人说 I forked repo X 时,他们意味着他们在其他地方创建了一个repo的克隆,意图将其暴露给其他人,例如展示一些实验,或者应用不同的访问控制机制(例如,允许没有Github访问权限的人)但与公司内部帐户合作) .

    事实是:回购最有可能是用 git clone 之外的其他命令创建的,它是's most probably hosted somewhere on a server as opposed to somebody'的笔记本电脑,并且最有可能有略微不同的格式(它是"bare repo",即没有工作树)都只是技术细节 .

    事实上它很可能包含不同的分支,标签或提交集合,这很可能是他们首先做到这一点的原因 .

    (点击“fork”时Github会做什么,只是克隆加糖:它为您克隆回购,将它放在您的帐户下,记录“分叉”某处,添加名为“上游”的远程,最重要的是,播放好动画 . )

    • 当有人说 I cloned repo X 时,他们意味着他们已经在他们的笔记本电脑或台式机上本地创建了一个repo克隆,用于研究它,玩它,为它做贡献,或者从它的源代码构建一些东西 .

    Git的优点在于它使这一切完美契合:所有这些repos共享块提交链的共同部分,因此可以安全地(参见下面的注释)在您认为合适的所有这些回购之间来回合并更改 .


    注意:"safely"只要您不重写链的公共部分,并且只要更改不冲突 .

相关问题