我有一个承诺的树,已经成为一种很难做出来,无序。所以,我觉得我需要进行清洁。这将会是真棒,如果你能帮助我解决这个问题。
我工作的这在某些时候与两个分支B和C.每个分支我看到当我登录每个分支以下几个提交后延伸项目一个。我总结了日志,让我知道,如果它无法读取。
master:
commit: B2 (HEAD -> master, origin/master, origin/HEAD)
commit: B1
commit: A3
...
branch_B:
commit: B2 (HEAD -> branch_B)
commit: C3
commit: C2 (branch_C)
commit: C1
commit: B1
commit: A3
...
branch_C:
commit: C2 (HEAD -> branch_C)
commit: C1
commit: B1
commit: A3
...
编辑:具体地讲,我想从主除去B1和B2,从branch_C除去B1,从branch_B除去C1,C2,和C3以及移动C3回branch_C。
Git是建造,因此“希望”在一定意义上,添加新的提交,但从来没有删除任何旧的。它可以去除提交,但是:
有了这样的方式,这里是你如何做到这一点,利用git cherry-pick
和git reset
。还有就是要做到这一点,但让我们在这里这两个命令的方法不止一种。
正如你已经看到的,每次提交都有一个唯一的哈希ID-一些又大又丑的字符串,如b5101f929789889c2e536d915698f58d5c5c6b7a
。这些ID在每一个共享此库的Git相同。 (我在这里列出的是在Git仓库为自己的Git提交。)
每个提交保留,只要提交本身的存在,所有文件的完整快照。那么,它拥有所有那些在快照中的文件,但是这等于是说,所有的蓝色蜡笔蓝:它是一种愚蠢的。问题的关键是,它的文件的快照。这并不是说“改变README
这样”,这需要回去和寻找README
之前的样子。它只是说我们有README
,它看起来是这样的。如果快照没有一个文件,Git的或许应该删除该文件(尽管这部分变得有点棘手,因为Git的可以让你有“未跟踪文件”)。在任何情况下,在快照中的文件永远冻结,或至少,只要提交存在。
但是,每个快照也有一些元数据,如您的姓名(如果您所做的承诺),当你成功了,你为什么做它,你的日志信息和关键的是我们的目的,前面的哈希ID提交。元数据,如文件,永远冻结,或者只要提交存在。需要注意的是,当你让Git告诉你一个承诺,Git的节目(部分)的元数据,然后说明你这次提交的文件之间的差异,这次提交的父的文件。它可以这样做,因为,父母的,或以前,提交的哈希ID,保存为这部分承诺。
这意味着对我们来说,我们可以绘制出的向后指向提交的字符串,每次提交命名其父:
A <-B <-C
如果散列的ID是简单的大写字母这样,我们可以只扫描所有这些,找到最后一个,但他们没有:他们似乎随机的(虽然实际上他们严格保存内部提交的所有位,确定哪个所以,我们不能改变任何内提交位的!)。所以Git的需要一种方法来保存最后提交,从它可以向后工作的哈希ID。
在分支哈希ID最后一次提交的是分支名称的功能,如master
:
A--B--C--D--E <-- master
我们-并在年底的Git开始,通过使用名称master
获得哈希ID(这里E
)。然后,我们向后工作,下面那些不变-能的内箭头。
该分支名箭头-的下存储的哈希ID的名称,可以改变的,因为我们拭目以待。
要添加新的提交到当前分支,我们的Git保存文件的快照,加入我们的姓名和电子邮件,我们的日志信息,并保存当前的哈希ID提交。 Git的写了这一切到新的承诺,其由此获得了新的哈希ID:
A--B--C--D--E <-- master
\
F
现在的Git刚刚更新的名字记录新的最新承诺:
A--B--C--D--E
\
F <-- master
然后我们可以理顺:
A--B--C--D--E--F <-- master
需要注意的是它的提交,以及它们之间的关系等,内部,向后指向的箭头,这是至关重要的位置。名字做的事,但只是因为这就是我们如何发现的提交。在提交自己形成向非循环图DAG或。名字让我们进入DAG。在DAG本身什么都不能更改,但名称可以移动的,我们可以添加新的提交。
(我们仍可以随意绘制DAG我们想要的,弯曲的连接箭头,只要他们还在联系。我用线条,而不是在这里,因为它很难找到好的文本字符做斜箭头的箭文本。)
假设我们现在有我们六个提交:
A--B--C--D--E--F <-- master
并希望使一个新的分支。我们用两种git branch
或git checkout
使分支,所以现在我们有:
A--B--C--D--E--F <-- BranchA, master
这两个名字都指向同一个commit,F
。所有六个提交现在对两个分支。
如果我们添加了一个新的提交,显然我们会得到:
A--B--C--D--E--F
\
G
我们F
早些时候得到了同样的方式。但名字要改变?要回答这个问题,Git的高度名字HEAD
的分支之一:
A--B--C--D--E--F <-- BranchA (HEAD), master
这告诉Git的这名以更改:
A--B--C--D--E--F <-- master
\
G <-- BranchA (HEAD)
当名移动HEAD
附件仍然存在。我们需要了解的附件时,我们想知道:哪个分支,我们呢?哪个分支会,如果它影响到当前分支我们的命令影响?如果我们只是在寻找什么是在存储库中,我们可以把它关闭。
您有一系列在你上面调用A3
,之后事情变得有点多毛的一个结束的提交。我喜欢一个字母的名字,但我会在这里用你的:
...--A3
现在,你说你master
达到B2
这是由通过B1
之前A3
之前,所以必须有经过两次提交:
...--A3--B1--B2 <-- master
同时您Branch_B
在B2
,这是由C3
之前开始了,但是这是根本不可能:
...--A3--B1--B2 <-- master
\
C3--B2 <-- Branch_B
所以你必须已在抄写你提交的哈希一些错误(并不奇怪,因为他们是大和丑陋,基本需要小心剪切和粘贴,以避免错误)。我会认为在掌握B2
真的是一些其他的ID,并与B2a
这里替换它:
...--A3--B1--B2a <-- master
\
C3--B2 <-- Branch_B
您Branch_C
启动井,结束 - 附C2
,这是由C1
前面,然后B1
,然后A3
?
C1--C2 <-- Branch_C
/
...--A3--B1--B2a <-- master
\
C3--B2 <-- Branch_B
您可以通过使用git log --decorate --oneline --graph --decorate master Branch_B Branch_C
(或git log --all --decorate --oneline --graph
,Get Help From A Dog)证实了这一点。绘制垂直方向的图表,这是不一样漂亮或明显对我,但还是非常有用的。
现在,这里是你说的,你想:
C1--C2--C3 <-- Branch_C
/
...--A3 <-- master
\
B1--B2 <-- Branch_B
你不能这样。我们已经说过,没有电源在任何地方任何现有的承诺,并期待在我们现在有,提交B2
的父提交C3
,例如改变任何东西。
但是你可以得到的东西,可能是一样好,那就是:你可以B2
的副本。事实上,你可能已经-B2a
和B2
是彼此的可能拷贝。
无需担心的确切复制机制呢,让我们来看看,如果我们做一个B2b
这是B2
的副本,但是有B1
作为其父发生了什么:
C1--C2 <-- Branch_C
/
...--A3--B1--B2a <-- master
| \
| C3--B2 <-- Branch_B
\
B2b <-- new-branch-b
接下来,让我们C1
复制到新C1a
从A3
弹簧:
C1a <-- new-branch-C
/
/ C1--C2 <-- Branch_C
/ /
...--A3--B1--B2a <-- master
| \
| C3--B2 <-- Branch_B
\
B2b <-- new-branch-b
然后,我们只需要通过一个复制C2
和C3
,之一:
C1a--C2a--C3a <-- new-branch-C
/
/ C1--C2 <-- Branch_C
/ /
...--A3--B1--B2a <-- master
| \
| C3--B2 <-- Branch_B
\
B2b <-- new-branch-b
几乎最后,我们需要移动的旧名称,Branch_B
和Branch_C
,使点分别提交B2b
和C3a
:
C1a--C2a--C3a <-- new-branch-C, Branch_C
/
/ C1--C2 [abandoned]
/ /
...--A3--B1--B2a <-- master
| \
| C3--B2 [abandoned]
\
B2b <-- new-branch-b, Branch_B
然后,我们需要移动的名称master
后退了两步,使其指向A3
而不是B2a
,放弃B2a
完全。这是很难得出直到我们停止绘制废弃的提交。他们仍然会在你的仓库了一段时间(至少30天默认情况下),但隐藏起来,使你不能看到他们的任何更多,这给了我们:
C1a--C2a--C3a <-- new-branch-C, Branch_C
/
/__________
/ \
...--A3--B1 -- master
|
|
\
B2b <-- new-branch-b, Branch_B
现在,我们可以删除new-branch-[bc]
名称和清理绘图的安排:
C1a--C2a--C3a <-- Branch_C
/
...--A3 <-- master
\
B1--B2b <-- Branch_B
除了这里的后缀,这意味着它们是不同的散列的ID,这就是你想要的!
首先,你只需要添加新的名字,指着所需提交:
git branch new-branch-b <hash of B1>
git branch new-branch-c <hash of A3>
我们在这里选择的哈希ID是将继续对新建分支的提交。对于Branch_B
,这是B1
,我们可以留在原地,但Branch_C
,这是犯A3
,因为我们必须复制到C1
C1a
。
现在,它的时间来复制的提交。让我们复制B2
或B2a
。你可以使用任何一个你喜欢的,只要他们做出同样的变化并且具有相同的提交信息,因为复制命令是git cherry-pick
和它的工作方式非常类似于我们前面关于显示承诺说:
[混帐]将会显示该之间的差别提交的文件,这次提交的父的文件
而不是显示的差异,git cherry-pick
发现差异,那么应用于的任何承诺,我们已经签出,使得同样的变化,并提交结果,使用相同的日志信息与原始提交过。
所以,我们只需要:
git checkout new-branch-b
git cherry-pick <hash-of-B2a or whatever>
这会让我们这么远,当我们绘制图形,并留下了很多:
...--A3
\
B1--B2b <-- new-branch-b
然后,我们需要建立C进行同样方式的新的分支:
git checkout new-branch-b
git cherry-pick <hash-of-C1>
git cherry-pick <hash-of-C2>
git cherry-pick <hash-of-C3>
结果,再留出大量图形的绘制,是期望:
C1a--C2a--C3a <-- Branch_C
/
...--A3
最后一步是让master
确定提交A3
,为此,我们只需要git checkout master
然后git reset --hard
:
git checkout master
git reset --hard <hash-of-A3>
(注:如果您使用的哈希的ID这样做,这是一个好主意,剪切和粘贴他们,和/或将它们保存在文件中,因为它太容易在这里得到错别字有技巧,使用相对的名字,但我。 “M不会将其包含在这个答案。)
该git reset
命令会影响哪个分支名HEAD
连接到,和git cherry-pick
命令使上取其分支名HEAD
连接到新的提交。这就是为什么我们必须git checkout
每个那些名字。
在这一点上,我们有新的分支名称,并master
点A3
,但我们还没有更新了其他两个分支的名字。和以前一样,我们可以在这里使用git checkout
和git reset --hard
:
git checkout BranchB
git reset --hard new-branch-b
git checkout BranchC
git reset --hard new-branch-c
我们不需要哈希ID的这段时间,因为像git cherry-pick
和git reset
命令,一个分支的名字的意思是提交其ID存储在该分支的名称。
一旦我们完成了这一切,我们可以删除new-branch-b
和new-branch-c
的名字:
git branch -D new-branch-b
git branch -D new-branch-c
该-D
是强制删除,这使得Git来完成它,即使Git的认为它是不安全的。 (这个时候Git的想法是安全的,当这不是嘛,和一个很好的尝试,但不是很大。)
这是不是特别容易为你的情况,但要知道对于未来是很重要的。每git cherry-pick
实际上是一种合并。 Git是要通过比较父提交到提交,就像git show
“合并”的承诺本身算所做的更改比较两到当前提交,找到您最近提交的变化,通过比较父提交樱桃-picked提交到电流(HEAD
)提交。
如果你是一个有点糊涂这里,不用担心:在前款肯定是难以阅读。它是由插图真的最佳所示:
o--o--...--P--C--o--...--o <-- other-branch
/
...--o
\
o--o--H <-- your-branch (HEAD)
您运行git cherry-pick <hash of C>
。 Git的方法:
P
VS C
:这是他们改变了什么。P
VS H
:这是你改变了什么,有点儿P
文件(即重复“你改变了什么”刚要回什么是在H
,但后来加入“他们改变了什么”从H
去的结果) 。C'
。否则,停止并留下一个烂摊子。当这种不费力的工作在你的一部分,其效果是,无论从改变到P
C
,这些相同的变化现在在新的提交C'
是git cherry-pick
作出的提交C
的副本:
o--o--...--P--C--o--...--o <-- other-branch
/
...--o
\
o--o--H--C' <-- your-branch (HEAD)
当它出现问题,Git会停止与合并冲突,它将停止在git merge
出问题的时候一样。在这一点上它是你的工作,完成了“合并”诚摘樱桃,在这种情况下,然后运行git commit
或git cherry-pick --continue
来完成这项工作。您可以使用所有相同的工具,你会git merge
期间,完成作业,所以不管你喜欢git merge
,用同样的方法。