SyntaxT3rr0r
SyntaxT3rr0r

Reputation: 28333

Go's gofmt and diff/VCS issues?

I've got a question about Go's gofmt tool, which formats automatically the output of programs according to the official Go specs (for example you cannot argue about where brackets should go in Go, because that's apparently fixed by the specs).

On the following page:

http://golang.org/doc/effective_go.html

under the "Formatting" paragraph, it is written that:

As an example, there's no need to spend time lining up the comments on the fields of a structure. Gofmt will do that for you. Given the declaration

type T struct {
    name string // name of the object
    value int // its value
}

gofmt will line up the columns:

type T struct {
    name    string // name of the object
    value   int    // its value
}

However I don't understand how this could possibly play nice with diff and VCSes.

For example, if I had a new line:

confuzzabler int // doo doo be doo

and run a diff, I should get this:

2d1
<     confuzzabler int // doo doo be doo
7d5
< 

And life would be all good: the diff shows the only line that got changed.

However if I re-run the gofmt I got this:

type T struct {
    confuzzabler int    // doo doo be doo
    name         string // name of the object
    value        int    // its value
}

And now I re-run diff and I get this:

2,4c2,3
<     confuzzabler int    // doo doo be doo
<     name         string // name of the object
<     value        int    // its value
---
>     name    string // name of the object
>     value   int    // its value
7d5
< 

Which is a highly confusing and misleading diff output because only one line changed.

How do you deal with this as a Go developer?

Upvotes: 8

Views: 1632

Answers (3)

amattn
amattn

Reputation: 10065

If this really bothers you, do two checkins.

The first check in adds confuzzabler. A reasonable comment is "Adding new variable to T". Your diff will be isolated to the code you have actually changed.

Then, perform gofmt.

The second commit is just formatting changes and a reasonable commit msg would be "gofmt". The diff here will be only code that gofmt has changed.

Upvotes: 1

Jonathan Leffler
Jonathan Leffler

Reputation: 754860

Your Go-based project standards should dictate something like:

Before any Go code is committed to the VCS, it is formatted with gofmt. This is the only acceptable format.

Then there is no argument; if the code passes through gofmt unchanged, all is well. If it changes when passed through gofmt, then use the output from gofmt. What you do while editing is up to you (subject to the other coding standards), but this is a requirement for any code checked into your VCS.

Upvotes: 5

kostix
kostix

Reputation: 55563

$ diff --help|grep -i white
  -b  --ignore-space-change  Ignore changes in the amount of white space.
  -w  --ignore-all-space  Ignore all white space.

As to issues with VCS, if you were formatting the code yourself following some established convention (let's assume here this convention is what gofmt follows) you'd have manually reformatted the whitespace in that code block exactly the way gofmt did, and this change would have been counted by any VCS as a change. So I don't see any problem with semantics in this case, really. If you instead care about diffing tools provided by VCSes you should probably look whether they do support ignoring whitespace changes as the GNU diff mentioned above does. FWIW git diff does support this with the same -b command line option.

Upvotes: 6

Related Questions