Using Git / Git Cheatsheet

07 May 2019 - tsp
Last update 27 Feb 2022
Reading time 22 mins

Note that at the end there is a short step by step guide on how to apply version control to your first short projects. Please note that - to use all features of git - you should use plain text source files, not MS Word or similar binary content. Although git can of course also manage binary files you loose the ability of viewing differences, merging changes, etc. You keep the ability to revert and look at previous versions with checkout of course.

The TL;DR:

Putting an existing project under version control

Removing an remote

If one wants to remove an remote to unlink a repository from their upstream or change an invalid reference on can

git remote remove origin

To list all remotes one can use

git remote -v

Signing and verifying git commits using GPG

Since git is an distributed version cotrol system the basic assumption is that no remote repository is authorative (even if used so) and that no remote repository is trusted. Commits of people can (and should) be signed with GPG - the certificates should certify authenticity of the set user.email. One can then verify if the commits have really been made by the authors that claim to have done the changes (see displaying history) as well as they can be checked during a pull to only download changes that have a valid signature attached (see creating a trusted keyring only for GIT when one just wants to trust a small subset of people to make modifications to a repository)

Creating new GPG key, using for signing commits on git(hub)

Signing commits

Basically you just have to supply the -S switch during commit.

git commit -S

or

git commit -S -m

Creating a trusted keyring only for GIT

If one extensivly uses gpg one should use a private keyring of trusted keys that are trusted for commits on the git repositories - if one would use the default keyring every known key with a valid signature (including those used for mail, etc.) would be trusted for signing git commits.

The idea is to create an own keyring just for git (or specific git repositories). To do that simply export the authorized keys to a keyring:

gpg --export KEYSPECIFIER | gpg --no-default-keyring --keyring=~/git.pgp --import -

To list the keys inside an keyring use

gpg --no-default-keyring --keyring=~/git.pgp --list-keys

Note that signatures with keys from your main keyring will not be validated if they are not included inside the git keyring. One has to build a full local web of trust or trust the local keys.

To interactively change the trustlevel one can use

gpg --no-default-keyring --keyring=~/git.pgp --edit-key KEYSPECIFIER

To change the trust level one can use the trust command inside this shell.

sec  rsa4096/06572BE1C0A8062D
     created: 2018-10-03  expires: 2026-10-01  usage: SC  
     trust: unknown       validity: ultimate
ssb  rsa4096/08D2E9AC73B82E95
     created: 2018-10-03  expires: 2026-10-01  usage: E   
[ultimate] (1). tspspi <11219971+tspspi@users.noreply.github.com>

gpg> trust
sec  rsa4096/06572BE1C0A8062D
     created: 2018-10-03  expires: 2026-10-01  usage: SC  
     trust: unknown       validity: ultimate
ssb  rsa4096/08D2E9AC73B82E95
     created: 2018-10-03  expires: 2026-10-01  usage: E   
[ultimate] (1). tspspi <11219971+tspspi@users.noreply.github.com>

Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)

  1 = I don't know or won't say
  2 = I do NOT trust
  3 = I trust marginally
  4 = I trust fully
  5 = I trust ultimately
  m = back to the main menu

Your decision? 5

Of course you should only trust ultimately your own keys. Other keys should maximally be trusted fully - if you trust that this person is really who they are and that they are only signing valid keys themselves.

Leve the shell with

gpg> quit

To use the trusted keyring with git one has to provide a wrapper around the gpg binary for github. This is easily achieved by using a shellscript (called /usr/local/bin/gitgpg.sh in this example) and specifying this script in the gpg.program option of git.

The shellscript is pretty simple:

#!/bin/sh
exec /usr/local/bin/gpg --no-default-keyring --keyring=~/git.pgp "$@"

Do not forget to set execute permissions and protect the script against modifications

chmod 555 /usr/local/bin/gitgpg.sh

Now one can either globally (for all repositories) or locally (for a specific repository) configure git to use gitgpg.sh

git config --global gpg.program /usr/local/bin/gitgpg.sh

or

git config gpg.program /usr/local/bin/gitgpg.sh

Now one can verify signatures on upload by using

git pull --verify-signatures

Changing local trust level for a given key

First get the key ID from the local key store

gpg --list-keys --keyid-format LONG

If - for example - the output looks like this:

pub   4096R/06572BE1C0A8062D 2018-10-03 [verfällt: 2026-10-01]
uid               [ uneing.] tspspi <11219971+tspspi@users.noreply.github.com>
sub   4096R/08D2E9AC73B82E95 2018-10-03 [verfällt: 2026-10-01]

you can now use gpg –edit-key to set the trust level:

gpg --edit-key 06572BE1C0A8062D

after entering the interactive GPG shell you can now use

trust

and set the trust level.

Uploading a public key to a keyserver

First determine the key ID by using –list-keys, then upload it via the –send-keys option to the keyservers. It’s a good idea to use the sks-keyservers pool. Note that it takes a while for the keys to propagate to all keyservers on the pool - so don’t be impatient if you cannot import them on other machines immediately

gpg --list-keys
gpg --keyserver pool.sks-keyservers.net --send-keys C0A8062D

Signing keys for the web of trust

If you want to certify the authenticity of another key, first download it from the keyserver (for example by key id):

gpg --keyserver pool.sks-keyservers.net --recv C0A8062D

Then the other person should tell you the fingerprint of their key on their machine.

gpg --finger C0A8062D

Compare the fingerprint you are reading with the fingerprint the owner of the key tells you (do this carefully) during the following step and verify the identity of the owner of the key (using official documents, etc.). To start the signature process you can use one of the following commands. The second one is required to sign if you have multiple private keys with which you want to sign (read the comment about trust levels below before sigining!)

