Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LFS Merge Conflict Merges Pointers #7166

Open
TCROC opened this issue Mar 26, 2019 · 57 comments
Open

LFS Merge Conflict Merges Pointers #7166

TCROC opened this issue Mar 26, 2019 · 57 comments
Labels
bug Confirmed bugs or reports that are very likely to be bugs priority-2 Bug that affects more than a few users in a meaningful way but doesn't prevent core functions

Comments

@TCROC
Copy link

TCROC commented Mar 26, 2019

Description

When merging into a branch while using Git LFS, it attempts to merge the LFS pointers together. We then have to manually change the files by removing the pointer we don't want. I would have expected to be prompted with "Take Incoming File" or "Keep Current File" for our LFS files.

Version

  • GitHub Desktop: 1.6.5
  • Operating system: Microsoft Windows [Version 10.0.17763.379]

Steps to Reproduce

  1. Create a merge conflict between two LFS files in two different branches.
  2. Attempt to merge one branch into the other branch with the merge conflict, and you will see that the conflict was "automatically resolved" when all it did was merge the pointers together.

Expected Behavior

Be prompted with "Take Incoming File" or "Keep Current File" for LFS files.

Actual Behavior

The LFS pointers are merged together into one file and breaks the LFS pointer.

Additional Information

Logs

2019-03-26.desktop.production.log

@shiftkey shiftkey added the investigation-needed Likely bugs, but haven't been reliably reproduced by a reviewer label Mar 26, 2019
@shiftkey
Copy link
Member

@TCROC thanks for the feedback! I think it'd be great to put together a sample project of this so we can verify the behaviour ourselves and confirm the fix.

@TCROC
Copy link
Author

TCROC commented Mar 26, 2019

@shiftkey Hey thanks for getting back with me :) I created a test repo here. All you have to do is clone the repo in GitHub Desktop. Merge the branch 'master' into 'DevBranch2' and commit the merge. Then open 'LFSTrackedFile.asset' in a text editor (I tested it in Notepad, Notepad++, and VS Code). The results should look like this:

version https://git-lfs.github.com/spec/v1
<<<<<<< HEAD
oid sha256:6b11f7689252ef9a2ae45a0949db32457b0404ffd27fbe399685da21efe06c46
size 51
=======
oid sha256:88169783c65ba3ceeff49a02a88e37c08b10d82b05368fe16792ede6d68db380
size 62
>>>>>>> master

I realize all we have to do is pick the merge ourselves in a merge tool / text editor and is plenty easy for us developers to do, but this is not intuitive for our artists (we are a game dev team). We simply want to be able to do an "Accept Incoming Change" or "Accept Current Change" from GitHub Desktop like we currently have to do in VS Code.

Here are some example pics of what we see:

Before comitting merge:

No Conflicts Remaining Message

What we expect to see before committing merge. Pic was taken with a normal merge conflict (not LFS).

Expected Output For LFS File

The file after merging:

Automatically Merged File

The during merge screen would be nice if there were "Accept Incoming Change" or "Keep My Change" buttons. This would be much more intuitive for our artists. However, we don't even get the option as seen in the expected image. Currently our artists have to open a command prompt and enter git mergetool and take the merges by hand.

Again thanks for looking into this for us :)

@shiftkey
Copy link
Member

@TCROC thanks so much for putting together a repro for it. I'm going to try it out and see if I can propose a solution for this (we have detecting in place for binary files but nothing LFS-specific).

@shiftkey shiftkey self-assigned this Mar 26, 2019
@shiftkey shiftkey added the bug Confirmed bugs or reports that are very likely to be bugs label Mar 26, 2019
@shiftkey shiftkey removed their assignment Mar 27, 2019
@shiftkey
Copy link
Member

Other priorities have jumped up which I need to tackle first before I can investigate this.

Unassigning myself in the meantime to show it's available for someone else to try and reproduce.

@outofambit outofambit self-assigned this Mar 27, 2019
@outofambit
Copy link
Contributor

Hi @TCROC and thanks for the excellent reproduction example! I reproduced this on my machine and am going to start looking into a fix. I'll post updates here!

@outofambit outofambit added priority-2 Bug that affects more than a few users in a meaningful way but doesn't prevent core functions and removed investigation-needed Likely bugs, but haven't been reliably reproduced by a reviewer labels Mar 27, 2019
@billygriffin
Copy link
Contributor

Hi @TCROC, just wanted to echo the others' thanks for the excellent issue and description of how it's falling down for y'all. We're currently working on several features that we're hoping to ship toward the end of this month and unfortunately aren't able to prioritize this until after that work is complete. However, we totally agree that it's confusing and it's a priority for us to fix when that work is complete. Just wanted to let you know and set expectations that it wouldn't be immediately worked on, as much as we'd love to do so.

@outofambit outofambit removed their assignment Apr 3, 2019
@TCROC
Copy link
Author

TCROC commented Apr 4, 2019

@billygriffin Thanks for the update! :) I look forward to seeing how this turns out when time is found to work on it :)

