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

类似地,git fetch和git pull是什么意思?

另外,与合并相比,rebase意味着什么?

我怎样才能把自己压在一起?

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

GitHub是怎么回事?


当前回答

只是补充一下,关于分叉的特别说明。

从技术上讲,克隆回购和分叉回购是同一件事,认识到这一点很好。做的事:

git clone $some_other_repo

你可以拍拍自己的背——你刚刚完成了另一个回购。

Git,作为一个VCS,实际上就是关于克隆和分叉的。除了使用远程UI(如cgit)“只是浏览”之外,git回购几乎没有什么不涉及在某些时候分叉克隆回购的事情。

然而,

when someone says I forked repo X, they mean that they have created a clone of the repo somewhere else with intention to expose it to others, for example to show some experiments, or to apply different access control mechanism (eg. to allow people without Github access but with company internal account to collaborate). Facts that: the repo is most probably created with other command than git clone, that it's most probably hosted somewhere on a server as opposed to somebody's laptop, and most probably has slightly different format (it's a "bare repo", ie. without working tree) are all just technical details. The fact that it will most probably contain different set of branches, tags or commits is most probably the reason why they did it in the first place. (What Github does when you click "fork", is just cloning with added sugar: it clones the repo for you, puts it under your account, records the "forked from" somewhere, adds remote named "upstream", and most importantly, plays the nice animation.) When someone says I cloned repo X, they mean that they have created a clone of the repo locally on their laptop or desktop with intention study it, play with it, contribute to it, or build something from source code in it.

Git的美妙之处在于它使这一切完美地结合在一起:所有这些回购共享区块提交链的公共部分,因此可以安全地(见下面的注释)在所有这些回购之间来回合并更改,只要你认为合适。


注意:“安全”,只要你不重写链的公共部分,只要这些变化不冲突。

其他回答

只是补充一下,关于分叉的特别说明。

从技术上讲,克隆回购和分叉回购是同一件事,认识到这一点很好。做的事:

git clone $some_other_repo

你可以拍拍自己的背——你刚刚完成了另一个回购。

Git,作为一个VCS,实际上就是关于克隆和分叉的。除了使用远程UI(如cgit)“只是浏览”之外,git回购几乎没有什么不涉及在某些时候分叉克隆回购的事情。

然而,

when someone says I forked repo X, they mean that they have created a clone of the repo somewhere else with intention to expose it to others, for example to show some experiments, or to apply different access control mechanism (eg. to allow people without Github access but with company internal account to collaborate). Facts that: the repo is most probably created with other command than git clone, that it's most probably hosted somewhere on a server as opposed to somebody's laptop, and most probably has slightly different format (it's a "bare repo", ie. without working tree) are all just technical details. The fact that it will most probably contain different set of branches, tags or commits is most probably the reason why they did it in the first place. (What Github does when you click "fork", is just cloning with added sugar: it clones the repo for you, puts it under your account, records the "forked from" somewhere, adds remote named "upstream", and most importantly, plays the nice animation.) When someone says I cloned repo X, they mean that they have created a clone of the repo locally on their laptop or desktop with intention study it, play with it, contribute to it, or build something from source code in it.

Git的美妙之处在于它使这一切完美地结合在一起:所有这些回购共享区块提交链的公共部分,因此可以安全地(见下面的注释)在所有这些回购之间来回合并更改,只要你认为合适。


注意:“安全”,只要你不重写链的公共部分,只要这些变化不冲突。

A clone is simply a copy of a repository. On the surface, its result is equivalent to svn checkout, where you download source code from some other repository. The difference between centralized VCS like Subversion and DVCSs like Git is that in Git, when you clone, you are actually copying the entire source repository, including all the history and branches. You now have a new repository on your machine and any commits you make go into that repository. Nobody will see any changes until you push those commits to another repository (or the original one) or until someone pulls commits from your repository, if it is publicly accessible.

A branch is something that is within a repository. Conceptually, it represents a thread of development. You usually have a master branch, but you may also have a branch where you are working on some feature xyz, and another one to fix bug abc. When you have checked out a branch, any commits you make will stay on that branch and not be shared with other branches until you merge them with or rebase them onto the branch in question. Of course, Git seems a little weird when it comes to branches until you look at the underlying model of how branches are implemented. Rather than explain it myself (I've already said too much, methinks), I'll link to the "computer science" explanation of how Git models branches and commits, taken from the Git website:

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

A fork isn't a Git concept really, it's more a political/social idea. That is, if some people aren't happy with the way a project is going, they can take the source code and work on it themselves separate from the original developers. That would be considered a fork. Git makes forking easy because everyone already has their own "master" copy of the source code, so it's as simple as cutting ties with the original project developers and doesn't require exporting history from a shared repository like you might have to do with SVN.

编辑:因为我不知道像GitHub这样的网站使用的“fork”的现代定义,请看看评论和Michael Durrant在我下面的回答以获得更多信息。

Git

这个答案包括GitHub,因为许多人也问过这个问题。

局部存储库

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

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

Git根本不“锁定”文件,因此避免了编辑时的“独占锁定”功能(我想到了像pvcs这样的旧系统),所以所有文件都可以编辑,即使是在脱机时。它实际上做了一个惊人的工作,在拉取/推到远程存储库(如GitHub)期间合并文件更改(在同一个文件中!)。唯一需要手动更改(实际编辑文件)的情况是,如果两个更改涉及同一行代码。


分支机构

Branches allow you to preserve the main code (the 'master' branch), make a copy (a new branch) and then work within that new branch. If the work takes a while or master gets a lot of updates since the branch was made then merging or rebasing (often preferred for better history and easier to resolve conflicts) against the master branch should be done. When you've finished, you merge the changes made in the branch back in to the master repository. Many organizations use branches for each piece of work whether it is a feature, bug or chore item. Other organizations only use branches for major changes such as version upgrades.

Fork:使用分支时,您可以控制和管理分支,而使用Fork时,其他人可以控制接受代码。

Broadly speaking, there are two main approaches to doing branches. The first is to keep most changes on the master branch, only using branches for larger and longer-running things like version changes where you want to have two branches available for different needs. The second is whereby you basically make a branch for every feature request, bug fix or chore and then manually decide when to actually merge those branches into the main master branch. Though this sounds tedious, this is a common approach and is the one that I currently use and recommend because this keeps the master branch cleaner and it's the master that we promote to production, so we only want completed, tested code, via the rebasing and merging of branches.

将分支“引入”到master的标准方法是进行合并。分支也可以“重基”以“清理”历史。它不会影响当前状态,这样做是为了提供一个“更干净”的历史记录。

Basically, the idea is that you branched from a certain point (usually from master). Since you branched, 'master' itself has since moved forward from that branching point. It will be 'cleaner' (easier to resolve issues and the history will be easier to understand) if all the changes you have done in a branch are played against the current state of master with all of its latest changes. So, the process is: save the changes; get the 'new' master, and then reapply (this is the rebase part) the changes again against that. Be aware that rebase, just like merge, can result in conflicts that you have to manually resolve (i.e. edit and fix).

需要注意的一个指导原则: 只有当分支是本地的,并且您还没有将其推到远程时,才会重新赋值! 这主要是因为重基会改变其他人看到的历史记录,其中可能包括他们自己的提交。

跟踪分支

These are the branches that are named origin/branch_name (as opposed to just branch_name). When you are pushing and pulling the code to/from remote repositories this is actually the mechanism through which that happens. For example, when you git push a branch called building_groups, your branch goes first to origin/building_groups and then that goes to the remote repository. Similarly, if you do a git fetch building_groups, the file that is retrieved is placed in your origin/building_groups branch. You can then choose to merge this branch into your local copy. Our practice is to always do a git fetch and a manual merge rather than just a git pull (which does both of the above in one step).

获取新的分支。

Getting new branches: At the initial point of a clone you will have all the branches. However, if other developers add branches and push them to the remote there needs to be a way to 'know' about those branches and their names in order to be able to pull them down locally. This is done via a git fetch which will get all new and changed branches into the locally repository using the tracking branches (e.g., origin/). Once fetched, one can git branch --remote to list the tracking branches and git checkout [branch] to actually switch to any given one.

合并

Merging is the process of combining code changes from different branches, or from different versions of the same branch (for example when a local branch and remote are out of sync). If one has developed work in a branch and the work is complete, ready and tested, then it can be merged into the master branch. This is done by git checkout master to switch to the master branch, then git merge your_branch. The merge will bring all the different files and even different changes to the same files together. This means that it will actually change the code inside files to merge all the changes.

When doing the checkout of master it's also recommended to do a git pull origin master to get the very latest version of the remote master merged into your local master. If the remote master changed, i.e., moved forward, you will see information that reflects that during that git pull. If that is the case (master changed) you are advised to git checkout your_branch and then rebase it to master so that your changes actually get 'replayed' on top of the 'new' master. Then you would continue with getting master up-to-date as shown in the next paragraph.

If there are no conflicts, then master will have the new changes added in. If there are conflicts, this means that the same files have changes around similar lines of code that it cannot automatically merge. In this case git merge new_branch will report that there's conflict(s) to resolve. You 'resolve' 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 want and then saving the file. The changes are marked with separators such as ======== and <<<<<<<<.

一旦你解决了任何冲突,你将再次git添加和git提交这些更改来继续合并(你将在这个过程中从git得到反馈来指导你)。

当这个过程不能很好地工作时,你会发现git merge——abort非常方便地重置东西。

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

如果你已经完成了很多小步骤的工作,例如,你每天都将代码作为“半成品”提交,你可能想要将这些小的提交“压缩”成几个更大的提交。当您希望与同事一起进行代码审查时,这可能特别有用。你不想重放你所采取的所有“步骤”(通过提交),你只想说这里是我在一次提交中对此工作的所有更改的最终效果(diff)。

在考虑是否这样做时,要评估的关键因素是多个提交是针对同一个文件还是针对多个文件(在这种情况下,最好压缩提交)。这是用交互式重基工具完成的。这个工具允许你压缩提交、删除提交、改写消息等。例如,git rebase -i HEAD~10(注意:这是~,而不是-)会显示以下内容:

但是要小心,小心地使用这个工具。每次执行一次压缩/删除/重新排序,退出并保存提交,然后重新进入工具。如果提交不是连续的,你可以重新排序它们(然后根据需要进行压缩)。实际上,你也可以在这里删除提交,但你真的需要确定你在做什么!

There are two main approaches to collaboration in Git repositories. The first, detailed above, is directly via branches that people pull and push from/to. These collaborators have their SSH keys registered with the remote repository. This will let them push directly to that repository. The downside is that you have to maintain the list of users. The other approach - forking - allows anybody to 'fork' the repository, basically making a local copy in their own Git repository account. They can then make changes and when finished send a 'pull request' (really it's more of a 'push' from them and a 'pull' request for the actual repository maintainer) to get the code accepted.

第二种方法使用fork,不需要维护存储库的用户列表。


GitHub

GitHub(一个远程存储库)是一个远程源,如果你有(或被添加到)这样的存储库,你通常会推送和拉那些提交的更改,所以本地和远程实际上是非常不同的。另一种考虑远程存储库的方式是,它是位于远程服务器上的.git目录结构。

当你“分叉”-在GitHub web浏览器GUI中,你可以点击这个按钮-你在你的GitHub帐户中创建了代码的副本(“克隆”)。第一次这样做的时候可能会有点微妙,所以要确保你看看代码库是在谁的存储库下面列出的——要么是原始所有者,要么是“从谁派生出来的”,例如,像这样:

一旦有了本地副本,就可以按照自己的意愿进行更改(通过将它们拉到本地机器)。当你完成后,你提交一个“拉请求”给原来的存储库所有者/管理员(听起来很花哨,但实际上你只需要点击这个),他们就会“拉”进去。

对于一起编写代码的团队来说,更常见的是“克隆”存储库(单击存储库主屏幕上的“复制”图标)。然后,在本地输入git克隆和粘贴。这将在本地设置你,你也可以推拉到(共享)GitHub位置。

克隆

As indicated in the section on GitHub, a clone is a copy of a repository. When you have a remote repository you issue the git clone command against its URL and you then end up with a local copy, or clone, of the repository. This clone has everything, the files, the master branch, the other branches, all the existing commits, the whole shebang. It is this clone that you do your adds and commits against and then the remote repository itself is what you push those commits to. It's this local/remote concept that makes Git (and systems similar to it such as Mercurial) a DVCS (Distributed Version Control System) as opposed to the more traditional CVSs (Code Versioning Systems) such as SVN, PVCS, CVS, etc. where you commit directly to the remote repository.

可视化

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

如果你想要一个可视化的显示变化是如何工作的,你不能用一个GUI来打败可视化工具gitg (macOS的gitx),我称之为“地铁地图”(尤其是伦敦地铁),它非常适合显示谁做了什么,事情是如何变化的,发散和合并等。

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

尽管gitg/gitx相当少,但GUI工具的数量在不断增加。许多Mac用户使用brother - bard的gitx分支,对于Linux来说,智能git是一个很好的选择,它具有直观而强大的界面:

请注意,即使使用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] <- tab补全分支将工作。

GUI学习工具

您可能会发现https://learngitbranching.js.org/在学习一些基本概念时很有用。屏幕截图: 的视频:https://youtu.be/23JqqcLPss0

最后,7个关键的救星!

You make changes, add and commit them (but don't push) and then oh! you realize you are in master! 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 ! You mess up some files while working in a local branch and simply want to go back to what you had the last time you did a git pull: git reset --hard origin/master # You will need to be comfortable doing this! You start making changes locally, you edit half a dozen files and then, oh crap, you're still in the master (or another) branch: 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 You mess up one particular file in your current branch and want to basically 'reset' that file (lose changes) to how it was the the last time you pulled it from the remote repository: git checkout your/directories/filename This actually resets the file (like many Git commands it is not well named for what it is doing here). You make some changes locally, you want to make sure you don't lose them while you do a git reset or rebase: I often make a manual copy of the entire project (cp -r ../my_project ~/) when I am not sure if I might mess up in Git or lose important changes. You are rebasing but things gets messed up: git rebase --abort # To abandon interactive rebase and merge issues Add your Git branch to your PS1 prompt (see https://unix.stackexchange.com/a/127800/10043), e.g. The branch is selenium_rspec_conversion.

以下是奥利弗·斯蒂尔(Oliver Steele)描绘的这一切是如何结合在一起的:

Fork Vs. Clone——这两个词的意思都是复制

请看这张图表。(原文来自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

一个拷贝到你的远程回购(云),链接到乔的 一个副本,然后你可以克隆到你的本地回购和F*%$ up 当你完成后,你可以回到你的遥控器 然后,您可以通过单击pull-request来询问Joe是否希望在他的项目中使用它

克隆

拷贝到本地回购(硬盘)