Git - Tips
28 Apr 2017- (how to) undo
git reset HEAD~
orgit --commit amend
- (how to) fork a fork and sync it with original repo
- (how to) remove file from Git
- (how to) sign GitHub commits
- (how to) use common configs in Git repo
- (how to) show
git diff
output in pager - don’t use git-up gem
- (how to) merge master into develop
(how to) undo git reset HEAD~
or git --commit amend
- http://stackoverflow.com/questions/2510276/undoing-git-reset
- https://stackoverflow.com/a/1459264/3632318
$ git reset 'HEAD@{1}'
or
$ git reset ORIG_HEAD
when git commit --amend
is undone, hash of the last commit is
restored to its original value -> changes can be safely pushed
to remote repo without --force
option.
(how to) fork a fork and sync it with original repo
- https://help.github.com/articles/syncing-a-fork/
- https://github.com/Esri/developer-support/wiki/Setting-the-upstream-for-a-fork
$ git clone <MY_FORK_REPO>
$ git remote -v
$ git remote add upstream <UPSTREAM_REPO>
$ git fetch upstream
$ git merge upstream/master
$ git mergetool
(how to) remove file from Git
$ git rm --cached config/database.yml
(how to) sign GitHub commits
glossary
- keypair consists of a private signing key and a public verification key
- fingerprint is SHA-1 hash of the public key
- GPG key ID is a part of the fingerprint:
- short key ID are the low 64 bits of the fingerprint
- long key ID are the low 128 bits of the fingerprint
for example:
$ gpg --list-keys --keyid-format LONG
/Users/tap/.gnupg/pubring.gpg
-----------------------------
pub rsa4096/ACFDF508F789A2CB 2017-10-17 [SC]
D9CA996601640B2121F29312ACFDF508F789A2CB
...
ACFDF508F789A2CB
is a long GPG key IDD9CA996601640B2121F29312ACFDF508F789A2CB
is a fingerprint
official guides
- https://help.github.com/articles/generating-a-new-gpg-key/
- https://help.github.com/articles/associating-an-email-with-your-gpg-key/
- https://help.github.com/articles/signing-commits-using-gpg/
use gpg --full-generate-key
command to generate keypair - not gpg --gen-key
command: the latter uses default key size of 2048 bits which can’t be changed.
$ZDOTDIR/.zshenv
- add
-S
flag togit commit
command in all aliases -
export
GPG_TTY
environment variablethis environment variable must be required for
gpg-agent
to work properly:https://www.gnupg.org/documentation/manuals/gnupg/Invoking-GPG_002dAGENT.html
It is important that this environment variable (GPG_TTY) always reflects the output of the tty command.
# $ZDOTDIR/.zshenv export GPG_TTY=$(tty)
Git will fail to sign commits if
GPG_TTY
is not set:$ git commit -S -m 'foo' error: gpg failed to sign the data fatal: failed to write commit object
$ZDOTDIR/.zshrc
https://www.gnupg.org/documentation/manuals/gnupg/Invoking-GPG_002dAGENT.html
gpg-agent is a daemon to manage secret (private) keys independently from any protocol.
The agent is automatically started on demand by gpg, gpgsm, gpgconf, or gpg-connect-agent. Thus there is no reason to start it manually.
=> it’s not necessary to start gpg-agent
manually (either via gpg-agent
command or corresponding plugin provided by your plugin manager for Zsh).
~/.gnupg/gpg.conf
-
use-agent
optionI thought it was the absence of this option that caused
git commit
command to hang before asking for the passphrase but in fact that hang was caused by trying to make commits from inside MacVim:- I run
:!publish
command in MacVim pinentry
prompts for the passphrase- MacVim doesn’t allow to enter the passphrase since all commands run in a non-interactive shell by default
- I cancel command with
<C-c>
pinentry
still waits for the passphrase in the background (correspoding process having a very high CPU usage)- I cannot make a commit from the command line because
pinentry
is still busy waiting for the passphrase
TL;DR:
use-agent
option can be safely removed from gpg.conf. - I run
-
passphrase-file
andpinentry-mode
optionsuse these options to read passphrase from file instead of typing it manually - it’s especially useful when running
git commit
command in a non-interactive shell (say, from inside MacVim):# ~/.gnupg/gpg.conf passphrase-file /Users/tap/.gnupg/passphrase pinentry-mode loopback
don’t use tilde in passphrase file path - or else:
$ git commit -S -m "foo" error: gpg failed to sign the data fatal: failed to write commit object
if
pinentry-mode loopback
option is missing passphrase won’t be read from file at all - you’ll have to enter it manually then (even though passphrase file is specified). -
batch
optionthis option is supposed to be used along with
passphrase-file
option but it all works as is so the former can be omitted.
~/.gitconfig
-
set commit email (required)
$ git config --global user.email GITHUB_VERIFIED_EMAIL
if Git email doesn’t match GitHub email, commit will have
Unverified
badge on GitHub. -
set signing key (optional)
$ git config --global user.signingkey GPG_KEY_ID
I guess, setting signing key explicitly might be required if you have more than one signing key.
(how to) use common configs in Git repo
just use hardlinks instead of symlinks - they are commited to Git repo like ordinary files.
UPDATE
still it’s not possible: at some point (most likely, when hardlinked file is changed in upstream) hardlink and original file no longer share the same inode so fetched changes are not reflected in original file.
(how to) show git diff
output in pager
; ~/.gitconfig
[core]
; ...
+ pager = less -+X -+F
don’t use git-up gem
https://github.com/aanand/git-up#warning
This project is no longer maintained, for several reasons:
- As of Git 2.9, git pull –rebase –autostash does basically the same thing.
=> add Git alias instead:
-
in Git config directly
# ~/.gitconfig [alias] + # https://github.com/aanand/git-up + up = pull --rebase --autostash
-
or using
git config
command$ git config --global alias.up 'pull --rebase --autostash'
set upstream
see the linked post for details on how and why it’s necessary to set upstream
for your branch - git-up
gem would handle it for us before but now we should
do it by ourselves.
(how to) merge master into develop
$ git checkout develop
$ git merge master
$ git mergetool
$ git commit -m "merge master"
$ git push
NOTE: it’s important to create and push commit even if there are no changes
when all conflicts are resolved (git status
displays a message that
working tree is clean).