@TCROC
Copy link
Author

TCROC commented Jul 13, 2019

@billygriffin @shiftkey @outofambit Hey. Just wanted to check in and see what the status is on this issue.

@TCROC
Copy link
Author

TCROC commented Jul 29, 2019

Hey just checking in to see what the status is on this

@billygriffin
Copy link
Contributor

Hi @TCROC, thanks for the gentle nudges, and sorry for the delay. We've got a couple folks out right now, so we haven't gotten to this yet. It'll be prioritized alongside the other priority 2 bugs, so I don't expect that it'll happen in the next couple weeks but as I mentioned before, we agree that it should be fixed. If you want to dig into what might be causing it to enable us to knock it out more quickly when we are able to get to it, you're welcome to do so, but certainly no obligation. Thanks again!

@TCROC
Copy link
Author

TCROC commented Jul 30, 2019

@billygriffin Thanks for the response :) . I'll come back to check in the next couple of weeks then :)

@TerryChan
Copy link
Contributor

I got the same issue on LFS conflict. I found GitHub Desktop has resolution on text file conflict and binary file(non-lfs) conflict, but has no resolution for LFS conflict, hope this issue can be resolved soon.

@TerryChan
Copy link
Contributor

I come up with a solution for this issue in this comment #8059 (comment)
Could you give some comments on this solution?

@TCROC
Copy link
Author

TCROC commented Aug 1, 2019

@TerryChan Yes that is what we are looking for in regards to our LFS merge conflicts via a GUI. A "Choose Mine" or "Choose Theirs" solution. A "Choose All Mine" or "Choose All Theirs" option would also be helpful to just act on all of the merge conflicts. Normally we do good about not having that many merge conflicts to worry about, but every once and a while when upgrading to a newer version of our game engine Unity, things don't go as smoothly and we need that "Choose All Mine" or "Choose all Their's" option. If anyone gets the chance to implement these features let me know and I'd love to try them out / provide feedback.

In regards to the actual git commands being invoked I'm not sure. Based on my understanding of git LFS, they look like they should work, but git commands are not my expertise. I will let someone else verify those.

I imagine the challenge probably falls more in line with determining if the file is in fact an LFS file and not just a txt file, but again I'll let the experts provide more light on the situation / what the challenges and potential solutions are in implementing this feature.

@outofambit
Copy link
Contributor

@TerryChan I believe that change will help with this issue, but I don't think its the complete solution. (we will probably need to also improve desktop's logic for detecting conflicts in LFS files, too)

@TerryChan
Copy link
Contributor

@outofambit yes, you are right, we still need to implement LFS conflict detection
I found when LFS conflict, the conflict file content will be a conflicted pointer file which contains conflict markers, no matter it's a bianry LFS or text LFS file.

And, the output of git diff --numstat MERGE_HEAD command will be:
image
It will detect 2 conflict markers (the output is similar to the binary conflcit, but not exact the same, that's why the LFS conflict detection failed in current GitHub Desktop). And the git diff --check command will output none, which means it will not treat it as a text conflict - even for text LFS file.

So for the detection, maybe we can use regex /2\t2\t(?:\0.+\0)?([^\0]*)/gi for the first check, and then check the files after the first check are not in the output of git diff --check comand. Maybe you have better solution to detect LFS conflict.

@theNth
Copy link

theNth commented Aug 16, 2019

If I'm not mistaken, there's a more fundamental, analogous issue with git rebase. Suppose you're working on a stack of commits where commits A and B both touch the text LFS file foo. Editing A in an interactive rebase results in a conflict at B when you run git rebase --continue, even if git would normally be able to resolve the conflict. Further, there's no easy way to resolve the rebase conflict; you just get hashes:

~/repo (branch|REBASE-i 2/2)$ git diff HEAD -- foo
diff --git a/foo b/foo
index 40b929909..ee924354a 100644
--- a/foo
+++ b/foo
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:b6b18c7e35b79624d65141dde71119f8f1f9742d28b474d4fef655f6c50900da
-size 3843822
+oid sha256:630e6288b57b7a3f3c1b98ee0c8add8604058627fe5d80ff279457b15eee6fac
+size 275

Trying to use git difftool gives a similar, uneditable result. When I encountered this issue, I had to resort to git reflog to figure out the git hash of the pre-rebase version of B, manually copy changes from A to B, and save the manually merged B version.

@TCROC
Copy link
Author

TCROC commented Aug 16, 2019

Hey @theNth Thanks for the response! I'm slightly confused though. We aren't trying to perform a rebase. We are trying to resolve LFS merge conflicts when merging one branch into another branch. I don't consider myself an expert in git by any means (which is partially why I enjoy GUIs like GitHub Desktop). However, I don't see where rebasing comes into play here. If you could expand further that would be great! Thanks :) .

@TCROC
Copy link
Author

TCROC commented Jan 16, 2020

@billygriffin All good. Completely understand. Thanks for the response. I hadn't' heard from any of you guys since July so I wanted to make sure it wasn't forgotten. I do look forward to hearing what comes from the discussions. 👍

