Changes in .attributes leads to "empty" svn commit (no change in svn, but files listed as changed)

After importing from svn your .gitattributes may look like

/COPYING.txt svneol=native#text/plain

Adding a line (for future added files) like either of the next to (only one of them):

*.txt -text svneol=native#text/plain
*.txt -text svneol=native#text/foo

Will lead to all *.txt files in svn being marked as changed. Though neither their text content, nor their properties have any actual change.

As for adding the: -text
This had not been intentional. But it is technically allowed.

I suspect, this is due to all txt files now having the -text, which is relevant for git, but does in the above scenario not influence the svn files.

Forgot: the *.txt line is to be added on top of the file.

So existing files will keep (later lines override previous lines) their svneol and mime type.
They indeed keep them in svn, but are listed as changed in the commit

Hello Martin.

Actually, adding one of those lines does change files properties in SVN; we have just re-tested it and found that properties in SVN have changed and that why files are being marked changed.
Do I understand correctly the main question here is why the files are marked changed? If not, please advise what could we help you with.
Btw, we have an article on the EOLs matter, it could be useful:

Ok, here is the actual case

The revision that was committed by subgit

It lists all the files that supposedly have changes (incl property changes). The list is cut off by default, but can be expanded at the bottom.

Attached is an svn diff for that revision. Many files are not listed, they have apparently no change?

Attached is also the gitatribute file, as it was after/by this commit.
The only change, made to that file in that commit was the addition of lines 2, 3 & 4

*.pas -text svneol=native#text/pascal
*.pp -text svneol=native#text/pascal
*.txt -text svneol=native#text/pascal

The change should not have had the -text. That was my mistake. For working with git that makes not much sense. But that aside, technically it is a valid change.
Those changes of course affect who git is dealing with those file…

But from all I can see most files in svn have no change to their property (svn diff is not listing them). Yet svn claims those files were changed (and subgit took a long time to make that commit).

svn diff also does not say anything about content changes.
On the off-chance that svn is hiding spaces or crlf changes
This is one of the files that is marked as changed. It is not listed by svn diff (no actual changes)
And according to svn it has
File length: 1102 byte(s)
before and after that commit.

Just to mention, this is subgit 3.3.5
But the release note for 3.3.6 do not suggest any change related to this.

Apologies, it may indeed be that subgit saw actual changes.

I spoke to the svn admin, and it may be that the svn server enforces line endings => effectively reverting them.

I still wonder though: If the original setting was
* text=auto !eol
Then any file that subgit retrieved from svn (initial import) should have had the same line ending, as it had in svn? (Since the other setting was svneol=native)

The majority of the files in question were never changed in git. They still were from the initial import.

From your blog, the only way subgit should have pushed them with new line endings would be eol=crlf
I did a
git config -l
in the git directory on which subgit runs:

I might be missing some other important bit, in which case I apology if the report turns out to be my fault.

gitsub is running on linux

Hello Martin,
thanks for the link to the certain revision. I’ll have a deeper look and try to understand and probably reproduce the problem. The whole topic of line endings conversion is complicated in both Git and SVN, unfortunately. But as your repository is open source, I can analyze the problem myself and find out what’s wrong.

Meanwhile, I recommend you:

  1. not to change recursive rules (rules not starting with leading slash, e.g. “" or ".pas”) in .gitattributes file whenever possible; otherwise such changes could be translated as massive changes in SVN, be they empty (I’ll check if it’s a bug) or non-empty;
  2. not to use self-contradicting rules like
    *.pas -text svneol=native#text/pascal
    when possible ("-text" should be used for binary only, “text=auto” rule handles binary files already; “!eol” rule implies svn:eol-style=native, but you can overwrite it with “eol=lf” or “eol=crlf”; finally “svneol” can override both svn:eol-style and svn:mime-type, but it’s better to align those values with corresponding “text” and “eol” attributes).

Normally all those recommendations are just recommendations. If you violate them, it’s still a valid configuration, but this way you may get into edge cases.

This particular case could be fixed by this patch, but I would prefer not to apply it and not to fix that at all. There always will be problems of this kind, we can’t fix them all.

Some description why this happens. When sending deltas between old and new file to SVN, we [nearly] always open the old and new blob, then apply filters like “text” and “eol” attributes and it’s up to SVN, whether the files will be different or the same after applying the filters. But even if the contents (old and new) are the same after applying the filters, the files show up in the “svn log -v” output.

We already perform some checks, e.g. if the file (old and new) has the same “text” and “eol” value (i.e.), and the same blob id, its content is considered as unchanged.
The user ran into a problem when “text” is effectively changed from “auto” to “unset”. This means that SVN content is changed from LF-based (as svn:eol-style=native) to “as-is” (which also appears to contain LFs in this particular case; if the files contained CRLFs or mixed EOLs, they wouldn’t be unchanged).

If we would really wanted to make sure there’re no unchanged files in SVN, we should perfrom either 1) double check for each file (fully read its content — old and new — with filters applied) before deciding whether to call openFile(); 2) or call abortEdit() at the end and collect the list of files we shouldn’t touch (if there’re any — closeEdit() otherwise) and re-run transation once again taking this information into account.

(1) would degrade the performance 2x; (2) is too complicated.

So for now, I would leave the behaviour as is and explain to the user not to perform such recursive changes.

The patch attached could be a small improvement of the current behaviour but it even it doesn’t fix the issue and I would prefer not to apply it as well.