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

查看原始版本

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

类似地,当我做一个git fetch而不是一个git pull时,这意味着什么?

还有,rebasemerge相比意味着什么?

我怎么能把个人承诺压扁在一起?

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

GitHub是如何计算的?

所有回答
  • Simona Lee #1

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

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

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

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

    编辑:由于我不知道GitHub等网站使用的“fork”的现代定义,请查看评论以及我下面的Michael Durrant's answer了解更多信息

  • Rebecca Lee #2

    Git

    This answer includes GitHub as many folks have asked about that too.

    Local repositories

    Git (locally) has a directory (.git) which you commit your files to and this is your 'local repository'. This is different from systems like SVN where you add and commit to the remote repository immediately.

    Git stores each version of a file that changes by saving the entire file. It is also different from SVN in this respect as you could go to any individual version without 'recreating' it through delta changes.

    Git doesn't 'lock' files at all and thus avoids the 'exclusive lock' functionality for an edit (older systems like pvcs come to mind), so all files can always be edited, even when off-line. It actually does an amazing job of merging file changes (within the same file!) together during pulls or fetches/pushes to a remote repository such as GitHub. The only time you need to do manual changes (actually editing a file) is if two changes involve the same line(s) of code.


    Branches

    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: With a branch you control and manage the branch, whereas with a fork someone else controls accepting the code back in.

    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.

    The standard way to bring a branch 'in' to master is to do a merge. Branches can also be "rebased" to 'clean up' history. It doesn't affect the current state and is done to give a 'cleaner' history.

    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).

    One guideline to note:
    Only rebase if the branch is local and you haven't pushed it to remote yet!
    This is mainly because rebasing can alter the history that other people see which may include their own commits.

    Tracking branches

    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).

    Fetching new branches.

    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

    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 <<<<<<<<.

    Once you have resolved any conflicts you will once again git add and git commit those changes to continue the merge (you'll get feedback from git during this process to guide you).

    When the process doesn't work well you will find that git merge --abort is very handy to reset things.

    Interactive rebasing and squashing / reordering / removing commits

    If you have done work in a lot of small steps, e.g., you commit code as 'work-in-progress' every day, you may want to 'squash' those many small commits into a few larger commits. This can be particularly useful when you want to do code reviews with colleagues. You don't want to replay all the 'steps' you took (via commits), you want to just say here is the end effect (diff) of all of my changes for this work in one commit.

    The key factor to evaluate when considering whether to do this is whether the multiple commits are against the same file or files more than once (better to squash commits in that case). This is done with the interactive rebasing tool. This tool lets you squash commits, delete commits, reword messages, etc. For example, git rebase -i HEAD~10 (note: that's a ~, not a -) brings up the following:

    interactive rebasing in Git

    Be careful though and use this tool 'gingerly'. Do one squash/delete/reorder at a time, exit and save that commit, then reenter the tool. If commits are not contiguous you can reorder them (and then squash as needed). You can actually delete commits here too, but you really need to be sure of what you are doing when you do that!

    Forks

    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.

    This second method, using forks, does not require someone to maintain a list of users for the repository.


    GitHub

    GitHub (a remote repository) is a remote source that you normally push and pull those committed changes to if you have (or are added to) such a repository, so local and remote are actually quite distinct. Another way to think of a remote repository is that it is a .git directory structure that lives on a remote server.

    When you 'fork' - in the GitHub web browser GUI you can click on this button Image of fork button - you create a copy ('clone') of the code in your GitHub account. It can be a little subtle first time you do it, so keep making sure you look at whose repository a code base is listed under - either the original owner or 'forked from' and you, e.g., like this:

    Image of name of forked repository

    Once you have the local copy, you can make changes as you wish (by pulling and pushing them to a local machine). When you are done then you submit a 'pull request' to the original repository owner/admin (sounds fancy but actually you just click on this: Image of pull request button) and they 'pull' it in.

    More common for a team working on code together is to 'clone' the repository (click on the 'copy' icon on the repository's main screen). Then, locally type git clone and paste. This will set you up locally and you can also push and pull to the (shared) GitHub location.

    Clones

    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.

    Visualization

    Visualization of the core concepts can be seen at
    http://marklodato.github.com/visual-git-guide/index-en.html and
    http://ndpsoftware.com/git-cheatsheet.html#loc=index

    If you want a visual display of how the changes are working, you can't beat the visual tool gitg (gitx for macOS) with a GUI that I call 'the subway map' (esp. London Underground), great for showing who did what, how things changes, diverged and merged, etc.

    You can also use it to add, commit and manage your changes!

    Image of gitg/gitx interface

    Although gitg/gitx is fairly minimal, the number of GUI tools continues to expand. Many Mac users use brotherbard's fork of gitx and for Linux, a great option is smart-git with an intuitive yet powerful interface:

    Image of smart-git GUI

    Note that even with a GUI tool, you will probably do a lot of commands at the command line.

    For this, I have the following aliases in my ~/.bash_aliases file (which is called from my ~/.bashrc file for each terminal session):

    # 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 '
    

    AND I have the following "git aliases" in my ~/.gitconfig file - why have these ?
    So that branch completion (with the TAB key) works !

    So these are:

    [alias]
      co = checkout
      cob = checkout -b
    

    Example usage: git co [branch] <- tab completion for branches will work.

    GUI Learning Tool

    You may find https://learngitbranching.js.org/ useful in learning some of the base concepts. Screen shot: enter image description here
    Video: https://youtu.be/23JqqcLPss0

    Finally, 7 key lifesavers!

    1. 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 !
      
    2. 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!
      
    3. 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
      
    4. 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).

    5. 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.

    6. You are rebasing but things gets messed up:

      git rebase --abort # To abandon interactive rebase and merge issues
      
    7. Add your Git branch to your PS1 prompt (see https://unix.stackexchange.com/a/127800/10043), e.g.

      Image of prompt

      The branch is selenium_rspec_conversion.

  • Selena Lee #3

    以下是奥利弗·斯蒂尔对这一切的看法:

    enter image description here

  • Avery Lee #4

    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

    • 一份到你的远程回购(云)的副本,将其链接到Joe的
    • 然后可以复制到本地回购和F*%$-上
    • 完成后,您可以推回到遥控器
    • 然后,您可以通过单击pull request来询问Joe是否希望在项目中使用它

    Clone

    • 本地回购协议副本(硬盘)
  • Eunice Lee #5

    只是为了给其他人增加一点,特别是叉子

    很高兴认识到,从技术上讲,克隆回购和分叉回购是同一回事。做:

    git clone $some_other_repo
    

    你也可以拍自己的后背——你刚刚又做了些回购

    Git作为一个风投公司,事实上是关于克隆的。除了使用远程用户界面(如cgit)进行“浏览”,与git repo没有什么关系,因为git repo在某些时候不涉及到克隆repo

    然而

    • 当有人说I forked repo X时,他们的意思是他们创造了 在其他地方复制回购协议,意图将其暴露于 其他,例如展示一些实验,或应用不同的 访问控制机制(例如,允许没有Github访问权限的用户,但是 与公司内部账户合作)

      事实是:repo很可能是用其他命令创建的,而不是 git clone,它很可能是作为 与某人的笔记本电脑相反,而且很可能有点不同 格式(这是一个“裸回购”,即没有工作树)都只是 技术细节

      它很可能包含不同的分支集, 标记或提交很可能是他们在第一个 地点

      (当您单击“fork”时,Github所做的只是添加 糖:它为你复制回购协议,把它放在你的账户下,记录 从某处“分叉”,添加了remote命名为“upstream”,并且大多数 重要的是,播放好的动画。)

    • 当有人说I cloned repo X时,他们的意思是他们创造了 在笔记本电脑或台式机上本地复制回购协议 研究它,玩它,贡献它,或者从源头上建立一些东西 里面有密码

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


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