@TCROC
Copy link
Author

TCROC commented Jan 25, 2020

Hey @billygriffin @wycfutures @PseudoNinja @shiftkey @outofambit @pkane @theNth @TerryChan I found a workaround to get the behaviour we are looking for! If you simply mark each LFS file as binary in .gitattributes, it behaves as expected. Here is the .gitattributes file my team is now using:

# Unity LFS
*.cubemap filter=lfs diff=lfs merge=lfs -text binary
*.unitypackage filter=lfs diff=lfs merge=lfs -text binary
*.mat filter=lfs diff=lfs merge=lfs -text binary
*.anim filter=lfs diff=lfs merge=lfs -text binary
*.unity filter=lfs diff=lfs merge=lfs -text binary
*.prefab filter=lfs diff=lfs merge=lfs -text binary
*.physicMaterial2D filter=lfs diff=lfs merge=lfs -text binary
*.physicMaterial filter=lfs diff=lfs merge=lfs -text binary
*.asset filter=lfs diff=lfs merge=lfs -text binary
*.meta filter=lfs diff=lfs merge=lfs -text binary
*.controller filter=lfs diff=lfs merge=lfs -text binary
*.sbsar filter=lfs diff=lfs merge=lfs -text binary
*.flare filter=lfs diff=lfs merge=lfs -text binary
*.playable filter=lfs diff=lfs merge=lfs -text binary

# 3D models
*.3dm filter=lfs diff=lfs merge=lfs -text binary
*.3ds filter=lfs diff=lfs merge=lfs -text binary
*.blend filter=lfs diff=lfs merge=lfs -text binary
*.c4d filter=lfs diff=lfs merge=lfs -text binary
*.collada filter=lfs diff=lfs merge=lfs -text binary
*.dae filter=lfs diff=lfs merge=lfs -text binary
*.dxf filter=lfs diff=lfs merge=lfs -text binary
*.fbx filter=lfs diff=lfs merge=lfs -text binary
*.jas filter=lfs diff=lfs merge=lfs -text binary
*.lws filter=lfs diff=lfs merge=lfs -text binary
*.lxo filter=lfs diff=lfs merge=lfs -text binary
*.ma filter=lfs diff=lfs merge=lfs -text binary
*.max filter=lfs diff=lfs merge=lfs -text binary
*.mb filter=lfs diff=lfs merge=lfs -text binary
*.obj filter=lfs diff=lfs merge=lfs -text binary
*.ply filter=lfs diff=lfs merge=lfs -text binary
*.skp filter=lfs diff=lfs merge=lfs -text binary
*.stl filter=lfs diff=lfs merge=lfs -text binary
*.ztl filter=lfs diff=lfs merge=lfs -text binary
*.spm filter=lfs diff=lfs merge=lfs -text binary

# Audio
*.aif filter=lfs diff=lfs merge=lfs -text binary
*.aiff filter=lfs diff=lfs merge=lfs -text binary
*.it filter=lfs diff=lfs merge=lfs -text binary
*.mod filter=lfs diff=lfs merge=lfs -text binary
*.mp3 filter=lfs diff=lfs merge=lfs -text binary
*.ogg filter=lfs diff=lfs merge=lfs -text binary
*.s3m filter=lfs diff=lfs merge=lfs -text binary
*.wav filter=lfs diff=lfs merge=lfs -text binary
*.xm filter=lfs diff=lfs merge=lfs -text binary

# Video
*.asf filter=lfs diff=lfs merge=lfs -text binary
*.avi filter=lfs diff=lfs merge=lfs -text binary
*.flv filter=lfs diff=lfs merge=lfs -text binary
*.mov filter=lfs diff=lfs merge=lfs -text binary
*.mp4 filter=lfs diff=lfs merge=lfs -text binary
*.mpeg filter=lfs diff=lfs merge=lfs -text binary
*.mpg filter=lfs diff=lfs merge=lfs -text binary
*.ogv filter=lfs diff=lfs merge=lfs -text binary
*.wmv filter=lfs diff=lfs merge=lfs -text binary

# Images
*.bmp filter=lfs diff=lfs merge=lfs -text binary
*.exr filter=lfs diff=lfs merge=lfs -text binary
*.gif filter=lfs diff=lfs merge=lfs -text binary
*.hdr filter=lfs diff=lfs merge=lfs -text binary
*.iff filter=lfs diff=lfs merge=lfs -text binary
*.jpeg filter=lfs diff=lfs merge=lfs -text binary
*.jpg filter=lfs diff=lfs merge=lfs -text binary
*.pict filter=lfs diff=lfs merge=lfs -text binary
*.png filter=lfs diff=lfs merge=lfs -text binary
*.psd filter=lfs diff=lfs merge=lfs -text binary
*.tga filter=lfs diff=lfs merge=lfs -text binary
*.tif filter=lfs diff=lfs merge=lfs -text binary
*.tiff filter=lfs diff=lfs merge=lfs -text binary

