Using gitattributes to improve git output
From the git man page:
A gitattributes file is a simple text file that gives attributes to pathnames.
gitattributes
allows you to tell git that files should be
treated in certain ways. You can use git attributes to apply various attributes
but we're focussing on diff
. For example, this tells git that files ending in
*.ex
should be treated as Elixir code during diff operations.
1
*.ex diff=elixir
I couldn't get the standard ~/.gitattributes
file location to work for me so I
decided to take this opportunity to standardise all my git config under
~/.config/git
instead.
TIP You can use git check-attr --all -- path/to/file
to
check which attributes are applying to a file. This is very useful during setup.
So what effect does this have?
Hunk output
Here's a simple example. On line 5 we can see a change, but that isn't the
important part. The interesting difference is what's shown on line 1 after the
filename. In this case it's defmodule TestWeb.ListController
which in the
Elixir module in which the change has been made.
1
2
3
4
5
6
7
8
9
@ path/to/file.ex:25 @ defmodule TestWeb.ListController do
{:ok, _list} = Lists.delete_list(list)
conn
+ |> put_flash(:info, "List deleted successfully.")
- |> put_flash(:info, "List deleted successfully")
|> redirect(to: Routes.list_path(conn, :index))
end
end
If we add *.ex diff=elixir
to the attributes file we see def delete(conn,
%{"id" => id})
, which is the function containing the change. Far more
specific.
1
2
3
4
5
6
7
8
9
@ path/to/file.ex:25 @ def delete(conn, %{"id" => id}) do
{:ok, _list} = Lists.delete_list(list)
conn
+ |> put_flash(:info, "List deleted successfully.")
- |> put_flash(:info, "List deleted successfully")
|> redirect(to: Routes.list_path(conn, :index))
end
end
--function-context
Adding this setting also changes the way that
--function-context
works. What is --function-context
? It
can be passed to git diff
(and other subcommands) and will show the full
change in the full context of where the change has been made. By default this
means it will show the full module, which is probably not what you want most
of the time.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@ path/to/file.ex:25 @ def delete(conn, %{"id" => id}) do
defmodule TestWeb.ListController do
use TestWeb, :controller
# ...other functions removed for brevity
def delete(conn, %{"id" => id}) do
list = Lists.get_list!(id)
{:ok, _list} = Lists.delete_list(list)
conn
+ |> put_flash(:info, "List deleted successfully.")
- |> put_flash(:info, "List deleted successfully")
|> redirect(to: Routes.list_path(conn, :index))
end
end
However, with the change to gitattributes
, the "function context" becomes the
actual function.
1
2
3
4
5
6
7
8
9
10
11
@ path/to/file.ex:25 @ def delete(conn, %{"id" => id}) do
def delete(conn, %{"id" => id}) do
list = Lists.get_list!(id)
{:ok, _list} = Lists.delete_list(list)
conn
+ |> put_flash(:info, "List deleted successfully.")
- |> put_flash(:info, "List deleted successfully")
|> redirect(to: Routes.list_path(conn, :index))
end
end
It's strange that a lot of the available gitattibutes
are not defaults in git.
But with a few simple tweaks you can get more useful git output.