我怎么能告诉Git提交中发生了什么事情,两个父母没有合并来自第二个父母的更改?

DAC*_*DAC 7 git git-pull git-merge git-log git-commit

在Gitk中,我可以看到团队成员的提交(X)有两个父母,第一个父母是他自己的先前提交(A),另一个父母包含许多其他人提交(1到5).合并后,其他人(1到5和其他人)所做的所有更改都不再出现在X,B,C等...

A------------
              \
               X - B - C 
              /
1--2--3--4--5
           /
e--r--j--k
     /
l--m
Run Code Online (Sandbox Code Playgroud)

如果我提交X提交A它没有显示差异,如果我将X提交X提交5它显示所有缺少的更改.此外,在提交X,B或C时,git日志不会显示对提交1到5中的文件所做的更改.但是,如果我执行git log --full-history,则历史记录会显示在1中进行的更改到5,但这些更改仍未出现在实际文件中,并且历史记录未显示它们正在撤消.所以git log --full-history似乎与当前文件内容相矛盾.

我与提交X的用户进行了交谈.他说他没有进行重置或拒绝,他说他在相关时间内没有恢复任何提交.然而,他说他确实有时会做一个拉原点大师,导致其他人的变化被放入他的索引或工作树中,好像他已经做出了这些改变而不是这些改变的实际作者.他说,当这种情况发生时,他会做一个新的克隆,并且不会将任何东西从当地的回购推送给主人,因为他认为Git做错了什么.

这两件事是否相关(坏拉和坏合并)?

我怎样才能确切地说出发生了什么,以便我们将来可以避免这种情况?

是什么原因导致Git有时会将从原始主数据中提取的更改放在本地工作目录或索引中,就像它们是本地更改一样?

Die*_*Epp 7

然而,他说他确实有时会做一个拉原点大师,导致其他人的变化被放入他的索引或工作树中,好像他已经做出了这些改变而不是这些改变的实际作者.

这听起来像他正在进行合并冲突但却不明白它们是什么.这是一个非常常见的问题,遗憾的是,我们不知道避免它的好方法(例如,切换回SVN并不能避免它).

怎么会发生这种情况呢?

我们打电话给你的开发人员Alice和Bob.爱丽丝提交了1-5,而鲍勃提交了A和X.这是一个似是而非的历史.

  1. 鲍勃做出承诺A.

  2. Alice提交1-5,并将它们推送到中央存储库.

  3. 鲍勃试图推动A,但不能,因为他的存储库已经过时了.

    $ git push
     ! [rejected]        master -> master (non-fast-forward)
    
    Run Code Online (Sandbox Code Playgroud)
  4. 鲍勃然后他做了你告诉他做的事:他先拉.但是,他得到合并冲突,因为提交A并提交1-5触摸一些相同的代码.

    $ git pull
    Auto-merging file.txt
    CONFLICT (content): Merge conflict in file.txt
    Automatic merge failed; fix conflicts and then commit the result.
    
    Run Code Online (Sandbox Code Playgroud)
  5. Bob在工作目录中看到了其他人的变化,并且不明白为什么会有变化.

    $ git status
        both modified:   file.txt
    
    Run Code Online (Sandbox Code Playgroud)
  6. 他认为Git做错了,事实上,Git要求他解决合并冲突.他试图查看一份新的副本,但收到错误:

    $ git checkout HEAD file.txt  
    error: path 'file.txt' is unmerged
    
    Run Code Online (Sandbox Code Playgroud)
  7. 由于它不起作用,他试图-f:

    $ git checkout -f HEAD file.txt
    warning: path 'file.txt' is unmerged
    
    Run Code Online (Sandbox Code Playgroud)
  8. 成功!他承诺并推动.

    $ git commit
    $ git push
    
    Run Code Online (Sandbox Code Playgroud)

变得更难的部分

那里有很多git工具.认真.Visual Studio和Xcode都带有Git集成,还有其他几个GUI,甚至还有多个命令行客户端.人们对他们如何使用Git的描述方式也很草率,大多数开发人员对Git如何在"拉动提交"工作流程之外的工作方式感到不太满意.

不久前有一篇关于这个主题的优秀论文(我很难找到它).一些结论是(原谅我的记忆):

  • 大多数开发人员并不真正知道如何使用源代码控制,除了一些非常简单的命令(commit,push).

  • 当源代码控制的行为不像开发人员期望的那样时,他们会采取一些策略,例如复制粘贴一些他们不太理解的命令来"修复问题",添加-f标记,或者删除存储库并重新开始使用干净的副本.

  • 在开发团队中,通常情况是只有主要开发人员真正知道回购中发生了什么.

所以这真是一个教育挑战.

我认为这里的关键教训鲍勃需要学习的是,git pull其实只是git fetchgit merge,那你可以得到合并冲突,并且需要解决合并时非常认真,有目的的方式行事.这甚至在没有报告冲突的情况下也适用......但是现在让我们不要过多地吹嘘鲍勃的想法!

这里的另一个重要教训是,主要开发人员需要花时间确保团队中的每个人都能正确使用源代码控制,并了解拉动,推送,分支和合并是如何相关的.这是午餐时间讲座的好机会:放一些幻灯片,买披萨,谈谈Git的工作方式.

  • 你好,我是鲍勃。 (5认同)
  • 我以为 Bob 知道如何解决合并冲突,但是,既然您怀疑这一点,我将调查 Bob 在发生冲突时实际执行的操作。做完之后再评论。 (2认同)
  • 我已经意识到这通常会发生.当pull origin master因冲突而失败时,git status将显示来自另一个分支的所有更改,如同提交阶段一样.鲍勃认为,那些不是我的变化,恐慌并且开始取消暂停.但实际上,Bob必须在解决冲突后提交所有其他人的更改,否则,git将永远不会合并其中.解决方案是告诉Bob,当你有冲突,解决冲突和提交.不要担心你上演的其他人的变化,这是正常的. (2认同)