在这个例子中,git认为它不需要重新绑定,但显然确实如此。
这是一个创建迷你测试git存储库的快速脚本
#!/bin/bash
rm -rf testgit
mkdir testgit
cd testgit
git init
echo -e "a\nb\nc" > file
git add file
git commit -am 'first'
git checkout -b lineA
echo -e "A\nb\nc" > file
git commit -am 'A'
git checkout -b lineB
echo -e "a\nB\nc" > file
git commit -am 'B'
git checkout -b lineC
echo -e "a\nb\nC" > file
git commit -am 'C'
运行之后,这是file
在每个分支中的样子
master | lineA | lineB | lineC
------------------------------
a A a a
b b B b
c c c C
现在让我们将所有分支合并为master,之后file
中的每个字母都应该大写
$ git checkout master
$ git merge lineA
好。
$ git checkout lineB
$ git rebase master
Current branch lineB is up to date.
什么?不,大师改变了。
$ git checkout master
$ cat file
A
b
c
$ git checkout lineB
$ cat file
a
B
c
在我看来,分支行B需要通过合并lineA来修改主变量。
为什么git认为不需要这样做?
此外,如果你这样做
$ git checkout master
$ git merge lineA
Already up-to-date.
$ git merge lineB
...
1 file changed, 2 insertions(+), 2 deletions(-)
$ cat file
a
B
c
$ git merge lineC
...
1 file changed, 2 insertions(+), 2 deletions(-)
$ cat file
a
b
C
这里的合并应该冲突,但是git正在悄悄地破坏它们。我不知道这是否相关,但看起来很奇怪。
答案 0 :(得分:2)
第一个命令的结果
在我们拥有的脚本之后(缩写行分支名称......):
The application environment is not set correctly.
这些命令:
master lA lB lC
↓ ↓ ↓ ↓
first----A----B----C
会导致快进合并,只会将$ git checkout master
$ git merge lineA
移至指向与master
相同的提交。
,并提供:
lineA
无法使用Rebase
所以这个命令序列:
master
lA lB lC
↓ ↓ ↓
first----A----B----C
表示将$ git checkout lineB
$ git rebase master
分支移到lineB
之上。
...但它已经位于master
之上。
master
必须在其历史记录中进行一些提交master
没有让rebase命令有任何工作要做。
无合并冲突
当Git创建合并提交时,它会考虑进入合并的父项的历史记录。在这种情况下,两个分支都指向共同提交链上的提交。 Git可以看到lineB
提交来自A
提交之前的B
提交。因此,Git认为后来的提交是在早期提交之上添加的,因此它们不会发生冲突。
如果您有以下历史记录:
C
然后Git会将它们视为平行的开发线。在这种情况下,将 master
↓
---A
/
| lB
| ↓
first----B
合并到lB
或反之亦然会发生冲突。这是因为master
不是历史记录中B
之上的附加内容,因此Git需要用户输入才能了解要保留哪些更改。
答案 1 :(得分:1)
我认为你的困惑又回来了。执行时
git commit -am 'first'
git checkout -b lineA
你确实创建了一个名为lineA
的新分支,但分支点就是你刚刚做过的提交(" first
")。正如Git所说,first
是两个分支历史的一部分,在你的脚本中,它也是两个分支中最近的提交。带有一些选项的Git日志显示两个分支名称都指向第一个提交,在此示例中为commit id 58b7dcf:
git log --graph --oneline --decorate
* 58b7dcf (HEAD, master, lineA) first
继续:
echo -e "A\nb\nc" > file
git commit -am 'A'
git log --graph --oneline --decorate
* ed40ed2 (HEAD, lineA) A
* 58b7dcf (master) first
log命令显示提交A
(ed40ed2)现在是lineA
上的最新提交,其父提交是first
,它仍然是master
上的最新提交。 {1}}。如果您此时将lineA
合并回master
,那么这将是一个快速(简单)合并,因为master
已经lineA
未提交任何提交离开它。同样,将lineA
重新定位到master
除了报告
Current branch lineA is up to date.
因为分支master
上的最新提交(主分支的提示)仍然是分支lineA
的历史记录的一部分。继续:
git checkout -b lineB
echo -e "a\nB\nc" > file
git commit -am 'B'
git checkout -b lineC
echo -e "a\nb\nC" > file
git commit -am 'C'
git log --graph --oneline --decorate
* 4033067 (HEAD, lineC) C
* f742aed (lineB) B
* ed40ed2 (lineA) A
* 58b7dcf (master) first
每个新分支都是基于前一个分支的最新提交,没有并行开发。继续:
git checkout master
git merge lineA
Updating 58b7dcf..ed40ed2
Fast-forward
请注意,这是一个快进合并,所以它只是将master
移动到ed40ed2:
git log --graph --oneline --decorate
* ed40ed2 (HEAD, master, lineA) A
* 58b7dcf first
最后:
git checkout lineB
git rebase master
Current branch lineB is up to date.
git log --graph --oneline --decorate
* f742aed (HEAD, lineB) B
* ed40ed2 (master, lineA) A
* 58b7dcf first
您写道:
什么?不,大师改变了。
是的,master
已更改,但不会影响lineB
或lineC
的历史记录。 master
快速提交ed40ed2,它已经是lineB
的父级。确切地说,它是f742aed的父级,这是我为提交B
而获得的提交ID。
对于习惯于其他版本控制系统的人来说,混淆是Git为提交记录而不是分支名称记录树状数据结构(技术上是DAG)。分支是短暂的;它们只是标签,如可移动版本标签。提交之间的父子关系就是您在git log --graph
和其他可视化工具中看到的。