# Compressed Archive
*.7z filter=lfs diff=lfs merge=lfs -text binary
*.bz2 filter=lfs diff=lfs merge=lfs -text binary
*.gz filter=lfs diff=lfs merge=lfs -text binary
*.rar filter=lfs diff=lfs merge=lfs -text binary
*.tar filter=lfs diff=lfs merge=lfs -text binary
*.zip filter=lfs diff=lfs merge=lfs -text binary

# Compiled Dynamic Library
*.dll filter=lfs diff=lfs merge=lfs -text binary
*.pdb filter=lfs diff=lfs merge=lfs -text binary
*.so filter=lfs diff=lfs merge=lfs -text binary

# Fonts
*.otf filter=lfs diff=lfs merge=lfs -text binary
*.ttf filter=lfs diff=lfs merge=lfs -text binary

# Executable/Installer
*.apk filter=lfs diff=lfs merge=lfs -text binary
*.exe filter=lfs diff=lfs merge=lfs -text binary

# Documents
*.pdf filter=lfs diff=lfs merge=lfs -text binary

# Etc
*.bytes filter=lfs diff=lfs merge=lfs -text binary
*.url filter=lfs diff=lfs merge=lfs -text binary
*.pso filter=lfs diff=lfs merge=lfs -text binary
*.ptx filter=lfs diff=lfs merge=lfs -text binary
*.vso filter=lfs diff=lfs merge=lfs -text binary
*.gso filter=lfs diff=lfs merge=lfs -text binary
*.bin filter=lfs diff=lfs merge=lfs -text binary
*.dat filter=lfs diff=lfs merge=lfs -text binary
*.axobj filter=lfs diff=lfs merge=lfs -text binary

Sorry if I'm doing something wrong tagging all of you in here, but I know some of you were abandoning LFS completely because of this. I wanted to make sure you saw this as some of you made it seem critical to your project. I hope it helps. It's not really a solution as it is still a problem how GitHub Desktop handles LFS merge conflicts, but it does cause the expected behaviour to occur. I'm not sure if there will be any unexpected side effects from this. I will post more if I see anything negative happening. As of now, it seems like a nice workaround.

@ghost
Copy link

ghost commented Jan 25, 2020

Awesome! I will test it after the break.

@nerdneha nerdneha added this to Backlog (unprioritized) in Desktop 2.5 release via automation Mar 25, 2020
@nerdneha nerdneha moved this from Backlog (unprioritized) to Prioritized backlog (ordered) in Desktop 2.5 release Mar 25, 2020
@azmartone
Copy link

Hey @billygriffin @wycfutures @PseudoNinja @shiftkey @outofambit @pkane @theNth @TerryChan I found a workaround to get the behaviour we are looking for! If you simply mark each LFS file as binary in .gitattributes, it behaves as expected. Here is the .gitattributes file my team is now using:

# Unity LFS
*.cubemap filter=lfs diff=lfs merge=lfs -text binary
*.unitypackage filter=lfs diff=lfs merge=lfs -text binary
*.mat filter=lfs diff=lfs merge=lfs -text binary
*.anim filter=lfs diff=lfs merge=lfs -text binary
*.unity filter=lfs diff=lfs merge=lfs -text binary
*.prefab filter=lfs diff=lfs merge=lfs -text binary
*.physicMaterial2D filter=lfs diff=lfs merge=lfs -text binary
*.physicMaterial filter=lfs diff=lfs merge=lfs -text binary
*.asset filter=lfs diff=lfs merge=lfs -text binary
*.meta filter=lfs diff=lfs merge=lfs -text binary
*.controller filter=lfs diff=lfs merge=lfs -text binary
*.sbsar filter=lfs diff=lfs merge=lfs -text binary
*.flare filter=lfs diff=lfs merge=lfs -text binary
*.playable filter=lfs diff=lfs merge=lfs -text binary

# 3D models
*.3dm filter=lfs diff=lfs merge=lfs -text binary
*.3ds filter=lfs diff=lfs merge=lfs -text binary
*.blend filter=lfs diff=lfs merge=lfs -text binary
*.c4d filter=lfs diff=lfs merge=lfs -text binary
*.collada filter=lfs diff=lfs merge=lfs -text binary
*.dae filter=lfs diff=lfs merge=lfs -text binary
*.dxf filter=lfs diff=lfs merge=lfs -text binary
*.fbx filter=lfs diff=lfs merge=lfs -text binary
*.jas filter=lfs diff=lfs merge=lfs -text binary
*.lws filter=lfs diff=lfs merge=lfs -text binary
*.lxo filter=lfs diff=lfs merge=lfs -text binary
*.ma filter=lfs diff=lfs merge=lfs -text binary
*.max filter=lfs diff=lfs merge=lfs -text binary
*.mb filter=lfs diff=lfs merge=lfs -text binary
*.obj filter=lfs diff=lfs merge=lfs -text binary
*.ply filter=lfs diff=lfs merge=lfs -text binary
*.skp filter=lfs diff=lfs merge=lfs -text binary
*.stl filter=lfs diff=lfs merge=lfs -text binary
*.ztl filter=lfs diff=lfs merge=lfs -text binary
*.spm filter=lfs diff=lfs merge=lfs -text binary

