被git checkout弄糊涂了 [英] Confused by git checkout

查看:130
本文介绍了被git checkout弄糊涂了的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是git的新手,并试图将我的头围绕分支的工作方式.根据文档git checkout

更新工作树中的文件以匹配索引或指定树中的版本.如果未提供任何路径,则git checkout还将更新HEAD,以将指定的分支设置为> current分支.

据我了解,我工作所在目录中的文件(执行git init的文件)应该根据我所在的分支而改变.我很困惑,因为当我在两个分支之间进行切换时,这不会发生分支机构.在切换分支之前,我正在进行的编辑工作存在于切换到的分支中.我是在做错什么,还是git checkout不能以这种方式工作,而我只是误解了文档?

解决方案

Git有一个普遍的问题,即将8或10种不同的东西塞进一个命令中. 注意:Git 2.23正在拆分其中的一些内容-可以肯定的是,这是有益的,但也是非常大的变化.( Git 2.23是否应称为Git 3.0?Git 2.0改变了git add,在我看来,程度相似.)另请参见 VonC的答案.

git checkout 可以更新工作树,通常可以.

可以更改HEAD指向的位置,有时指向,有时不指向.

它可以 覆盖您对文件所做的工作,以防您想重置文件并撤消工作.或者可以拒绝覆盖您对文件所做的工作,在更改HEAD更改HEAD时将其保留不变.

