Git like a pro

Git like a pro will present some more advanced git tricks, you might not have heard about. This is going to be a collection of deluxe git stuff I have picked up somewhere or written myself. It is also going to be a repeating section, so stay tuned and look for other posts on git like a pro.

Article series
Git like a pro

  1. Git like a pro
  2. Sort git tags by date
  3. Rewrite author history

1. Extended Status

Normally git status just shows the current state of a git repository. It looks like this:

[275] cytopia at MD51001627 in ~/repo/mysqldump-secure/nagios (☿ check_mysqldump-secure ꒛ master ⇡2)
 git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
  (use "git push" to publish your local commits)
nothing to commit, working directory clean
[0]

Additionally it is also possible to show the state of each submodules.

[276] cytopia at MD51001627 in ~/repo/mysqldump-secure (☿ mysqldump-secure ꒛ master+)
 git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

        modified:   nagios (new commits)

Submodules changed but not updated:

* nagios 644d5c0...e0dbf3a (2):
  > removed empty space

no changes added to commit (use "git add" and/or "git commit -a")
[0]

This can easily be accomplished by appending the following to the /path/to/repository/.git/config file inside of your repository.

[status]
    submodulesummary = 1

2. Ignored Files

If you want to list all the files that are currently being ignored by .gitignore, you can try the following.

git ls-files -o -i --exclude-standard

This is not too handy. So you better create an alias in ~/.gitconfig:

[alias]
    ign = ls-files -o -i --exclude-standard

Now you can simply issue the git alias to list all ignored files.

[277] cytopia at MD51001627 in ~/repo/mysqldump-secure (☿ mysqldump-secure ꒛ master+)
 git ign
.DS_Store
[0]

3. Tags

You will obviously know that you can list all tags via git tag. Unfortunately they are being displayed alphabetically and not sorted by creation date.
So you can do something like this.

[278] cytopia at MD51001627 in ~/repo/mysqldump-secure (☿ mysqldump-secure ꒛ master+)
 git for-each-ref --sort=taggerdate --format '%(tag)%09%(taggerdate:raw)%09%(*authorname)' refs/tags | awk '{print $1"\t\t"strftime("%F  %H:%M", $2)"\t"$4" "$5}'
0.1             2015-06-19  18:37       Cytopia
0.2             2015-06-20  18:41       Cytopia
0.3             2015-06-24  19:57       Cytopia
0.4             2015-06-28  13:11       Cytopia
[0]

As this command is pretty hard to remember, you better create a git alias for it in ~/.gitconfig

[alias]
   tags = "!git for-each-ref --sort=taggerdate --format '%(tag)%09%(taggerdate:raw)%09%(*authorname)%09%(*subject)' refs/tags | awk '{print $1\"\t\t\"strftime(\"%F  %H:%M\", $2)\"\t\"$4\" \"$5\"  \t\t\"$6\" \"$7\" \"$8\" \"$9\" \"$10}'"

Now you can simply use it like this:

[279] cytopia at MD51001627 in ~/repo/mysqldump-secure (☿ mysqldump-secure ꒛ master+)
 git tags
0.1             2015-06-19  18:37       Cytopia
0.2             2015-06-20  18:41       Cytopia
0.3             2015-06-24  19:57       Cytopia
0.4             2015-06-28  13:11       Cytopia
[0]

This however only works with annotated tags.

4. Uncommit

Did you ever had the case where you really needed to uncommit (locally)? Here is how it goes:

[280] cytopia at MD51001627 in ~/repo/lib.sh (☿ lib.sh ꒛ master ⇡4)
 git status
On branch master
Your branch is ahead of 'origin/master' by 4 commits.
  (use "git push" to publish your local commits)
nothing to commit, working directory clean
[0]
[281] cytopia at MD51001627 in ~/repo/lib.sh (☿ lib.sh ꒛ master ⇡4)
 git uncommit
Unstaged changes after reset:
M       README.md
D       ask.sh
D       filesystem.sh
D       math.sh
[0]
[282] cytopia at MD51001627 in ~/repo/lib.sh (☿ lib.sh ꒛ master ⇡4)
 git status
On branch master
Your branch is ahead of 'origin/master' by 3 commits.
  (use "git push" to publish your local commits)