# Audio
*.aif filter=lfs diff=lfs merge=lfs -text binary
*.aiff filter=lfs diff=lfs merge=lfs -text binary
*.it filter=lfs diff=lfs merge=lfs -text binary
*.mod filter=lfs diff=lfs merge=lfs -text binary
*.mp3 filter=lfs diff=lfs merge=lfs -text binary
*.ogg filter=lfs diff=lfs merge=lfs -text binary
*.s3m filter=lfs diff=lfs merge=lfs -text binary
*.wav filter=lfs diff=lfs merge=lfs -text binary
*.xm filter=lfs diff=lfs merge=lfs -text binary

# Video
*.asf filter=lfs diff=lfs merge=lfs -text binary
*.avi filter=lfs diff=lfs merge=lfs -text binary
*.flv filter=lfs diff=lfs merge=lfs -text binary
*.mov filter=lfs diff=lfs merge=lfs -text binary
*.mp4 filter=lfs diff=lfs merge=lfs -text binary
*.mpeg filter=lfs diff=lfs merge=lfs -text binary
*.mpg filter=lfs diff=lfs merge=lfs -text binary
*.ogv filter=lfs diff=lfs merge=lfs -text binary
*.wmv filter=lfs diff=lfs merge=lfs -text binary

# Images
*.bmp filter=lfs diff=lfs merge=lfs -text binary
*.exr filter=lfs diff=lfs merge=lfs -text binary
*.gif filter=lfs diff=lfs merge=lfs -text binary
*.hdr filter=lfs diff=lfs merge=lfs -text binary
*.iff filter=lfs diff=lfs merge=lfs -text binary
*.jpeg filter=lfs diff=lfs merge=lfs -text binary
*.jpg filter=lfs diff=lfs merge=lfs -text binary
*.pict filter=lfs diff=lfs merge=lfs -text binary
*.png filter=lfs diff=lfs merge=lfs -text binary
*.psd filter=lfs diff=lfs merge=lfs -text binary
*.tga filter=lfs diff=lfs merge=lfs -text binary
*.tif filter=lfs diff=lfs merge=lfs -text binary
*.tiff filter=lfs diff=lfs merge=lfs -text binary

# Compressed Archive
*.7z filter=lfs diff=lfs merge=lfs -text binary
*.bz2 filter=lfs diff=lfs merge=lfs -text binary
*.gz filter=lfs diff=lfs merge=lfs -text binary
*.rar filter=lfs diff=lfs merge=lfs -text binary
*.tar filter=lfs diff=lfs merge=lfs -text binary
*.zip filter=lfs diff=lfs merge=lfs -text binary

# Compiled Dynamic Library
*.dll filter=lfs diff=lfs merge=lfs -text binary
*.pdb filter=lfs diff=lfs merge=lfs -text binary
*.so filter=lfs diff=lfs merge=lfs -text binary

# Fonts
*.otf filter=lfs diff=lfs merge=lfs -text binary
*.ttf filter=lfs diff=lfs merge=lfs -text binary

# Executable/Installer
*.apk filter=lfs diff=lfs merge=lfs -text binary
*.exe filter=lfs diff=lfs merge=lfs -text binary

# Documents
*.pdf filter=lfs diff=lfs merge=lfs -text binary

# Etc
*.bytes filter=lfs diff=lfs merge=lfs -text binary
*.url filter=lfs diff=lfs merge=lfs -text binary
*.pso filter=lfs diff=lfs merge=lfs -text binary
*.ptx filter=lfs diff=lfs merge=lfs -text binary
*.vso filter=lfs diff=lfs merge=lfs -text binary
*.gso filter=lfs diff=lfs merge=lfs -text binary
*.bin filter=lfs diff=lfs merge=lfs -text binary
*.dat filter=lfs diff=lfs merge=lfs -text binary
*.axobj filter=lfs diff=lfs merge=lfs -text binary

Sorry if I'm doing something wrong tagging all of you in here, but I know some of you were abandoning LFS completely because of this. I wanted to make sure you saw this as some of you made it seem critical to your project. I hope it helps. It's not really a solution as it is still a problem how GitHub Desktop handles LFS merge conflicts, but it does cause the expected behaviour to occur. I'm not sure if there will be any unexpected side effects from this. I will post more if I see anything negative happening. As of now, it seems like a nice workaround.

The binary flag doesn't seem to do anything in github desktop

@TCROC
Copy link
Author

TCROC commented Apr 10, 2020

What version of GitHub Desktop are u using? It still seems to be working for us.

@azmartone
Copy link

Forgive me, I was rebasing my feature branch onto master and master does not have the updates to the gitattributes file. So github desktop did not use those new settings during the rebase.

@paradroid001
Copy link

