9

Background:

I've got what I perceive to be a simple scenario. I've committed changes locally and now I want to merge what's on the remote, in the same branch (ahead of me) into the local, working directory.

git branch -vv --list --all gives the following:

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

There's one file in particular that I'd like to merge. Here's the diff: git diff --stat a86a1a9 79d9d4e views/footprint.handlebars

views/footprint.handlebars | 65 +++++++++++++++++++++++++++++++++--------------------------------
 1 file changed, 33 insertions(+), 32 deletions(-)

But when I run git pull, the version of the file in my local commit is overwritten by that of the remote. In more verbose terms:

$ 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

I've read over the following posts:

  1. git merge overwrites contents
  2. Git merge master into development branch is overwriting, not merging

And have tried these commands:

  1. git pull --rebase overwrites the local version of the file
  2. git merge -s recursive -X ours overwrites local version of file
  3. git merge -s ours prompts for commit message and then overwrites remote changes
  4. git rebase remotes/origin/master says that it will "replay my work on top of" head, but still overwrites it
  5. git merge --no-ff --no-commit literally reports "Automatic merge went well; stopped before committing as requested" when it's overwritten the file

(After running each of the above, I checked the file in question and, noting that it was overwritten, ran 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)

Question:

Why is this conflict not being flagged as such by git, with the appropriate markers (<<<<<<< HEAD, =======, >>>>>>>) being added to the relevant file?

Community
  • 1
  • 1
chb
  • 1,727
  • 7
  • 25
  • 47
  • 1
    Can you post the output of `git config --list`? As the answer to the second question you've linked notes, this can be affected by your git configuration (note that just looking in `.git` is not enough, that's not the only place git uses). – Michail Mar 13 '19 at 23:08
  • @Michail thanks for the response; updated with requested info – chb Mar 13 '19 at 23:20
  • 1
    What exactly do you call *overwriting*? Could you maybe write a very small mockup change, show what you get after the overwriting and what better result you'd expect? – Romain Valeri Mar 13 '19 at 23:23
  • That's kinda odd, the output of `git branch ...` doesn't have an `ahead ...` bit. – Michail Mar 13 '19 at 23:24
  • wait, that's the output before `pull`, right? what does it show if you do `fetch` first? – Michail Mar 13 '19 at 23:26
  • @Michail could you elaborate on that last comment? what command(s) are you referring to when you say "manual merge"? – chb Mar 13 '19 at 23:30
  • 1
    `git merge origin/whatever`. should've said "a manual merge invokation", really, or not mentioned it at all. what _I_ do normally is a bit irrelevant here – Michail Mar 13 '19 at 23:31
  • the same `branch` command as yours gives me this: `* master 2f81205 [origin/master: ahead 1, behind 1] local change` if I have a commit that is not present in the remote. Are you sure the relevant commits are present on local `master`? – Michail Mar 13 '19 at 23:41
  • Maybe also show us (many demands here, but hey! it'll help the process I guess) the output of `git log --oneline --decorate --simplify-by-decoration --all -10` (in order, among other things, to have an idea of where your local commit actually is). – Romain Valeri Mar 13 '19 at 23:44
  • @Michail I've added `fetch`/`merge` output – chb Mar 13 '19 at 23:46
  • @RomainValeri no worries, I appreciate the help – chb Mar 13 '19 at 23:48
  • 1
    "fast forward" - pretty sure your changes are either already on remote `master` (and probably were subsequently overwritten in other commit if the file has wrong contents), or are not on local `master` (an unlucky `git reset`, or maybe you were working on other branch by accident, or something similar). Sorry, can't really continue with this, it's 3 A.M. over here. Good luck! – Michail Mar 14 '19 at 00:13
  • 2
    According to the output of your `git merge`, you coworker made a mistake merging things – Ferrybig Mar 16 '19 at 15:29
  • Note that you can, and should, look back through the history and _see_ what you coworker did, and decide for yourself if it was correct or not. Showing the log isn't that helpful, you want to examine the diff of each change applied to the file. – Useless Mar 18 '19 at 18:10
  • Have you checked the origin branch history? Is it possible that someone had merged your commits before merging your branch (i.e. branching your branch and then merging it to master before you)? If so, it explain the "fast-forward", and then someone can overwrite your changes – Fede Mar 20 '19 at 21:59
  • 1
    Run the following and post your output here: 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 || :) My theory is the same as the @RomainValeri. I am assuming git just did a fast-forward as there is some merge in the history that will show why that happened. – Julian Mar 22 '19 at 17:58

1 Answers1

9

I suspect a misunderstanding about what a merge is supposed to do. (mind the emphasis, and bear with me)

