大多数时候,当我尝试检出另一个现有分支时,如果我在当前分支上有一些未提交的更改,Git不允许我.所以我必须首先提交或存储这些更改.
但是,偶尔Git允许我签出另一个分支而不提交或存储这些更改,它会将这些更改带到我签出的分支.
这里的规则是什么?更改是分阶段还是未分阶段是否重要?将更改传递给另一个分支对我没有任何意义,为什么git有时会允许它?也就是说,它在某些情况下有用吗?
tor*_*rek 316
这里的观察是,在你开始工作之后branch1
(忘记或没有意识到最好先切换到另一个分支branch2
),你运行:
git checkout branch2
Run Code Online (Sandbox Code Playgroud)
有时Git说"好的,你现在就在branch2上了!" 有时,Git说"我不能那样做,我会失去你的一些改变."
如果Git 不允许你这样做,你必须提交你的更改,将它们永久保存在某个地方. 你可能想用它git stash
来保存它们; 这是它的设计之一. 请注意,git stash save
实际上意味着 "提交所有更改,但根本没有分支,然后将其从我现在的位置删除".这使得切换成为可能:您现在没有正在进行的更改.git stash push
切换后你就可以了.
如果Git 不允许你切换,你已经有了一个补救措施:使用git stash apply
或git stash save
; 或者,如果您的更改很容易重新创建,请使用git stash push
强制它.这个答案是所有关于何时混帐会让你git stash
即使你开始做一些改变.为什么它有时会起作用,而不是其他时候?
这里的规则在某种程度上是简单的,在另一种情况下是复杂的/难以解释的:
那是 - 请注意,这仍然是简化的; 有一些特别困难的角落案例,上演git stash
s,git commit
s等 - 假设你正在上演git checkout -f
.A git checkout branch2
必须这样做:
git add
与不中git rm
,1删除该文件.branch1
与不中git checkout branch2
,创建该文件(在适当的内容).branch1
不同,请更新工作树版本.这些步骤中的每一步都可能破坏工作树中的某些内容:
branch2
; 如果你做了改变,这是"不安全的".branch2
现在不存在,那么按照它出现的方式创建文件是"安全的".2 如果它现在确实存在但具有"错误"内容,则"不安全".branch1
.创建新的branch(branch2
)始终被视为"安全":作为此过程的一部分,工作树中不会添加,删除或更改任何文件,并且索引/暂存区域也不会受到影响.(警告:在创建新分支而不更改新分支的起点时是安全的;但是如果你添加另一个参数,例如branch1
,这可能需要改变一些东西,转移到branch2
.Git将照常应用结账安全规则.)
1这要求我们定义文件在分支中的含义,这又需要正确定义分支.(参见我们究竟由"分支"是什么意思?)这里,我真正的意思是提交到分支名称解析:其路径是一个文件是在如果产生了哈希值.如果您收到错误消息,则该文件不在.在回答此特定问题时,索引或工作树中路径的存在无关紧要.因此,这里的秘密是检查每一个的结果.这要么失败,因为文件最多只有一个分支,或者给我们两个哈希ID.如果两个哈希ID 相同,则两个分支中的文件相同.无需更改.如果散列ID不同,则两个分支中的文件不同,必须更改为切换分支.branch1
git checkout -b newbranch
git checkout -b newbranch different-start-point
different-start-point
P
branch1
git rev-parse branch1:P
这里的关键概念是提交中的文件永远被冻结.您要编辑的文件显然不会被冻结.至少在最初阶段,我们只关注两个冻结提交之间的不匹配. 不幸的是,我们-或Git的,还必须处理的文件是不是在提交你打算从开关路程,是在提交你要切换到.这导致了其余的复杂性,因为文件也可以存在于索引和/或工作树中,而不必存在我们正在使用的这两个特定的冻结提交.
2如果它已经存在"正确的内容",它可能被认为是"安全的",因此Git毕竟不必创建它.我记得至少有一些版本的Git允许这样做,但刚刚测试表明它在Git 1.8.5.4中被认为是"不安全的".相同的参数将适用于碰巧被修改以匹配to-be-switch-to分支的修改文件.同样,1.8.5.4只是说"会被覆盖".另请参阅技术说明的结尾:我的内存可能有问题,因为自从我第一次开始在版本1.5.something上使用Git以来,我认为读取树规则没有改变.
是的,在某些方面.特别是,您可以进行更改,然后"取消修改"工作树文件.这里有两个分支的文件,这是不同的branch1
和P
:
$ git show branch1:inboth
this file is in both branches
$ git show branch2:inboth
this file is in both branches
but it has more stuff in branch2 now
$ git checkout branch1
Switched to branch 'branch1'
$ echo 'but it has more stuff in branch2 now' >> inboth
Run Code Online (Sandbox Code Playgroud)
此时,即使我们正在运行,工作树文件也会git rev-parse
匹配.此更改不会在提交阶段进行,这是在此处显示的内容:branch-name:path
branch1
branch2
$ git status --short
M inboth
Run Code Online (Sandbox Code Playgroud)
space-then-M表示"已修改但未暂存"(或更确切地说,工作树副本与暂存/索引副本不同).
$ git checkout branch2
error: Your local changes ...
Run Code Online (Sandbox Code Playgroud)
好的,现在让我们暂存工作树副本,我们已经知道它也与副本相匹配inboth
.
$ git add inboth
$ git status --short
M inboth
$ git checkout branch2
Switched to branch 'branch2'
Run Code Online (Sandbox Code Playgroud)
这里的分段和工作副本都匹配了branch2
,所以允许结账.
让我们尝试另一个步骤:
$ git checkout branch1
Switched to branch 'branch1'
$ cat inboth
this file is in both branches
Run Code Online (Sandbox Code Playgroud)
我所做的更改现在从暂存区域丢失(因为结帐通过暂存区域写入).这是一个角落的案例.这种变化是不是走了,但事实上,我已经上演了,是走了.
让我们分析文件的第三个变体,不同于分支副本,然后设置工作副本以匹配当前分支版本:
$ echo 'staged version different from all' > inboth
$ git add inboth
$ git show branch1:inboth > inboth
$ git status --short
MM inboth
Run Code Online (Sandbox Code Playgroud)
branch1
这里的两个意思是:暂存文件与文件不同git status --short
,而工作树文件与暂存文件不同.工作树版本确实匹配branch2
(又名branch2
)版本:
$ git diff HEAD
$
Run Code Online (Sandbox Code Playgroud)
但是M
不允许结账:
$ git checkout branch2
error: Your local changes ...
Run Code Online (Sandbox Code Playgroud)
我们将HEAD
版本设置为工作版本:
$ git show branch2:inboth > inboth
$ git status --short
MM inboth
$ git diff HEAD
diff --git a/inboth b/inboth
index ecb07f7..aee20fb 100644
--- a/inboth
+++ b/inboth
@@ -1 +1,2 @@
this file is in both branches
+but it has more stuff in branch2 now
$ git diff branch2 -- inboth
$ git checkout branch2
error: Your local changes ...
Run Code Online (Sandbox Code Playgroud)
即使当前工作副本与中的工作副本匹配branch1
,分阶段文件也不会,因此a HEAD
将丢失该副本,并且git checkout
被拒绝.
所有这些的基础实现机制是Git的索引.索引,也称为"临时区域",是您构建下一个提交的地方:它开始匹配当前提交,即,无论您现在签出什么,然后每次您branch2
一个文件,您替换索引版本随你工作树中的任何东西.
请记住,工作树是您处理文件的地方.在这里,它们具有它们的正常形式,而不是像它们在提交和索引中那样的一些特殊的有用的Git形式.因此,您通过索引从提交中提取文件,然后再将其提取到工作树中.更改后,您将其添加到索引中.因此,每个文件实际上有三个位置:当前提交,索引和工作树.branch2
当您运行git checkout
,什么混帐做封面的下面是比较尖承诺的git checkout
到无论是在双方最近提交现在的指数.任何与现在相匹配的文件,Git都可以单独留下.这一切都没有动过.在两次提交中都是相同的任何文件,Git也可以单独留下 - 这些是允许你切换分支的文件.
由于这个索引,很多Git,包括提交切换,都相对较快.索引中的实际内容不是每个文件本身,而是每个文件的哈希值.文件本身的副本存储为Git 在存储库中调用blob对象的内容.这类似于文件在提交中的存储方式:提交实际上不包含文件,它们只是将Git引导到每个文件的哈希ID.因此Git可以比较散列ID(当前是160位长的字符串)来决定提交X和Y是否具有相同的文件.然后,它可以将这些散列ID与索引中的散列ID进行比较.
这就是导致上面所有奇怪角落情况的原因.我们提交的X和Y都有文件git add
,我们有一个索引条目git add
.也许所有三个哈希都匹配.也许其中两个匹配,一个不匹配.也许三者都不同.而且,我们也可能git checkout branch2
只在X中或仅在Y中,现在是或者不在索引中.这些不同情况中的每一种都需要单独考虑:Git 是否需要将文件从提交复制到索引,或者从索引中删除它,从X切换到Y?如果是这样,它还必须将文件复制到工作树,或将其从工作树中删除.如果是这种情况,索引和工作树版本最好匹配至少一个已提交的版本; 否则Git会破坏一些数据.
(所有这些的完整规则都在描述中,而不是branch2
您可能期望的path/to/name.txt
文档,而是文档,在标题为"Two Tree Merge"的部分中.)
Rob*_*Rob 47
您有两种选择:存储您的更改:
git stash
Run Code Online (Sandbox Code Playgroud)
然后再让他们回来:
git stash apply
Run Code Online (Sandbox Code Playgroud)
或者将更改放在分支上,这样您就可以获得远程分支,然后将更改合并到其上.这是git最棒的事情之一:你可以创建一个分支,提交它,然后获取其他更改到你所在的分支.
你说它没有任何意义,但你只是这样做,所以你可以在拉动后随意合并它们.显然,你的另一个选择是提交你的分支副本然后做拉.假设你要么不想这样做(在这种情况下我很困惑你不想要一个分支)或者你害怕冲突.
Gor*_*lio 12
如果新分支包含与该特定更改文件的当前分支不同的编辑,则在提交或隐藏更改之前,它将不允许您切换分支.如果两个分支上的更改文件相同(即该文件的已提交版本),则可以自由切换.
例:
$ echo 'hello world' > file.txt
$ git add file.txt
$ git commit -m "adding file.txt"
$ git checkout -b experiment
$ echo 'goodbye world' >> file.txt
$ git add file.txt
$ git commit -m "added text"
# experiment now contains changes that master doesn't have
# any future changes to this file will keep you from changing branches
# until the changes are stashed or committed
$ echo "and we're back" >> file.txt # making additional changes
$ git checkout master
error: Your local changes to the following files would be overwritten by checkout:
file.txt
Please, commit your changes or stash them before you can switch branches.
Aborting
Run Code Online (Sandbox Code Playgroud)
这适用于未跟踪的文件以及跟踪的文件.这是一个未跟踪文件的示例.
例:
$ git checkout -b experimental # creates new branch 'experimental'
$ echo 'hello world' > file.txt
$ git add file.txt
$ git commit -m "added file.txt"
$ git checkout master # master does not have file.txt
$ echo 'goodbye world' > file.txt
$ git checkout experimental
error: The following untracked working tree files would be overwritten by checkout:
file.txt
Please move or remove them before you can switch branches.
Aborting
Run Code Online (Sandbox Code Playgroud)
一个很好的例子说明为什么你想要在进行更改时在分支之间移动,如果你在master上进行一些实验,想要提交它们,但是还没有掌握...
$ echo 'experimental change' >> file.txt # change to existing tracked file
# I want to save these, but not on master
$ git checkout -b experiment
M file.txt
Switched to branch 'experiment'
$ git add file.txt
$ git commit -m "possible modification for file.txt"
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
121501 次 |
最近记录: |