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

jac*_*zil 495 git branch clone git-clone gitx

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

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

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

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

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

GitHub如何计算?

Mic*_*ant 525

混帐

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

本地存储库

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

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

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


分行

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

将分支"in"带入掌握的标准方法是做一个.git.分支机构也可以merge"清理"历史.它不会影响当前状态,并且可以提供"更清洁"的历史记录.基本上这个想法是你从某一点(通常来自主人)分支.由于你分支'主'本身已经向前发展.因此,如果您在分支中完成的所有更改都是针对最近的主人进行的,并且所有更改都会更新,那么这将更加清晰.所以过程是:保存更改; 获取"新"主,然后再次重新应用更改.请注意,与合并一样,rebase可能会导致您必须手动解决(编辑)的冲突.

需要注意的一个"指南": 如果分支是本地的,并且您还没有将其推送到远程,那么只能进行折扣! 这主要是因为变基可以改变其他人看到的可能包括他们自己的提交的历史.

跟踪分支

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

git push新的分支机构.

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

合并

合并是组合来自不同分支或来自同一分支的不同版本的代码更改的过程(例如,当本地分支和远程不同步时).如果一个人在分支机构中开发了工作并且工作已经完成,准备好并经过测试,那么它就可以合并到git fetch分支机构中.这是通过git pull切换到git fetch分支来完成的origin/.合并将把所有不同的文件甚至不同的更改带到同一个文件中.这意味着它实际上将更改文件中的代码以合并所有更改.在执行此操作fetchgit branch --remote,还建议执行a git checkout [branch]以将最新版本的远程主服务器合并到本地主服务器中.如果远程主站更改,即master,您将看到在此期间反映的信息git checkout master.如果是这种情况(主人改变了),建议你掌握master,然后git merge your_branch掌握,以便你的更改实际上"重播"在"新"主人之上.然后,您将继续获取最新的主数据,如下一段所示.

如果没有冲突,那么master将添加新的更改.如果存在冲突,这意味着相同的文件在类似的代码行周围发生了变化,无法自动合并.在这种情况下,checkout将报告存在要解决的冲突.您可以通过编辑文件(将对其进行更改)来解决这些问题,选择所需的更改,从字面上删除不需要的更改行,然后保存文件.更改标记为分隔符,如mastergit pull origin master

一旦你解决了任何冲突,你将再次moved forwardgit pull那些更改继续合并(你将在这个过程中从git获得反馈来指导你).当这个过程不能正常工作时,你会发现git checkout your_branch重置它非常方便.

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

如果你已经完成了许多小步骤的工作,例如你每天将代码提交为"正在进行中",那么你可能希望将那些许多小提交"压缩"到一些较大的提交中.当您想与同事进行代码审查时,这可能特别有用.你不想重放你所采取的所有"步骤"(通过提交),你只想说这是我在一次提交中对这项工作的所有更改的最终结果(差异).在考虑是否执行此操作时要评估的关键因素是多次提交是否多次针对同一文件或文件(在这种情况下更好地压缩提交).这是通过交互式变基工具完成的.此工具允许您压缩提交,删除提交,重新编写消息等.例如,rebase 请注意,git merge new_branch不是a========表示以下内容:
Git中的交互式变基 但要小心,并小心翼翼地使用这个工具.一次进行一次压缩/删除/重新排序,退出并保存该提交,然后重新输入该工具.如果提交不连续,您可以重新排序(然后根据需要压缩).你实际上也可以在这里删除提交,但是当你这样做时,你真的需要确定你在做什么!

福克斯

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


Github上

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

