Git pull会覆盖同一分支(主分支)上的内容,而不是合并或确认冲突。

9

背景:

我认为这是一个简单的场景。我已经在本地提交了更改,现在我想将远程分支(领先于我)上的内容合并到本地的工作目录中。

git branch -vv --list --all 的输出如下:

  master                79d9d4e [origin/master: behind 7] Footprint UI working
  remotes/origin/HEAD   -> origin/master
  remotes/origin/master a86a1a9 Added sample data to webpage

我希望合并其中的一个文件。以下是差异:

git diff --stat a86a1a9 79d9d4e views/footprint.handlebars
views/footprint.handlebars | 65 +++++++++++++++++++++++++++++++++--------------------------------
 1 file changed, 33 insertions(+), 32 deletions(-)

但是当我运行 git pull 命令时,本地提交的文件版本被远程覆盖了。更详细地说:
$ git fetch -v origin  

From github.com:githubusername/foo
 = [up to date]      master     -> origin/master

$ git merge origin  
Updating 79d9d4e..a86a1a9
Fast-forward
...
 views/footprint.handlebars    | 65 ++++++++++++++++++++++++++++++++---------------------------------
...
 6 files changed, 220 insertions(+), 59 deletions(-)
 create mode 100644 static/search.js
 create mode 100644 views/search.handlebars

我已阅读以下帖子:
  1. git merge overwrites contents
  2. Git merge master into development branch is overwriting, not merging
我尝试了以下命令:
  1. git pull --rebase 会覆盖文件的本地版本
  2. git merge -s recursive -X ours 会覆盖本地文件的版本
  3. git merge -s ours 提示输入提交信息,然后覆盖远程更改
  4. git rebase remotes/origin/master 表示将在“head”上“重放我的工作”,但仍会覆盖它
  5. git merge --no-ff --no-commit当覆盖文件时,字面上报告“自动合并进行得很好;根据要求停止提交”
