为什么与两个提交者共享的git分支有两次提交多次?(可能与git-svn交互)

Sar*_*rge 0 git git-svn git-rebase

当我设置我的分支时,我做了:

git svn rebase
git checkout -b branch-a
Run Code Online (Sandbox Code Playgroud)

然后我把那个分支到远程的Git仓库和一个同事和我没有使用它的工作git commit,git pullgit push.

现在,我想从subversion中获取所有新的更改,所以我做了:

git checkout master
git svn rebase
git checkout branch-a
git rebase master
Run Code Online (Sandbox Code Playgroud)

此时我很困惑.似乎发生的事情是git会在一次或多次冲突中提交并迫使我解决它们.然而,冲突似乎是git让HEAD指向树的尖端(使用最新的代码),然后尝试逐个应用每个更改,就好像它将它们应用于原始分支点一样.

感觉就像我重新编写所有代码一样,大部分解决方案都是保留HEAD块并摆脱提交块.

我的期望是git rebase master命令将在分支之前的提交处开始,从master添加每个提交,然后在分支上添加每个提交.然后,这将在分支上产生与尖端之前几乎相同的尖端.

那么,任何人都可以解释我无法理解的内容.如果做不到这一点,任何人都可以建议如何找出为什么git决定这样做.我会在寻找什么git log,看看它为什么这样做.

编辑:2012-03-06 进一步的研究表明,我们似乎在我们的分支和分支结构中有多个提交的多个副本,git log --graph当我们认为只有一个时,从中显示多个分支.

一个片段(鉴定去除细节和提交信息已被替换为MESSAGE- Ñ MESSAGE-.Ñ是指相同的消息):

| * | commit f5c48df66ed9d733364562d8f125866aa6483c1e
| | | Author: commiter-b
| | | Date:   Mon Feb 27 16:18:05 2012 -0800
| | | 
| | |     Message-4
| | |    
| * | commit e6115229e629c237b08d0b2e149353f33ff66bd1
| | | Author: commiter-a
| | | Date:   Mon Feb 27 15:49:02 2012 -0800
| | | 
| | |     Message-3
| | |    
| * | commit f85981736c59231dc34a7cef4fceab5cffdbdff2
| |/  Author: committer-a
| |   Date:   Mon Feb 27 14:20:56 2012 -0800
| |   
| |       Message-2
| |   
| * commit b09ba82e6290f5905d4c98fdcfbe2220d221e762
|   Author: committer-a
|   Date:   Mon Feb 27 14:04:13 2012 -0800
|   
|       Message-1
|  
* commit 4d2892c239acfab5c9845518fde98ba551f273e6
| Author: committer-a
| Date:   Mon Mar 5 09:13:19 2012 -0800
| 
|     UN-3710 Fixes after merge from svn

---8<----- snip

* commit 8307d1ae8214ebe3eac5bdc5b835c21f89d727bd
| Author: committer-b
| Date:   Mon Feb 27 16:18:05 2012 -0800
| 
|     Message-4
|  
* commit 859acc56de59877cb721914443c63ad97882cb41
| Author: committer-a
| Date:   Mon Feb 27 15:49:02 2012 -0800
| 
|     Message-3
|  
* commit 93e15921d735333194970cefc673a8b953e80838
| Author: committer-a
| Date:   Mon Feb 27 14:20:56 2012 -0800
| 
|     Message-2
|  
* commit 7a863bb44be5c5019a0e0958460324dc3cfb2e6b
  Author: committer-a
  Date:   Mon Feb 27 14:04:13 2012 -0800

      Message-1
Run Code Online (Sandbox Code Playgroud)

我相信,我们的git工作流程是保守的.我们git-svn用来维护master哪个被推送到远程git存储库.我们分支master,两个或多个提交者使用git pull origin branch-a和处理它git push origin.

现在我们已经注意到了这个问题的这个特征,我们将来会仔细观察它会导致什么事件.

Bor*_*lid 5

首先,快速总结一下git rebase.

如果您的历史记录如下所示:

trunk  branch
  |   /
  B  C
  | /
  |/
  A
  |
  |
Run Code Online (Sandbox Code Playgroud)

git rebase trunk当你开始时branch,这就是你得到的:

trunk/branch
   |
   C
   |
   B
   |
   A
   |
   |
Run Code Online (Sandbox Code Playgroud)

这就是为什么它被称为rebase-以前的基础branch是提交A-这是在它从它的"上游"分支发散的点,trunk.操作后,新的基础是B,更新HEADtrunk.你重新建立了它.

git svn rebase 只是自动执行此操作,将您所做的更改移植到来自SVN的新提交中.

现在,有一个问题.git-svn,对于歇斯底里的葡萄干,不使用git笔记来存储其元数据.相反,它会重写提交对象本身,git-svn-id在每个提交消息的末尾添加行.这会导致每个提交的SHA1标识符发生更改.因此,即使是相同的提交也是不同的 - 并且可能与他们自己的替代宇宙版本冲突!

这可能是当你尝试,你看到的git rebase master来自branch-a:branch-a从一些非承诺到SVN版本的先前状态的分歧master,所以现在当你试图合并,你会得到改变双方的事情之间的冲突两侧.

这是一个限制git-svn:一旦你将更改推送到SVN,你必须小心只使用推送到SVN重写的提交版本.您不能混合预先提交的表单和提交后的表单,因为它们具有相同内容的"不同"更改.

您可以通过检查来自和的更改git merge-base master branch-a来验证这是您尝试执行的操作.您可能会在双方看到相同的变化.masterbranch-a

要在这种特殊情况下让自己摆脱困境,删除你的分支,创建一个新的分支master,然后git cherry-pickbranch-a顺序中更改,省略master已经包含的分支.在未来,使用尚未进入SVN的版本会更加谨慎......