
Better Git configuration - scottnonnenberg
https://blog.scottnonnenberg.com/better-git-configuration/
======
scrollaway
I want to also recommend the following:

git config --global stash.showPatch true: A recent addition to git which
defaults the -p flag to `git stash show`; meaning `git stash show` shows the
diff from that stash (should really be default...)

git config --global rebase.autostash true: will automatically stash and
unstash the working directory before and after rebases. This makes it possible
to rebase with changes in the repo.

git config --global log.decorate full: Always decorate `git log`

~~~
masklinn
Other settings I appreciate:

    
    
        rebase.autoSquash true
    

When committing you can specify --squash=<commit> or --fixup=<commit>, `git
rebase -i --autosquash` will then automatically move and mark the relevant
commits in your rebase queue. Setting autosquash into your config enables it
by default for all interactive rebases.

    
    
        user.useConfigOnly true
    

that's really convenient when you routinely use multiple identities on the
same machine (e.g. personal and work): by default if you haven't configured an
identity locally git will fallback to global, and then to _guessing based on
your current user and machine_.

useConfigOnly mandates an explicit configuration, then you can just remove any
global user or email, and git will _require_ the correct configuration of any
local repository before allowing commits.

    
    
        alias.original "!git show $(cat .git/rebase-apply/original-commit)"
    

when performing a rebase (interactive or not) it can be difficult to remember
what the original intent of a specific commit is when it's mixed with conflict
markers. This shows the original commit being rebased.

    
    
        alias.git "!git"
    

I regularly type "git", go do something else, remember what I wanted to do and
type "git <command><return>". This makes "git git git git show" work instead
of barfing.

Finally

    
    
        merge.tool <yourtool>
    

Will automatically use the specified tool when invoking "git mergetool", if
you like external utilities to perform merges or conflict resolution (e.g.
emerge, kdiff3, araxis, vimdiff3, meld, etc… the list of builtin tool support
is accessible via "git mergetool --tool-help")

------
gsylvie
This has saved me:

    
    
        git config  --global pull.ff only
    

I can always override an individual pull invocation with either "git pull
--rebase" or "git pull --no-ff", making it a conscious choice when a fast-
forward pull is not possible.

~~~
ninkendo
Oh wow, this must be a recent feature, I remember looking for a way to
configure `--ff-only` by default a few years ago and it didn't seem possible.
I ended up making a git alias of `git puff` which calls pull with the `--ff-
only` flag.

~~~
gsylvie
Looks like it showed up with commit b814da891e, and has been around since Git
v2.0.0.