(在运行上述每个命令后,我检查了相关文件,并注意到它被覆盖,然后运行了 git reset --hard master@{"5 minutes ago"}
$ git config --list  

redential.helper=osxkeychain
user.name=My Name
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
core.precomposeunicode=true
remote.origin.url=git@github.com:githubusername/foo.git
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
branch.master.remote=origin
branch.master.merge=refs/heads/master
user.email=email@address.com
remote.heroku.url=https://git.heroku.com/foo.git
remote.heroku.fetch=+refs/heads/*:refs/remotes/heroku/*

$ git log --oneline --decorate --simplify-by-decoration --all -10  

a86a1a9 (origin/master, origin/HEAD) Added sample data to webpage
79d9d4e (HEAD -> master) Footprint UI working
c53160d Initial commit

$git log --format="%h %ci %cn" views/footprint.handlebars

79d9d4e 2019-03-12 19:04:08 -0400 chb
fada3fa 2019-03-10 13:59:41 -0700 JA
9641499 2019-03-08 16:48:14 -0800 JA
1759509 2019-03-08 12:32:08 -0800 GitHub
bfe443e 2019-03-07 16:41:18 -0800 JA

git version 2.17.2 (Apple Git-113)

问题:

为什么git没有将此冲突标记为冲突并在相关文件中添加适当的标记(<<<<<<< HEAD, =======, >>>>>>>)?


1
你可以发布git config --list的输出吗?就像你所链接的第二个问题的答案所指出的那样,这可能会受到你的 git 配置的影响(请注意,仅查看 .git 是不够的,那不是 git 使用的唯一位置)。 - Michail
1
git merge origin/whatever。其实应该说“手动合并调用”,或者干脆不提。我通常做什么在这里有点不相关。 - Michail
1
“快进” - 很确定你的更改已经在远程master上了(如果文件内容有误,则可能已被其他提交覆盖),或者不在本地master上(不幸的是 git reset,或者可能是你不小心在其他分支上工作,或者类似的情况)。抱歉,我无法继续了,这里已经是凌晨3点了。祝你好运! - Michail
2
根据您的 git merge 输出,您的同事在合并时犯了一个错误。 - Ferrybig
1
运行以下命令并在此处发布您的输出:git log --graph --full-history --all --date=format:'%Y-%m-%d %H:%M:%S, %a' --format='%h %d%n%x09%x09 %C(blue bold)%an%Creset, %C(magenta)%ad (%ar)%Creset:%n%x09%x09 %Cgreen"%s"' $(git reflog show --format=%h stash 2>/dev/null || :) 我的理论与 @RomainValeri 相同。我假设 git 只是进行了快进,因为历史记录中有一些合并会显示为什么会发生这种情况。 - Julian
显示剩余11条评论
1个回答

9

我怀疑关于合并的一些误解。(注意强调,稍等片刻)

如果有的话,我们需要澄清一下。

我们最好关注文件 views/footprint.handlebars。在初始提交和您的本地提交之间是否更改了它?在初始提交和 origin/master 之间是否更改了它?还是都有更改?

如果您没有更改它,那么合并后您的文件反映其更改是预期的。

如果他们没有更改它,但是在合并后您的更改版本被来自初始提交的“旧”版本覆盖,这就是一个需要调查的奇怪行为。

如果您和他们都对文件进行了更改,但在不冲突的不同点上进行了更改,则最终结果应包含双方的更改,而没有冲突。我不会称其为“被覆盖”。


最后,如果您确实想要保留此文件与您最近的本地提交完全相同的状态,您必须(像您所暗示的那样)使合并产生冲突,但这并不是什么大不了的事:

git checkout master
git fetch
git merge --no-commit origin/master
git checkout HEAD -- views/footprint.handlebars
git commit -am "Kept file views/footprint.handlebars as per commit 79d9d4e"

请给我们更多反馈,我会进行编辑以进行调整。(可能要等到明天才能完成;-))

评论后的添加:

我基本上同意Useless在下面的评论。我没有从你最初的问题中得知你和你的同事提交的“同一文件”之间存在来回交流(如你在这里所补充的)。

现在恢复你所需的更改和他们的解决方案可能是检查文件历史记录,然后仔细从初始共享状态重新构建内容,但根据你的上下文很难建议最佳公式。如果同事能够与你一起解决,你很可能会避免很多麻烦。

结语添加:

对于这个有些苦涩的结局,我表示抱歉,我完全理解你希望得到更具智力满足感的答案/解决方案。感谢你的慷慨奖励,也感谢所有人的建设性评论。


1
如果你的同事在你重写后将代码推送到服务器,问题可能出在他们如何解决合并冲突上。也就是说,从 Git 的角度来看,他们故意让 Git 采用了他们的版本。 - Useless
@Useless 但是,如果我们拿两个文件进行比较,这两个文件只有一个段落不同,然后在git之外使用简单的diff fileA.txt fileB.txt命令进行比较,那么会得到一个文件(或一组差异),指示出冲突。那么,在git的上下文中执行此操作时,为什么这个简单的过程会失败并需要进行一个额外的对话呢?另外,如果我需要了解公共祖先(如果存在的话)的信息,该如何获得?git log --graph只会呈现哈希列表,因为所有操作都在同一个分支上完成。 - chb
为了以后的参考,我建议你鼓励你的同事在自己的特性分支上工作,这样你就可以控制合并。他们听起来像是一个绝对的责任。无论如何,没有版本控制系统能够按照你所建议的方式工作 - 你怎么知道哪些差异中的更改应该应用于结果?你需要能够区分你添加一行和其他人删除一行的情况。平坦的差异在这两种情况下都是相同的。 - Useless
@Useless 我并不要求版本控制系统能够读心术,只是希望它能够“标记”冲突。这就是让我感到困惑的地方:为什么在git之外,冲突是显而易见的,但是使用git时却没有得到确认?关于你对工作流程的评论:是的,我认为从这种情况中可以得出的结论是每个开发人员都应该在自己的分支上工作(这是我们两个人都没有做的事情)。 - chb
4
你一直声称存在冲突,但并不明确是否真的存在。我强烈建议你阅读Git如何解决合并的方式,因为它完全不像你所描述的期望结果。在同一文件中进行更改并不意味着自动出现冲突。你需要知道每个路径自上次共同祖先以来所发生的更改,而你目前展示的线性历史记录无法告诉你这一点。 - Useless
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接