gpg --sign-key <keytosign>
gpg --default-key <yoursigningkeyID> --sign-key <keytosign>

You can sign with various certification levels. There are:

Normally gpg uses certification level 2. If you want to certify with another level you can add the –ask-cert-level option:

gpg --ask-cert-level 3 --sign-key <keytosign>
gpg --ask-cert-level 3 --default-key <yoursigningkeyID> --sign-key <keytosign>

Take signing keys seriously. The people who assign your keys trust depend on your certifications to be valid. Also keep in mind that it’s valid for third parties who you trust - the web of trust helps to identify people to verify the identity of people they don’t know directly but only over one or more hops.

Displaying history

To display the history (in your local repository) use

git log --show-signature

If you don’t care about GPG signatures of commits you can leave the --show-signature option. Verification of GPG signatures requires you to have the public keys of the authors - you can download a key with a given key ID if it has been uploaded to a keyserver by

gpg --keyserver pool.sks-keyservers.net --recv C0A8062D

How to get git(hub) to work with SSH keys

After installing PuTTY and git:

  1. Create a new SSH key with puttygen (use ED25519 format) and store private and public key somewhere on your machine.
  2. Upload the “Public key for pasting into OpenSSH authorized_keys file” into your github Settings (add new SSH key)
  3. Modify the users environment to include GIT_SSH pointing to your plink.exe.
  4. Tell the git client who you are (this can also be set on a per repository basis, just don’t use –global)
    • git config –global user.name “exampleusername”
    • git config –global user.email “example@example.com”
  5. Load your private key into pageant (the PuTTY authentication agent). As long as the keys are loaded into pageant SSH applications are capable of authenticating with that key. As you don’t require the keys any more remove them from the agent.
  6. Testing SSH connection. This can be done using plink:
    plink git@github.com
    

    If you see any error messages there is a problem with your local installation, if github greets you with your username everything is setup correctly

Cloning an project (Fetching it for the first time from a remote repository)

Simply run

git clone git@github.com:USERNAME/reponame.git

to clone via git over SSH or

git clone https://github.com/USERNAME/reponame.git

to clone via HTTPS. When using github the URIs can be retrieved from the respositories webpage - upper right corner “clone or download”.

One can additionaly specify the target directory. If one wants to clone into the currently empty directory one could use:

git clone git@github.com:USERNAME/reponame.git .
git clone https://github.com/USERNAME/reponame.git .

Staging local changes

Everytime a local change should be added to a commit into the local repository one has to stage the change. To stage one uses

git add FILENAME

to add the changed files. One can of course also add a whole directory

Commiting staged changes to local repository

To comit locally staged changes to the local repository one can use

git commit
git commit -S
git commit -m "Message"
git commit -S -m "Message"

The -S flag can be used to sign the commit with an GPG key (see above), -m allows to specify the commit logmessage on the command line. If not specified the git client will open the configured editor and present an default commit message that should be changed

Empty commits

Sometimes one is required to do empty commits. One situation where this might get useful are automated deployment systems that only run when being able to verify commit signatures from a certain subset of people or with specific keys. In this case it might be necessary to just push a signed head commit to sign previous commits - I know of at least two web projects that use this to sign off changes made by previous authors and that then automatically trigger a static website generator to build and deploy their websites. The same might be interesting when one does versioning for system configurations and there have to be two or more independent signatures for a given set of configuration to take effect by the automatic deployment systems.

Long story short - one can create an empty commit using the --allow-empty flag to create an commit object that does not contain any changes. Depending on how one wants to write the message or how one handles signing one of the following commands might be useful:

git commit --allow-empty
git commit --allow-empty -S
git commit --allow-empty -m "Message"
git commit --allow-empty -S -m "Message"

Pushing local commits to an remote repository

git push
git push origin master

Modifying author or email address on an previous commit

If you’ve commited with an invalid author name or your private mail address even when using githubs mail protection feature you might discover that error not until you try to push the changes to the remote repository. In this case you can re-write history (beware that this is nearly always a bad thing - do this only if you change the last locally non pushed commit):

git commit --amend --author="Example User <example@example.com>"

Showing configuration options

To show all configuration options that have been configured (for example via git config)

git config --list

Step by step - how to apply to your own small personal project

If you want to use git just for your own personal project (to see what has changed, have an offsite backup on github, being capable of reverting changes and optionally using branches the following section lists the required steps after installing git.

Without branching (just a linear chain of changes).

In case you are working on another machine you can clone the remote repository on the first time

git clone git@github.com:USERNAME/reponame.git

Before resuming work and modifying content it’s a good idea to always pull the most recent version from the remote:

git pull

If you have any conflicting changes git shows you the conflicts during the pull and also with

git status

In case of conflicts just edit the conflicting files and search for a section looking like

<<<<<<< TARGETBRANCHNAME
Theirs
=======
Yours
>>>>>>> SOURCEBRANCHNAME

Edit the whole section to just contain the parts you want to be contained inside the file:

Yours and Theirs

Then git add the file or all files and git commit them.

If you want to show a the list of log messages

git log

or the differences between the current and previous version

git diff FILENAME

To revert to the current head on the repository (i.e. delete uncommited changes)

git reset FILENAME

And to undo the last commit just do

git revert UNWANTEDCOMMITHASH

Good practice

Some practice tips:

This article is tagged:


Data protection policy

Dipl.-Ing. Thomas Spielauer, Wien (webcomplains389t48957@tspi.at)

This webpage is also available via TOR at http://rh6v563nt2dnxd5h2vhhqkudmyvjaevgiv77c62xflas52d5omtkxuid.onion/

Valid HTML 4.01 Strict Powered by FreeBSD IPv6 support