The online docs mention it in Git v2.1.0: [https://git-scm.com/docs/git-
config/2.1.0](https://git-scm.com/docs/git-config/2.1.0)

------
ymse
Oddly, the author recommends signing commits, yet uses only fast-forward
merges. Little do they know that signed commits necessarily can _not_ be
resolved as fast-forwards in a merge situation, since that would require
changing the signatures!

Rebasing is the answer, but that will of course re-sign every commit with your
key. In a shared repository, I prefer creating "useless" merge commits to
changing other peoples signatures.

~~~
rlpb
Perhaps I misunderstand you, but a fast forward merge isn't really a merge
(there is no merge commit) and by definition doesn't change any commits. So it
doesn’t require changing any commits, and therefore no signatures need
changing either.

Is there some other part of a workflow that you're inferring here that will
need changing commits?

~~~
growse
If you have a feature branch with multiple commits signed by multiple people,
does rebasing that not invalidate the signatures (changes the parent and thus
every hash)?

~~~
rlpb
I see. The rebasing you mention is part the implied workflow I was missing. I
see it now. Yes - if the rule is that merge commits to master are not
permitted (ie. all commits must be rebased onto master first), then of course
one person cannot rebase someone else's signed commits without losing those
signatures. Thanks.

Theoretically one could devise a tool which allows each contributor to re-sign
(in the correct order), but I'm not aware that any such thing exists, and it'd
probably be too impractical anyway.

------
dilap
Here's one: Use:

    
    
        git push --force-with-lease
    

Instead of

    
    
        git push -f
    

(Obviously ideally you'd never do either, but sometimes life happens.)

The advantage of the former over the latter is that it won't push if you
haven't already seen the ref you're overwriting. It avoids the race condition
of accidentally "push -f"ing over a commit you haven't seen.

(Why this isn't the default, I have no idea.)

~~~
scrollaway
Yes, force-with-lease is really useful. I set it up as an alias of git fpush,
and have never used push --force since.

------
aeontech
I really like diff-so-fancy [1] highlighter as a pager and to review diffs.
Previously discussed here on HN here: [2]

[1]: [https://github.com/so-fancy/diff-so-fancy](https://github.com/so-
fancy/diff-so-fancy)

[2]:
[https://news.ycombinator.com/item?id=11057421](https://news.ycombinator.com/item?id=11057421)

------
mi100hael
Some good tips in here. I also like to add the following alias to give me a
more condensed log with graph & tags:

    
    
        hist = log --pretty=format:\"%C(yellow)%h%C(reset) %C(green)%ad%C(reset) %C(red)|%C(reset) %s %C(bold blue)[%an]%C(reset)%C(yellow)%d%C(reset)\" --graph --date=short

~~~
pavel_lishin
I have a similar one:

    
    
        lg2 = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen%cn%Creset %Cblue(%cr)%Creset' --abbrev-commit --date=relative
    

Shows dates at the end, in a relative format (2 days ago, 29 hours ago, etc)
and the tags/branches before the commit message.

~~~
nichochar
So do I! lg = log --color --graph --pretty=format:'%Cred%h%Creset
-%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' \--abbrev-
commit

~~~
pavel_lishin
Date before author? Blasphemeeeeeeee†!

† [http://oglaf.com/assorted-fruits/](http://oglaf.com/assorted-fruits/) (sfw)

------
dilap
I will never understand why people hate merge commits. It's an accurate
history of what happened, and can be useful in tracking down bugs.

~~~
bluehawk
It's a trade off. In my opinion when using rebase you don't lose history or
make it inaccurate. A bug would still be introduced by the commit that made
it, so tracking down bugs with bisect or other tools works the same. The main
advantage is that your history is much cleaner.

------
chrisan
One thing I like to do is alter the coloring as an aide for `git status` which
is giving "changed" a yellow as an intermediary color

    
    
        [color "status"]
                added = green
                changed = yellow bold
                untracked = red bold

------
jph
Many git alias ideas:
[https://github.com/gitalias](https://github.com/gitalias)

Improvements and pull requests are welcome.

------
ereyes01
I'm a long time vim user and my brain is wired to reach for the keyboard
shortcuts in vimdiff to jump from diff to diff. Also, I really love diffing
entire trees in one vim session using the DirDiff plugin
([https://github.com/will133/vim-dirdiff](https://github.com/will133/vim-
dirdiff)).

Here's how I wire it into my .gitconfig, which gets me the alias "git
dirdiff":

    
    
      [difftool "default-difftool"]
        cmd = gvim -f '+next' '+execute \"DirDiff\" argv(0) argv(1)' $LOCAL $REMOTE
    
      [difftool]
        prompt = false
    
      [alias]
        difftool --dir-diff
    

... I like to use gvim to open new windows separate from my terminal, but if
you prefer you can just use plain vim in there as well.

Also, if using vim for viewing diffs, you might want to hack vim's config as
well to make it look good. I like to (effectively) disable folding of lines
with no diffs so I can still read the whole file- I use the shortcuts ]c (next
diff) and [c (previous diff) to jump around diffs. I also like to disable
editing in diff mode.

Here's my diff-related .vimrc hackage:

    
    
      if &diff
      	set lines=60 columns=184
      	set foldminlines=99999
      	set nomodifiable
      	set nowrite
      endif

~~~
jwilk
The last section should be:

    
    
      [alias]
        dirdiff = difftool --dir-diff

~~~
ereyes01
Copy/paste fail... Thanks for catching

------
gitaarik
I have a dedicated Git tmux tab for every repo I'm working on, in that tab I
use a git shell. Initiated by this bash function:

    
    
        # A nice shell prompt for inside git repostories
        # Shows a short status of the repository in the prompt
        # Adds an alias `g=git` and makes autocomplete work
        gitprompt() {
    
            __color_bold_blue='\[$(tput bold)\]\[$(tput setaf 4)\]'
            __color_white='\[$(tput sgr0)\]'
    
            export GIT_PS1_SHOWDIRTYSTATE=true;
            export GIT_PS1_SHOWSTASHSTATE=true;
            export GIT_PS1_SHOWUNTRACKEDFILES=true;
            export GIT_PS1_SHOWUPSTREAM="auto";
            export GIT_PS1_SHOWCOLORHINTS=true;
            . /usr/lib/git-core/git-sh-prompt;
    
            local ps1_start="$__color_bold_blue\w"
            local ps1_end="$__color_bold_blue \\$ $__color_white"
            local git_string=" (%s$__color_bold_blue)"
    
            export PROMPT_COMMAND="__git_ps1 \"$ps1_start\" \"$ps1_end\" \"$git_string\""
    
            # Short alias for git stuff
            alias g=git
    
            # Make autocomplete also work fo the `g` alias
            eval $(complete -p git | sed 's/git$/g/g')
    
        }
    

So I have this in my `.bashrc` and when I want my bash to get a handy Git
prompt I type `gitprompt`.

You do need the file `git-sh-prompt` which should come with git, for me it's
located in `/usr/lib/git-core/git-sh-prompt`. It's also available here:

[https://github.com/git/git/blob/master/contrib/completion/gi...](https://github.com/git/git/blob/master/contrib/completion/git-
prompt.sh)

------
hiphipjorge
I'm going through my gitconfig and I'm realizing there's ALL THESE really nice
shortcut I literally never use.

~~~
Cthulhu_
Same, it's hard to break one's finger memory when you're used to e.g. typing
`--force --no-verify` in full all the time. Although imo those should always
be typed out in full.

------
AlexCoventry
Seems like most of these enhancements have matching features in emacs's magit,
which also offers many others.

Which is not to dismiss these: Using magit involves its own cognitive load.

------
r0muald
> I will never accidentally create a merge commit

What is the big deal about creating a merge commit? It that because you only
merge in `origin` (wherever that lives)?

~~~
mikekchar
This really depends on your style of using git. If you are rebasing (or
otherwise changing history), merge commits can come back to bite you. You've
got to make sure that you are dealing with the correct side of the branch. One
side will have the history you need, while the other side may not. This can
lead to serious weirdness like git reverting changes without telling you.

If you are not changing history, then merge commit cause no harm at all.
You've got to be a bit careful about reverts and again choosing the correct
side of the history, though.

IMHO, the rebasing style is great when you are working with a group that
understands how git is working under the hood. As long as they don't do
anything to break stuff, then it's very nice. If you are working with a team
which a bit more laissez fair, then merge commits are generally safer -- just
make sure to tell then _never_ to change history (rebase, force push, etc).

If you mix the two, you will be spending the odd afternoon piecing your git
repository's history together by hand. It is seriously not fun.

------
mikegerwitz
This references my Git Horror Story article from 2012. Which is fine, but note
that git has evolved a lot since then, and you should also seek out some of
its more modern conveniences (this thread's article mentions a number of
them). I've been telling myself I'll update this article for the past few
years. I'll get to it eventually.

As an alternative to git's aliases: if you're sick of typing `git' all the
time, feel free to adapt this little script to suit your needs (allowing you
to type e.g. `a' instead of `git add' and such, with tab completion):

    
    
      https://gitlab.com/mikegerwitz/git-shortmaps

------
teekert
I'm a git noob. I realy mis an option to simply backup my current work
situation to Git and work further on it on another machine, or simply later
with the knowledge that everything is safe on the server. Currently I have a
big list of commits called "Backup" which I always push immediately. It's
ugly. Is there a way to save to the git server your current situation with
bothering others working on the project with your commits?

Maybe this is simply not what Git is made for and I should use Git from my
NextCloud folder to have my data safe on a server?

~~~
markild
Sounds like you want to work on a separate branch. Also sounds like you'd want
to rebase onto the correct branch when done, so that you can reorganize
commits

~~~
teekert
I do work on my own branches indeed. But something like "git sync" would be
nice, no commits, no mess for your collaborators or in your Git history, just
my current work, safe on the server, to be synced elsewhere without formally
committing anything so that commits can be real improvements that require a
commit message. Git sync would be the equivalent of hitting ctrl-S working on
a doc in a Dropbox folder. You hit ctrl-S, boom it's safe on the server. I'd
setup git sync to sync regularly and allow you to go back in time, or if you
want, completely back to the last formal commit.

Git feels so local and thus vulnerable to theft, breakage, power outages etc.

~~~
sangnoir
> I do work on my own branches indeed. But something like "git sync" would be
> nice, no commits, no mess for your collaborators or in your Git history,
> just my current work, safe on the server, to be synced elsewhere without
> formally committing anything so that commits can be real improvements that
> require a commit message.

You seem to be hung-up on commits or have an inexplicable aversion (IMO) to
committing to a private, expendable branch. Git made branching cheap and easy
by design - you can go crazy on your private 'backup' branches without having
to add detailed commit messages. When you are happy, you can rebase or squash
merge into the 'real' branch with proper commit messages and delete the backup
branch. This will not create a mess for collaborators or your Git history
(after you've deleted the ephemeral branches).

As a matter of fact, you could create an alias for 'git sync' that does the
above in the background, if you find the individual steps too tedious to
manually type in.

------
llimllib
Don't set fsckobjects=true. There are normal repositories that have broken
trees which will not download if you have it set. Yes it is irritating and I
would rather turn it on, but I had to turn it off after several repos failed
for me.

Git doesn't check validity of commit hashes by default:
[https://groups.google.com/forum/#!topic/binary-
transparency/...](https://groups.google.com/forum/#!topic/binary-
transparency/f-BI4o8HZW0)

~~~
scottnonnenberg
Wouldn't it make sense to turn that off per-project when you encounter it?

~~~
llimllib
That wasn't a hassle I was willing to deal with, I guess at least know that
you're going to be doing that if you enable it.

IIRC, the jquery repo was an example of one with a bad object hash.

------
astrostl
When I want/need to customize this much, I tend to think poorly of the tool.

~~~
Ajedi32
I'm guessing you don't like Vim or EMACS then? Or the command line in general?

Most of the development tools I use on a regular basis tend to be extremely
customizable, and I regard that as a Good Thing.

~~~
nulagrithom
To each their own. Sure my coworkers complain about this or that annoyance in
WebStorm or whatever that they can't customize or fix, but then they never
lost the better half of a day to ~/.vimrc so...

I can see it both ways. I'll choose customization, but I wouldn't fault
someone for expecting a good out-of-box setup.

------
partycoder
There are some good tips there, like using GPG. I am definitively going to get
that set up for my project.

Now, I always merge with no fast-forward because it creates a commit for the
merge that you can revert.

    
    
        git merge --no-ff
    

Then, I always pull with rebase... That will apply your changes on top of the
remote ones. It may lead to conflicts but it leads to a log with less
branches.

    
    
        git pull --rebase
    

The merge/diff tool I use is p4diff, which comes with P4V (Perforce visual
client) and is free.

To explore the git log, I use tig.
[https://github.com/jonas/tig](https://github.com/jonas/tig)

It is a curses interface to git. Screenshot:
[https://atlassianblog.wpengine.com/wp-
content/uploads/tig-2....](https://atlassianblog.wpengine.com/wp-
content/uploads/tig-2.png)

~~~
pstadler
Shameless plug. I published a little guide some months ago, on how to use GPG
with keybase.io to sign commits.

Link: [https://github.com/pstadler/keybase-gpg-
github](https://github.com/pstadler/keybase-gpg-github)

Discussion on HN:
[https://news.ycombinator.com/item?id=12289481](https://news.ycombinator.com/item?id=12289481)

------
floatboth
I have a ridiculous "vim style" alias setup:
[https://github.com/myfreeweb/dotfiles/blob/4eb052cc54f9edcc8...](https://github.com/myfreeweb/dotfiles/blob/4eb052cc54f9edcc870932494c2c30f90a220970/dev-
base/gitconfig#L64)

So I can just e.g. type "g ws" to tell [g]it to give me the [w]orking tree
[s]tatus. Seeing people actually type "git status" is just painful.

~~~
mrkgnao
That's impressive. Together with (neo)vim as $GIT_EDITOR I can see that being
really nice to use.

Now you _could_ decide to systematize the "grammar" of your shortcuts somehow,
and, well... it's definitely an idea people have had before. ;)

[https://magit.vc/screenshots/popup-
diff.png](https://magit.vc/screenshots/popup-diff.png)

Not an Emacs fanboy, by any means: I use Spacemacs. Magit is objectively
excellent, though.

------
hyperpallium
How can I make git diff default to --color-words, instead of:

    
    
      [alias]
        wdiff = "diff --color-words"

~~~
dotancohen
That would most likely be:

    
    
      $ git config color.diff always

------
turboladen
oh-my-zsh has some great git aliases too (scroll down 1/3 of the page):
[https://github.com/robbyrussell/oh-my-
zsh/wiki/Cheatsheet](https://github.com/robbyrussell/oh-my-
zsh/wiki/Cheatsheet)

------
rajathagasthya
Nice post. I didn't know about the followTags = true until now and I'm using
it in my .gitconfig.

------
papag
Nice to hear from a fellow mustang!