I just want to thank @TCROC for this workaround. Without it, using Github Desktop for any kinds of conflicts with binary files would just be painful. This saved me a whole heap of time!

@monoteba
Copy link

monoteba commented Apr 25, 2020

Am I wrong in saying that the binary macro is the same as setting -diff -text? https://git-scm.com/docs/gitattributes#_using_macro_attributes

Doesn't that break something with LFS? Can you confirm your entire history for binary files isn't stored locally now? Instead of only the latest version, keeping versions remote.

Which parts of LFS is required for it to work as intended? Is filter=lfs for example enough? Sorry, but I don't fully understand the gitattributes yet.

Trying @TCROC example only allows me to choose my own changes and results in an error 128 if I try to choose the changes from remote. Something about git credentials.

@TCROC
Copy link
Author

TCROC commented Apr 25, 2020

@mortenblaa

Am I wrong in saying that the binary macro is the same as setting -diff -text? https://git-scm.com/docs/gitattributes#_using_macro_attributes

image

Reading the docs, it says it "unsets" the -diff -text attributes. I also misread that as "sets" at first. So to answer your question, the binary macro is NOT the same as -diff -text according to those docs.

Doesn't that break something with LFS? Can you confirm your entire history for binary files isn't stored locally now? Instead of only the latest version, keeping versions remote.

I just checked my remote history and the changes appear to be there. I can confirm that I do not have a problem pulling down to different machines using the binary flag. This makes me believe that it is all working correctly.

Which parts of LFS is required for it to work as intended? Is filter=lfs for example enough? Sorry, but I don't fully understand the gitattributes yet.

I am also not an expert in gitattributes or LFS. Just doing some quick Googling, I found some docs that might be worth a read:

Trying @TCROC example only allows me to choose my own changes and results in an error 128 if I try to choose the changes from remote. Something about git credentials.

Our team has not yet noticed any issues using the binary flag. Everything appears to store on the remote. In regards to your credential errors, it sounds like it is trying to access the remote changes but can't because you don't have the credentials for the remote. If that is the case, yes you would only be able to access things locally. I do not think it has any relation to LFS or the binary flag.

@monoteba
Copy link

But doesn't -text mean unset and text mean set? At least that's how I have been interpreting it. Also according to the documentation https://git-scm.com/docs/gitattributes#_description

Set
The path has the attribute with special value "true"; this is specified by listing only the name of the attribute in the attribute list.
Unset
The path has the attribute with special value "false"; this is specified by listing the name of the attribute prefixed with a dash - in the attribute list.
Set to a value
The path has the attribute with specified string value; this is specified by listing the name of the attribute followed by an equal sign = and its value in the attribute list.
Unspecified
No pattern matches the path, and nothing says if the path has or does not have the attribute, the attribute for the path is said to be Unspecified.

Regarding the credentials, I just signed in using my GitHub account and the repository was created by me. Besides that one error I can push/pull just fine. The error only appears when I add the binary macro and like I said, only when trying to choose the remote file. Maybe I'll give it a shot with a new repo.

Thanks for following up @TCROC :)

@TCROC
Copy link
Author

TCROC commented Apr 25, 2020

@mortenblaa

But doesn't -text mean unset and text mean set? At least that's how I have been interpreting it. Also according to the documentation https://git-scm.com/docs/gitattributes#_description

I did not know that. If that is the case, I imagine the -text is probably redundant. Try it in your gitattributes and let us know if you see any different behavior.

@monoteba
Copy link

@TCROC I tried creating a new project on GitHub. Then I added the .gitignore and .gitattributes to the repo, comitted and pushed those. After, I cloned the repo to another computer.

Then I added an 8k png to clearly see if there was any size changes. Pushed that from computer A and pulled on computer B.

On both computers I then modified the png, and comitted and pushed from B. On A, I comitted but waited for B to finish, and followed with a pull on A.

Finally the merge conflict appeared with an option between using the modified file from master or origin/master. Here I selected "origin/master", and I ended up with the following error:

Commit failed - exit code 128 received, with output: 'fatal: could not read Username for 'https://github.com': Device not configured
Downloading image-1.png (49 MB)
fatal: could not read Username for 'https://github.com': Device not configured
Error downloading object: image-1.png (2be91b8): Smudge error: Error downloading image-1.png (2be91b88411c3cf08666fd3c17695748f2d96014c9a1972c8dca4db67966cde6): batch response: Git credentials for https://github.com/mortenblaa/git-unity-testing.git not found.

Errors logged to /logs/20200426T100539.434326.log
Use `git lfs logs last` to view the log.
error: external filter 'git-lfs filter-process' failed
fatal: image-1.png: smudge filter lfs failed'

However, if I manually resolve the conflict with
git checkout --theirs image-1.png

It succeeds. No issues with signing in. Maybe this is caused by another bug in Desktop.

I would also like to point out, that my .git folder gradually increased in size.

After the first commit, it was 47 MB.
And after the last merge resolution the .git folder was 140 MB. Basically 3 versions of the image.

The original image is 49 MB.

@monoteba
Copy link

