Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 226
SyntaxT3rr0r Avatar asked Sep 08 '11 13:09

SyntaxT3rr0r


3 Answers

$ 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.

like image 64
kostix Avatar answered Nov 13 '22 16:11

kostix


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.

like image 5
Jonathan Leffler Avatar answered Nov 13 '22 16:11

Jonathan Leffler


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.

like image 1
amattn Avatar answered Nov 13 '22 17:11

amattn