当你'分叉' - 在github网页浏览器gui你可以点击 在此输入图像描述-您在创建代码的副本("克隆"),您的 GitHub的帐户.第一次执行此操作时可能会有点微妙,因此请务必确保查看其下方列出的代码库的存储库 - 原始所有者或"分叉"和您,例如在此输入图像描述
获得本地副本后,您可以根据需要进行更改(通过拉动并将其推送到本地计算机).当你完成后,你向原始存储库所有者/管理员提交一个"拉取请求"(听起来很奇特,但实际上你只需点击这个: - 在此输入图像描述并且他们"拉"进去.
对于一起编写代码的团队来说,更常见的是"克隆"存储库(单击存储库主屏幕上的"复制"图标).然后,本地输入git clone [paste]这将在本地设置你,你也可以推送到(共享)github位置.

克隆

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

可视化

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

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

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

gitg/gitx界面

虽然gitg/gitx相当小,但在过去的2 - 3年(2009-2012)中,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 '
Run Code Online (Sandbox Code Playgroud)

最后,6个关键救生员:

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

[alias]
  co = checkout
  cob = checkout -b
Run Code Online (Sandbox Code Playgroud)

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

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 !
Run Code Online (Sandbox Code Playgroud)

3)你搞砸了当前分支中的一个特定文件,并希望基本上"重置"该文件(丢失更改)到上次从远程存储库中提取它时的方式: <<<<<<<< 这实际上会重置文件(就像许多git一样)命令它没有很好地命名它在这里做什么).

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

5)你正在变形,但事情变得混乱:

git reset --hard origin/master  # You will need to be comfortable doing this!
Run Code Online (Sandbox Code Playgroud)

6)将你的git分支添加到你的PS1提示符(参见https://unix.stackexchange.com/a/127800/10043),例如在此输入图像描述
分支是 git commit

  • 是吧?subversion用户也可以编写一本关于使用subversion的书.我认为颠覆是一种功能较少的旧技术.我个人觉得git很容易使用.因人而异 (5认同)
  • 这么多文字!! 我会坚持我的简单Subversion :-) (4认同)
  • 哇,迈克尔!所有这些都与分享知识有关.感谢伟大的工作,绝对+1 (3认同)
  • 2012 年 6 月 16 日添加了有关克隆的部分,使其更加完整。 (2认同)

sir*_*ide 363

克隆只是存储库的副本.从表面上看,其结果相当于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在我下面的答案以获取更多信息.

  • fork并不一定意味着开发人员对主回购不满意.通常,这意味着另一个开发人员已经读取但不能写入对该存储库的访问权限.开发人员可以分配回购,进行更改,但由于他无法写入主回购,他必须将修改作为补丁提交.因此,分叉也是一种鼓励协作而不授予写访问权的方法. (124认同)
  • 你可以说fork是一个不希望在上游合并的分支 (32认同)
  • 我想这是真的.我只见过在创建一个新的,可能具有竞争性的项目版本的环境中使用的"fork". (5认同)
  • Git hub使用"fork"作为fork.它是一个存储在github上的新存储库,与原始文件分开.但是,github也使得实现pull请求变得非常简单.拉请求基本上要求原始存储库的所有者将更改从您的repo的分支"拉"回原点.这样,每个人都可以使用源代码控制并拥有所有更改的历史记录,包括他们的所有更改,但不是每个人都需要对原始仓库进行写入访问. (5认同)
  • 我已经更新了我的答案,告诉人们在github的模型上更多地了解Michael Durrant的答案. (4认同)

Con*_*ngo 142

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

在此输入图像描述

  • 可以更新此图像以添加"git clone",我确信大多数人都知道这种情况. (6认同)
  • @Gravitas,我真的很喜欢这个图形,但它并没有告诉我文件何时被覆盖以及它们何时被合并.你能让我知道这些命令是针对哪些的?也许顶部的覆盖命令和驱动器下面的合并命令?谢谢. (3认同)
  • 我会看看我是否可以更新版本的图表. (2认同)

Tim*_*art 7

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

请看这个图. (最初来自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')
Run Code Online (Sandbox Code Playgroud)

叉子

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

克隆

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


Alo*_*dal 6

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

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

git clone $some_other_repo
Run Code Online (Sandbox Code Playgroud)

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

作为VCS,Git实际上都是关于克隆分叉的.除了"只是浏览"使用远程UI如CGT文件,很少有做混帐回购协议不涉及分叉在某些时候克隆回购.

然而,

  • 当有人说我分叉回购X时,他们意味着他们在其他地方创建了回购的克隆,意图暴露给其他人,例如展示一些实验,或者应用不同的访问控制机制(例如,允许没有人Github访问但与公司内部帐户进行协作).

    事实是:repo很可能是用其他命令创建的 git clone,它最有可能是在服务器上的某个地方托管,而不是某人的笔记本电脑,而且很可能格式略有不同(它是一个"裸仓",即没有工作树)都只是技术细节.

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

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

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

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


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