Summary

git diff doesn't support CR (^M) as a line ending. This is a Git limitation, and not something related to Bitbucket Server or Stash. This manifests in two ways:

  • Files which only contain CR line endings show as a single-line diff, but they are processed correctly
  • Files with mixed line endings (part of the file is LF, or CRLF, and part is CR) show unexpected results and can fail processing entirely
  • When a mixed-ending file fails diffs, it can cause cascading failures in other parts of the system. The most important of these is comment drift, but it can also cause user-visible errors when attempting to view commit or pull request diffs.

    Expected Results

    Unexpected CR (^M) line endings in the output shouldn't cause diff processing to fail..

    Actual Results

    One example of a CR (^M) related failure appearing in atlassian-bitbucket.log :

    atlassian-bitbucket.log
    2016-02-13 18:03:51,028 DEBUG [drift:thread-1]  c.a.bitbucket.scm.BaseCommand Executed /usr/local/git/bin/git diff -C --color=never -U1
    0 --dst-prefix=dst:// --src-prefix=src:// da4a5448b487f62ef520a400f17db84fc82eb1ec 521a0d8597944d79ad88f1c0230da962b37900c0 --
    2016-02-13 18:03:51,035 ERROR [drift:thread-1]  c.a.s.i.p.c.d.DriftCommentUpdateProcessor 13108:352@27: Error calculating comment drift
    (1 attempts).
     First: 13108:360@14 (004bf1e4586c5ba193847e23d387393dda043d80, cd4936b90d6daab2df118a360c219c0f4bec65ea) -> (004bf1e4586c5ba193847e23d387393dda043d80, 5018f411979ba93ed8bbfa0bd1a8a356b65865b1)
            Last: 13108:360@14 (004bf1e4586c5ba193847e23d387393dda043d80, bf5df9fbf301c2776715a1bda416909edcee31a7) -> (004bf1e4586c5ba193847e23d387393dda043d80, 7fedf1e8d3a169332891b5b5aea2ed34aa110a99)
    com.atlassian.bitbucket.ServerException: An error occurred while executing an external process: Expected diff header, but found [@@ -4145,9 +4145,9 @@ l5^Mɷ^Ot]
            at com.atlassian.bitbucket.scm.git.command.GitCommandExitHandler.evaluateThrowable(GitCommandExitHandler.java:115) ~[na:na]
            at com.atlassian.bitbucket.scm.git.command.GitCommandExitHandler.onCancel(GitCommandExitHandler.java:49) ~[na:na]
            at com.atlassian.bitbucket.scm.BaseCommand.callExitHandler(BaseCommand.java:135) ~[bitbucket-spi-4.1.0.jar:na]
            at com.atlassian.bitbucket.scm.BaseCommand$CommandFuture.internalGet(BaseCommand.java:251) ~[bitbucket-spi-4.1.0.jar:na]
            at com.atlassian.bitbucket.scm.BaseCommand$CommandFuture.get(BaseCommand.java:220) ~[bitbucket-spi-4.1.0.jar:na]
            at com.atlassian.bitbucket.scm.BaseCommand.call(BaseCommand.java:75) ~[bitbucket-spi-4.1.0.jar:na]
            at com.atlassian.stash.internal.pull.comment.drift.DiffCommentDriftStrategy.calculateDrift(DiffCommentDriftStrategy.java:233) ~[bitbucket-service-impl-4.1.0.jar:na]
    

    Workaround

    CR (^M) is not a valid line ending to Git. Files which use CR line endings should be converted to use either LF (Linux, Unix) or CRLF (Windows) line endings. Files which consistently use LF or CRLF endings will diff correctly and parse without issue.