I had a look at my gitconfig and noted there were additions from various sources. Including sourcetree. So I removed it and re-signed in and tried again. However, same result. If anyone is interested my gitconfig looks like this now (I have removed the username and email):

credential.helper=osxkeychain
filter.lfs.clean=git-lfs clean -- %f
filter.lfs.smudge=git-lfs smudge -- %f
filter.lfs.process=git-lfs filter-process
filter.lfs.required=true
user.name=XXXX
user.email=XXXX
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
core.ignorecase=true
core.precomposeunicode=true
submodule.active=.
remote.origin.url=https://github.com/mortenblaa/git-unity-testing.git
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
branch.master.remote=origin
branch.master.merge=refs/heads/master
lfs.https://github.com/mortenblaa/git-unity-testing.git/info/lfs.access=basic

@monoteba
Copy link

Actually, just watched the .git folder while committing files without the binary macro, and my local .git folder also increased in size with "normal" LFS commits. Seems like git lfs prune clears those out :)

@TCROC
Copy link
Author

TCROC commented May 2, 2020

Actually, just watched the .git folder while committing files without the binary macro, and my local .git folder also increased in size with "normal" LFS commits. Seems like git lfs prune clears those out :)

@mortenblaa Have you noticed your pushes to ever be strangely large? I had an instance where my pushes seem to be way larger than the files I am altering. I deleted my git repo, pulled it back down, and it seems to have fixed itself. If it happens again I'll see if git lfs prune fixes it. I'm wondering if it has anything to do with the way the .gitattributes file is configured.

@monoteba
Copy link

monoteba commented May 3, 2020

@TCROC No, I haven't experienced that. I only noticed my Unity scene files compressed really well when set to binary, from about 22 MB to 1.6 MB. Maybe try pushing using the command line and see if you notice anything odd. It might give you more insight, where Desktop hides some information.

Right now I'm working with a gitattributes looking something like this (though with many more types):

# Source code
*.cs merge diff=csharp -text

# Unity (no automatic merge)
*.meta merge=binary diff -text
*.unity merge=binary diff -text

# LFS
*.unitypackage filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text

Note that I've unset text for C#, but that's only because I don't want Git to change line endings.

I generally don't add Unity file types to LFS, since they are text files and diff well, so they don't have to rely on binary patches. At least the local repo growed faster, with Unity types in LFS, but may only be locally because of how LFS keeps versions. I'm unsure if the remote repo actually made better patches with Unity types in LFS and didn't increase that much in size.

@billygriffin
Copy link
Contributor

Hi @TCROC, sorry for the delay in getting back to you. #9702 is merged and now available on beta (and will be on production next week), which provides the option to choose either version for all file types now and not just explicitly binary files. Do you think that can also close this issue? It's not super clear to me whether there's something specific to LFS that requires further detection logic beyond providing the choice for all file types.

@TCROC
Copy link
Author

TCROC commented May 8, 2020

@billygriffin I think being able to do this for all file types should solve this issue. I will test out the beta version quick and if it works as expected, I will close this issue.

@TCROC
Copy link
Author

TCROC commented May 8, 2020

@billygriffin Where can I download the beta?

@billygriffin
Copy link
Contributor

@TCROC Sorry about that! I totally should've included a link in my original response. Here it is: https://github.com/desktop/desktop#beta-channel

@TCROC
Copy link
Author

TCROC commented May 8, 2020

@billygriffin After testing, I am sad to say that it does not resolve the issue 😞 . GitHub Desktop still merges the pointers of the LFS file:

GitHub Desktop incorrectly merging LFS pointer together and marking conflicts as fixed

image

Visual Studio Code correctly detecting merge conflicts with LFS file

image

Visual Studio correctly detecting merge conflicts with LFS file

image

The conflicted file is a png image and marked with this in the .gitattributes file:

*.png filter=lfs diff=lfs merge=lfs -text

TL; DR;

Visual Studio Code = works
Visual Studio = works
GitHub Desktop = broken

The reason I mention the other tools is because there has been much discussion about whether it is an LFS issue or a GitHub Desktop issue. Because other tools work and GitHub desktop does not, I am lead to believe that it is a GitHub Desktop issue.

However, I did make one interesting discovery in this test. I found that when modifying a file created with the Unity Game Engine that is marked to handle merge conflicts like this:

*.asset merge=unityyamlmerge eol=lf

It worked. Therefore, it could be a combination of an issue with LFS and GitHub Desktop. The only way to know if it is an LFS issue would be to recreate this with the command line. Because I have only done it with GitHub Desktop GUI, tried other GUIs, and these are the results I see, I still conclude that it is an issue with GitHub Desktop and will be keeping this issue open.

UPDATE
This can also be seen in the below comment. Edited in here for ease of reading.

image

I just tested it with the command line. I can confirm that it works as expected in the command line. This clarifies that it is not an issue with Git LFS. It is in fact an issue with GitHub Desktop.

@TCROC
Copy link
Author

TCROC commented May 8, 2020

@billygriffin