关于这一切的事情是,尽管很难描述,但实际上这一切都是有道理的,经过一段时间后,您习惯了这一点,并且发现一个命令在大多数情况下都能满足您的要求. (当然,这可能是大多数时候"的问题.)

无论如何,您看到的特定行为是故意的.假设您像大多数存储库一样从分支master开始:

$ git clone ...
$ git branch
* master
$

这时,您可能会编辑一些文件,进行一些工作,然后才意识到:啊!我打算在分支develop上这样做!" 1

此时git允许您执行的操作是在一种情况下切换(或创建)分支develop保留您的修改:切换到develop不需要清除它们.假设您修改了文件f1并创建了一个新的f2,现在您要创建并检出应从其开始的本地分支develop,并自动跟踪", 2 origin/develop:

$ git checkout develop 

(在git的旧版本中,您必须拼写git checkout -b develop --track origin/develop).

我们也可以说分支master和分支develop的提示处的文件f1是相同的. 3 对git而言,这意味着可以进行此签出,因为它不必修改文件f1,因此可以将对f1的现有更改保留在原处.

如果两个提交中的文件f2 相同,或者(在这种情况下)两者都不存在,则不会破坏文件,并且git checkout将创建新的本地分支develop,根据需要修改工作树以匹配origin/develop-这不包括修改f1或删除f2,因此到目前为止您所做的工作保持不变.

这使您可以将新更改提交到本地develop.

((如果遇到git 确实需要撤消您的更改,但仍然想将它们移动"到另一个分支的情况,通常的技巧是使用git stash脚本.这是听起来很简单,git stash通常很容易使用,但实际上它是一个相当复杂的小野兽.不过,直到您需要它时都不必担心.)


1 这总是在我身上发生 .很多时候,我想创建一个新的非跟踪分支,这比切换到现有分支要简单一些,但是原理仍然适用.

2 此自动跟踪功能使您可以更轻松地引入其他人所做的更改:一旦git用git fetch进行更改,git就会通知您有关其他人的更改,并且允许您使用git mergegit rebase将您的更改与他们的更改组合在一起,而无需进行过多的拨弄即可确定谁的更改在何处.

3 由于您是git的新手,所以像区分分支的尖端"(是一个特定的提交)和分支"(实际上是模棱两可的)之类的概念就存在了-有分支 labels ,然后由提交树形成分支结构-这是您暂时应该忽略的其他内容.需要注意的主要事情是,git存储库中有一个名为HEAD的特殊文件,在该特殊文件中,git编写字符串ref: refs/heads/masterref: refs/heads/develop,以便跟踪您所在的分支.因此,一旦git checkout X切换到分支X,就会将ref: refs/heads/X写入HEAD.

同时,存储库中的另一组特殊文件告诉git分支master引用了像c06f8d11b75e28328cdc809397eddd768ebeb533这样的大型丑陋SHA-1中的一个.这是分支master的提示".当您在master上进行新提交时,git会在旧提示之后"创建新提交,然后将新的SHA-1写入分支文件,因此master现在是您的新提交.

确切的细节并不重要,因为 new 提交的想法只是推动分支提示.

I am new to git and trying to wrap my head around the way branches work. According to the documentation git checkout

Updates files in the working tree to match the version in the index or the specified tree. If >no paths are given, git checkout will also update HEAD to set the specified branch as the >current branch.

So as I understand it the files in my directory that I work in (the file I performed the git init in) would should change according to what branch I am in. I am confused because this does not happen when I change between branches. Edits I was working on before I switched branches are present in the branch I switched to. Am I doing something wrong or does git checkout not work this way and I am just misunderstanding the docs?

解决方案

Git has this general issue of cramming about eight or ten different things into one command. Note: Git 2.23 is splitting some of these up—helpful, to be sure, but also a very big change. (Should Git 2.23 be called Git 3.0? Git 2.0 changed the behavior of git add, which seems to me similar in degree.) See also VonC's answer.

git checkout can update the working tree, and usually does.

It can change where HEAD points, and sometimes does, sometimes doesn't.

It can overwrite work you did to a file, in case you want to reset the file and undo your work. Or it can refuse to overwrite work you did to a file, leaving it unchanged while either changing HEAD, or not changing HEAD.

The thing about all this is that, while it's remarkably difficult to describe, it actually all makes sense and after a while you get used to this and find that the one command does what you mean, most of the time. (It's that "most of the time" that can be a problem, of course....)

Anyway, the particular behavior you're seeing is a deliberate feature. Let's say you start out on branch master, as most repositories do:

$ git clone ...
$ git branch
* master
$

At this point you might edit some file(s), get some work going, and only then realize: "gah! I meant to do this on branch develop!"1

What git lets you do at this point is switch to (or create) branch develop, keeping your modifications, under one condition: that switching to develop does not require wiping them out. Let's say you modified file f1 and created a new f2, and you now want to create and check out local branch develop that should start from, and automatically "track",2 origin/develop:

$ git checkout develop 

(in very old versions of git, you have to spell this git checkout -b develop --track origin/develop).

Let's also say that file f1 is the same at the tips of branch master and branch develop.3 What this means, to git, is that it can do this checkout, because it does not have to modify file f1, so it can leave your existing changes to f1 in place.

If file f2 is also the same in both commits, or (as in this case) does not exist in either one, then no files will be clobbered, and git checkout will create your new local branch develop, modifying the work tree to match origin/develop as needed—and this does not include modifying f1, nor removing f2, so the work you have done so far remains intact.

This allows you to commit your new changes to your local develop.

(If you run into cases where git does have to undo your changes, but still want to "move" them to another branch, the usual trick is to use the git stash script. This sounds like a simple thing, and git stash is often simple to use, but it is actually quite a complicated little beast under the covers. Don't worry about that until you need it, though.)


1This happens to me all the time. Many times I want to create a new non-tracking branch, which is a bit simpler than switching to an existing branch, but the principle still applies.

2This automatic tracking allows you to more easily bring in changes other people have done: once git picks them up with git fetch, git will inform you about those other-people's-changes, and let you use git merge or git rebase to combine your changes with theirs, without a lot of extra poking-about to figure out whose changes go where.

3Since you're new to git, concepts like distinguishing "the tip of a branch", which is a specific commit, from "the branch", which is actually ambiguous—there are branch labels, and then there are branch structures formed by the commit tree—is something else you mostly should ignore for a while. The main thing to note is that there's a special file in the git repository named HEAD, and in that special file, git writes the string ref: refs/heads/master or ref: refs/heads/develop, in order to keep track of which branch you're on. So git checkout X will write ref: refs/heads/X into HEAD once it switches to branch X.

Meanwhile, another set of special files in the repository tell git that branch master refers to one of those big ugly SHA-1s like c06f8d11b75e28328cdc809397eddd768ebeb533. This is the "tip" of branch master. When you make a new commit on master, git creates the new commit "one past the old tip", then writes the new SHA-1 into the branch files, so that master is now your new commit.

The precise details don't matter so much as the idea that new commits simply advance the branch-tip.

这篇关于被git checkout弄糊涂了的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