Ancient art of Git-fu
Tags: git
Published: 2020-04-28 11:22:36

I have been using Git for quite some time now, my [GitHub profile](https://github.com/slax0rr/) is almost 8 years old, and I have been using Git before joining GitHub for at least 2 years. I think I can safely say I have been using it for around 10 years. Not just as a contributor to the various repositories on Git, but also as a tool to help me debug an error in the application or library. You might wonder how Git could provide help with that, well, it holds the secrets to when something was changed, why it was changed, and by who it was changed. Its a treasure, and you should treat it like on as well.

Of course there are some unwritten rules or guidelines on how to treat your Git history like a treasure, and I will try to run through a couple of them.

## Commit soon, commit often

This first guideline might seem a bit backward, since to keep the history clean you might want to reduce the number of commits, but committing sooner and more often will help your with writing the code, more specifically when you need to make alterations, because you've decided to design your code in a different way.  So for now, do not worry how your history looks like, make commits as soon as some logical piece of your code is finished. If you later find out you don't need some piece of your code, you can simply remove that commit, and presto, that piece of code or that change of code is gone.

This will hopefully keep you from keeping up with another guideline, **don't commit commented code**. Seriously, just don't. When searching through the history you create a whole lot more false positives, extending the time to find what you are actually looking for in the history as all those commits which commit commented code also show up. You don't need to comment some old code in case you'll need it later or you're not sure about the change. That code you changed is still kept in the original form in git history, even if you don't commit anything, you can still find it by issuing a `git diff -- filename` command.

### Clean up commits before publishing

If you are following the above guideline, you probably now have a pretty messy history on your hands. And hopefully you also haven't already have published your commits to the remote, and you have them only locally. It's time to clean them up. To start, execute `git rebase --interactive`, if you still have some uncommitted changes, commit them now, or stash them using `git stash`. The **rebase** command will open your git set editor with something similar to:

```git
pick a4e64eb canged the error response text
pick 919f447 return an error when record not found
pick c7d7e82 bubble the error object up to the handler

# Rebase f2b16ac..c7d7e82 onto f2b16ac (3 commands)
#
# Commands:

... description of the commands follows bellow in the article ...
```

At the very beginning each line is one commit in the following form:

`<command> <commit short hash> <commit message title>`

To edit the history you simply edit the command for each line that you want to edit. Available commands are:

* **pick** - use commit as is
* **reword** - use commit as is but edit the commit message
* **edit** - pause the *rebase* and allow for amending of the commit
* **squash** - merge the commit with the previous commit
* **fixup** - same as squash and use previous commits message
* **exec** - execute the shell command found on the same line (add a new line with this command, i.e.: `exec ls`)
* **drop** - remove the commit (removing the line will also remove the commit)

In the above example I would want to squash the `919f447` and `c7d7e82` commits together, which would mean I would change the 3rd commits command from `pick` to `squash` or `fixup`, depending if I want to edit the commit message or not.  After the change, simply save the file and quit the editor and *rebase* will run.

## Finish your work before committing

Don't use git as a means to transfer your work from one machine to another. Or at least don't do this in any branches that are used by you or your team. If you absolutely HAVE to use git to transfer your edited files to a different machine then at least create a brand new branch, commit your changes there, and once you've transferred your work, remove that commit and branch from the remote immediately:

```shell
git push # I guess you will want to, but this step is optional
git checkout -b yourhandle_temp # create a new branch with your uncommited changes
git add . && git commit -m "transfering my work"

# on the other machine:
git fetch
git checkout yourhandle_temp
git push origin :yourhandle_temp # remove the remote branch
git reset HEAD~1 # remove the temp commit and leave files unstaged
```

### Alternatives

A much more cleaner approach would be to stash your changes and export them to a file:

```shell
git stash
git stash show -p > some.patch
```

Now take this file to your other machine via a thumb drive or some file sharing service, or however you want and apply this patch on your other machine:

```shel
git apply some.patch
```

This way you are not polluting the remote with your temp commits or temporary branches.

## Test your work before you publish

Always test your work before you publish your work. If you want to do yourself a favour, also test before committing, because it will save you some time needed to edit/squash the commits where you fix your newly created bugs right away.

## Write sensible commit messages

There is literally nothing worse than a non-descriptive commit message when you need to inspect Git history. Imagine the following history:

```
...
* fd4befe 
|          [3 days ago]     Tomaz Lovrec: more work 
* 08a128a 
|          [3 days ago]     Tomaz Lovrec: fix 
* 84a43f1 
|          [3 days ago]     Tomaz Lovrec: work 
* d8de94b 
|          [3 days ago]     Tomaz Lovrec: fix 
...
```

And you are looking through the history trying to piece together when and where some change was made, to understand maybe why it was made. Now you have to open every commit and inspect all the changes in the commit. Painful work. And since all the commit messages are almost the same it is much harder to keep track of which you already inspected and remembering which does what.

This is why it is recommended to write commits in the following form:

```
short descriptive title, up to 60-80 chars

Longer description about what you did, why did you do it, what you were trying
to solve. Your goal here should be to explain the change enough that someone
inspecting your commit does not need to contact you. Although, do try and keep
it short, because no one has time to spend 5 minutes on each commits message.
And keep the lines shorter than 80 characters.
```

Furthermore the title should describe what you have done in the code, not the effect the change had. Instead of writing `fixed the wrong error response` write:

```
error response to ErrFoo in foo endpoint

The previous error message was false and did not properly describe the error to
the client. ErrFoo is a better alternative since it......
```

## Conclusion

Those are just some of the guidelines you should keep in mind when working with Git in order to maintain some sensibility in your Git history and transmit your changes more effectively to the rest of your team, and also maybe to just get your co-worker of your back "bugging" you all the time why you did something.

There are a lot more guidelines, but most important is, that you and your team agree on them and follow them, even if you deem some of them unnecessary or stupid.

Do you have any other guidelines you think I should have mentioned? Please feel free to add them to the comments bellow!