image

I just tested it with the command line. I can confirm that it works as expected in the command line. This clarifies that it is not an issue with Git LFS. It is in fact an issue with GitHub Desktop.

dacanizares added a commit to equilaterus/ue4-gitlfs-baseproject that referenced this issue Aug 3, 2020
https: //github.com/desktop/desktop/issues/7166
Co-Authored-By: Edwin Osorio <30908546+edwin1106@users.noreply.github.com>
Co-Authored-By: Juan Felipe Cañizares Corrales <pipecaniza@outlook.com>
dacanizares added a commit to equilaterus-gamestudios/ue4-gitlfs-baseproject that referenced this issue Aug 8, 2020
https: //github.com/desktop/desktop/issues/7166
Co-Authored-By: Juan Felipe Cañizares Corrales <pipecaniza@outlook.com>
Co-Authored-By: Edwin Osorio <30908546+edwin1106@users.noreply.github.com>
@matteblair
Copy link

Thanks for the thorough and helpful discussion on this issue! I've encountered this problem too (also with art files in a Unity project) and so I've tried the work-around using the binary attribute. I found some details that may be helpful to others.

The work-around described above is to append the binary attribute to the usual LFS attribute list, producing this attribute list: filter=lfs diff=lfs merge=lfs -text binary. I can confirm that GitHub Desktop does use manual conflict resolution for files using this attribute list, which resolves the issue. But how does this actually affect the attributes that git is applying to these files? I used git check-attr to find out.

With the usual LFS attribute list (filter=lfs diff=lfs merge=lfs -text) we get these attributes:

LFSTrackedFile.asset: diff: lfs
LFSTrackedFile.asset: merge: lfs
LFSTrackedFile.asset: text: unset
LFSTrackedFile.asset: filter: lfs

And with binary added (filter=lfs diff=lfs merge=lfs -text binary) we get these attributes:

LFSTrackedFile.asset: binary: set
LFSTrackedFile.asset: diff: unset
LFSTrackedFile.asset: merge: unset
LFSTrackedFile.asset: text: unset
LFSTrackedFile.asset: filter: lfs

The binary attribute is set, but now the diff and merge attributes are unset! This is because binary is in fact a macro attribute that, when applied, unsets the diff, merge, and text attributes.

What is the effect of having diff and merge unset instead of set to the value lfs? Unclear! Unlike filter, I believe that git LFS does not currently do anything with these attributes and that they are reserved for some future use.

Ideally, you'd want to keep those attributes as-is to avoid potential issues with LFS. You can do this by putting the binary attribute before the LFS attributes, as in: binary filter=lfs diff=lfs merge=lfs -text. This produces the attributes:

LFSTrackedFile.asset: binary: set
LFSTrackedFile.asset: diff: lfs
LFSTrackedFile.asset: merge: lfs
LFSTrackedFile.asset: text: unset
LFSTrackedFile.asset: filter: lfs

This seems like exactly what we want! Except that GitHub Desktop does not use manual conflict resolution for files with these attributes (which is the whole point of this work-around).

By experimentation, I've found that GitHub Desktop will only use manual conflict resolution on files that have the diff attribute unset. Why? My best guess is this:

export async function getBinaryPaths(
repository: Repository,
ref: string
): Promise<ReadonlyArray<string>> {
const { output } = await spawnAndComplete(
['diff', '--numstat', '-z', ref],
repository.path,
'getBinaryPaths'
)
const captures = getCaptures(output.toString('utf8'), binaryListRegex)
if (captures.length === 0) {
return []
}
// flatten the list (only does one level deep)
const flatCaptures = captures.reduce((acc, val) => acc.concat(val))
return flatCaptures
}
const binaryListRegex = /-\t-\t(?:\0.+\0)?([^\0]*)/gi
This function is calling git diff --numstat and scanning the output for patterns that indicate a "binary" file, according to git. In my testing, I've found that the cases where GitHub Desktop uses manual conflict resolution correspond exactly to when git diff --numstat classifies a file as "binary".

TL;DR A "minimal" work-around for this issue is to change the attributes in your .gitattributes file for LFS files to

filter=lfs merge=lfs -diff -text

But be aware that this (or the binary attribute) may cause issues with future versions of LFS.

@connorjak
Copy link

@billygriffin After testing, I am sad to say that it does not resolve the issue 😞 . GitHub Desktop still merges the pointers of the LFS file:

GitHub Desktop incorrectly merging LFS pointer together and marking conflicts as fixed

image

I think I'm reproducing this issue with diff=lfs files.

GitHub Desktop Version 2.6.5

Windows 10 Pro 20H2 (19042.804).

Using @matteblair 's filter=lfs merge=lfs -diff -text appears to have immediately fixed the issue on my repo, at least for the moment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Confirmed bugs or reports that are very likely to be bugs priority-2 Bug that affects more than a few users in a meaningful way but doesn't prevent core functions
Projects
No open projects
Desktop 2.5 release
Prioritized backlog (ordered)
Development

No branches or pull requests