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
.
- Git like a pro
- Sort git tags by date
- 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 && git commit -qm 'WIPE SAVEPOINT' && 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