Changes not staged for commit:
  (use "git add/rm ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

        modified:   README.md
        deleted:    ask.sh
        deleted:    filesystem.sh
        deleted:    math.sh

Untracked files:
  (use "git add ..." to include in what will be committed)

        functions/
        lib/

no changes added to commit (use "git add" and/or "git commit -a")
[0]

So how is uncommit done? git uncommit simply is an alias for git reset HEAD~1 --mixed

[status]
    uncommit = reset HEAD~1 --mixed

5. GPG Signature

If you check git log no gpg information is displayed at all.

[283] cytopia at MD51001627 in ~/repo/mysqldump-secure (☿ mysqldump-secure ꒛ master+)
 git log
[0]

commit fc6ba54b75a84f7c1e027d5dda1518493d4c1b5b
Author: Cytopia <cytopia@everythingcli.org>
Date:   Sun Jun 28 13:11:00 2015 +0200

    Nagios Plugin Release v0.3

commit 7e8aec474f20581023d6d2e2d4d91bcf742ba8a2
Author: Cytopia <cytopia@everythingcli.org>
Date:   Sun Jun 28 12:37:24 2015 +0200

    new nagios plugin version

commit 5f743cdd1e4524322d7a3ad8ddb6447674623600
Author: Cytopia <cytopia@everythingcli.org>
Date:   Sun Jun 28 12:36:07 2015 +0200

    Removed Version and altered Changelog

Now those three commits could have come from anybody, with name and email set as above in the ~/.gitconfig.
If only gpg-signed commits/merges/tags are allowed, you can always validate each commit via git log.

[284] cytopia at MD51001627 in ~/repo/mysqldump-secure (☿ mysqldump-secure ꒛ master+)
 git log --show-signature
[0]

commit fc6ba54b75a84f7c1e027d5dda1518493d4c1b5b
gpg: Signature made Sun Jun 28 13:11:00 2015 CEST using RSA key ID 28BF179F
gpg: Good signature from "Cytopia <cytopia@everythingcli.org>"
Author: Cytopia <cytopia@everythingcli.org>
Date:   Sun Jun 28 13:11:00 2015 +0200

    Nagios Plugin Release v0.3

commit 7e8aec474f20581023d6d2e2d4d91bcf742ba8a2
gpg: Signature made Sun Jun 28 12:37:24 2015 CEST using RSA key ID 28BF179F
gpg: Good signature from "Cytopia <cytopia@everythingcli.org>"
Author: Cytopia <cytopia@everythingcli.org>
Date:   Sun Jun 28 12:37:24 2015 +0200

    new nagios plugin version

commit 5f743cdd1e4524322d7a3ad8ddb6447674623600
gpg: Signature made Sun Jun 28 12:36:07 2015 CEST using RSA key ID 28BF179F
gpg: Good signature from "Cytopia <cytopia@everythingcli.org>"
Author: Cytopia <cytopia@everythingcli.org>
Date:   Sun Jun 28 12:36:07 2015 +0200

    Removed Version and altered Changelog

To simplify the command, you can also create a git alias.

[alias]
    gpg = log --show-signature

6. Gitconfig

In case you are curious, here is an extract of my ~/.gitconfig:

[user]
    name = Cytopia
    email = cytopia@everythingcli.org
    signingkey = 28BF179F


[core]
    # Check if converting CRLF is reversible
    # and abort if not
    safecrlf = true

    # Better git diff view
    pager = less -x1,5

    # whitespace fix
    #
    # trailing-space: treats trailing whitespaces at the end of the line
    # space-before-tab: treats a space character that appears immediately before a tab character in the initial indent part of the line as an error
    whitespace = blank-at-eol,blank-at-eof,space-before-tab,trailing-space

    ignorecase = false

[apply]

    # Warn about whitespace issues defined in core.whitespace
    whitespace = warn

[merge]
    summary = true

    # No fast forward merge
    # I want to see the merge tree instead
    # of a flat merge
    ff = false

[alias]

    ################################################################################
    # Action Commands

    # Uncommit previous 'git commit'
    #
    # Files are still there and you will have
    # to stage them again.
    #
    # This is useful, if you are back to work the
    # next day and want to uncommit yesterday's commit
    # in order to see what you have done
    uncommit = reset HEAD~1 --mixed

    # This commits everything in my working directory
    # and then does a hard reset to remove that commit
    #
    # The nice thing is, the commit is still there, but it's just unreachable.
    # Unreachable commits are a bit inconvenient to restore,
    # but at least they are still there.
    # You can run the git reflog command and find the SHA
    # of the commit if you realize later that you made
    # a mistake with the reset. The commit message will be "WIPE SAVEPOINT" in this case.
    wipe = !git add -A &amp;&amp; git commit -qm 'WIPE SAVEPOINT' &amp;&amp; git reset HEAD~1 --hard

    ################################################################################
    # View git log

    # git log
    tree = log --graph --decorate --abbrev-commit --branches --tags --remotes --date=short --pretty=format:'%C(yellow)%h%Creset-%C(cyan)(%ai%x08%x08%x08%x08%x08%x08) %ar%Creset%C(bold green)%d%Creset %s %Creset %C(cyan)[%cn]%Creset'
    lg = log --stat --abbrev-commit --show-signature
    gpg = log --show-signature

    ################################################################################
    # View Hash

    # Show current tag, if available
    current = !sh -c 'git name-rev --tags --name-only $(git rev-parse HEAD)'

    # List all git tags ordered by date
    tags = "!git for-each-ref --sort=taggerdate --format '%(tag)%09%(taggerdate:raw)%09%(*authorname)%09%(*subject)' refs/tags | awk '{print $1\"\t\t\"strftime(\"%F %H:%M\", $2)\"\t\"$4\" \"$5\" \t\t\"$6\" \"$7\" \"$8\" \"$9\" \"$10}'"

    ################################################################################
    # View files

    # List files (indexed)
    ls = ls-tree --name-only -r HEAD

    # List files (ignored)
    ign = ls-files -o -i --exclude-standard
    ls-ign = ls-files -o -i --exclude-standard
    ls-ignored = ls-files -o -i --exclude-standard

    # List files (modified)
    ls-mod = ls-files -m
    ls-modified = ls-files -m

    # List files (deleted)
    ls-del = ls-files -d
    ls-deleted = ls-files -d

    # List files (unmerged)
    ls-unm = ls-files -u
    ls-unmerged = ls-files -u

[color]
    ui = true
    [color "branch"]
    current = yellow bold
    local = green bold
    remote = cyan bold
[color "diff"]
    meta = yellow bold
    frag = magenta bold
    old = red bold
    new = green bold
    whitespace = red reverse
[color "status"]
    added = green bold
    changed = yellow bold
    untracked = red bold

Leave a Reply

Your email address will not be published.