Let's clear it up, if any.

We'd better focus on the file views/footprint.handlebars. Was it changed between the initial commit and your local commit? Between the initial commit and origin/master? Both?

If you didn't change it, the fact that after the merge your file reflects their changes is expected.

If they didn't change it and your changed version is overwritten with an "older" version from initial commit after the merge, now that's an odd behaviour to investigate.

If both you and them have brought changes to the file, but at different, non-conflicting points, then the end result should contain changes from both sides, without conflict. I wouldn't call that "overwritten".


Lastly, if you in fact want to keep this file in the exact state it is in your recent local commit, you'd have to, like you hinted at like a very tedious thing, make the merge conflict, but that's not a big deal :

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"

Give us a bit more feedback and I'll edit to adjust. (probably tomorrow, though ;-)

Addition after comments :

I'm pretty much agreeing with Useless' comment down below. I didn't get from your original question that there was back-and-forth on the very file in-between you and your coworker's commits (as you added here).

The solution to restore both your needed changes and theirs might now be to check file history, then rebuild the contents carefully from the initial shared state, but depending on your context it's hard to advise on the best formula. If the coworker is available to sort it out with you, you're likely to avoid a lot of headaches.

Epilogue addition :

Sorry for the bitter sweet ending, I totally understand that you would have prefered a more intellectually satisfying answer/solution. I thank you for the bounty and everyone else for all the insightful comments.

Romain Valeri
  • 19,645
  • 3
  • 36
  • 61
  • Without a merge conflict, `--ours` won't have a stage-2 entry to copy - you'll need `git checkout HEAD -- views/footprint.handlebars`. – torek Mar 14 '19 at 00:54
  • Let me try to address your questions: the file was initially authored and pushed by a colleague. I then rewrote a good portion of it (the most recent commit listed in the file specific log output) and pushed. He continued to modify his version and pushed that to the server after my modifications. The points in the file that have been altered by both parties are in direct conflict--his changes completely eliminate mine. That is what I mean by "overwrite." – chb Mar 14 '19 at 01:00
  • @torek Thanks for the watchful eye, I've written this a bit too late yesterday, and rushed it I guess :-) Edited! – Romain Valeri Mar 14 '19 at 07:39
  • @chb Thanks for the feedback. I'll try to adress your answers later today! – Romain Valeri Mar 14 '19 at 07:39
  • 1
    If your colleague pushed to the server after your rewrite, the problem may lie in how _they_ resolved _that_ merge. That is, from git's perspective, they've deliberately told it to take their version. – Useless Mar 16 '19 at 00:56
  • @Useless If the file, as it exists in the remote repository, is in direct conflict with my local version, and I `pull`, why does the history of the file and the history of its state matter? Isn't the only question, "what in this file is different and can those differences be resolved via merge"? – chb Mar 16 '19 at 16:45
  • No. The question is what changed since the last common ancestor, and if your colleague performed a (bad) merge, that changes the last common ancestor. Look at the revision tree, not just a single linear history. – Useless Mar 16 '19 at 19:26
  • @Useless But if we were to take two files that differ by, say, a paragraph, and diff them outside of `git`, with a simple `diff fileA.txt fileB.txt`, that would result in a file (or a set of differences) that would indicate a conflict. How is it then, that when this is done within the context of `git`, that simple process breaks down and necessitates an out-of-band dialog? Also, if it's important that I understand what the common ancestor is (if one exists) how can I obtain this information? `git log --graph` simply presents a list of hashes because everything was done on the same branch. – chb Mar 18 '19 at 17:12
  • For future reference, I'd try encouraging your colleague to work on their own feature branch so you can control merging. They sound like an absolute liability. Anyway, no version control system can work the way you suggest - how would you know which changes from the diff should be applied to the result? You need to be able to distinguish between you adding a line and someone else removing one. The flat diff would be identical in both cases. – Useless Mar 18 '19 at 18:07
  • @Useless I'm not asking the VCS to be a mind reader, just to _flag_ the conflict. And that is what's so perplexing to me: why, outside of `git` is a conflict obvious, but using `git` the conflict goes unacknowledged? With regard to your comment regarding workflow: yes, I think the takeaway from this situation is that each developer should work on their own branch (something that neither of us did). – chb Mar 18 '19 at 18:42
  • 4
    You keep claiming there's a conflict, but it's not at all clear there should be one. I strongly recommend reading how git actually resolves merges, because it's nothing like the expectation you describe. Having changes in the same file doesn't automatically mean a conflict. You need to know what changed on each path since the last common ancestor, and you can't tell that from the linear histories you've shown so far. – Useless Mar 19 '19 at 10:07