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:
- Initializing a new project repository:
and if not done globally
git config user.email "example@example.com"
git config user.name "example"
- Adding files to the local stage:
- Commiting to local repository - one of:
git commit -S -m "Log Message"
git commit -S
git commit -m "Log Message, not signing commit"
git commit
- Pushing to a remote repository:
or remembering the origin and master:
git push -u origin master
and after that only
- Pulling changes from the remote
- Adding an remote
git remote add origin git@github.com:USERNAME/reponame.git
- Creating a new branch
git branch branchName
git checkout branchName
- Switching branches
or
- Merging two branches:
git checkout targetBranch
git merge sourceBranch
- Deleting a branch
- Displaying repository (and conflict) status:
- Conflicts. They are shown after a merge or a pull has been executed and are also shown via status. After resolving just commit the resolved status. For every conflict the diff is embedded in the
files that have conflicted in the way
<<<<<<< TARGETBRANCHNAME
Theirs
=======
Yours
>>>>>>> SOURCEBRANCHNAME
You simply edit the files to contain only the correct value (without the target and source branch lines), add and commit as usual to resovle the conflict.
- Rebase. This is a really powerful tool for various tasks. The easiest way is to use the interactive editor
git checkout TARGETBRANCH
git rebase -i SOURCEBRANCH
or
git rebase -i PREVIOUSCOMMIT
This lets one pick
(commit will be a single commit), squash
(commit will be combined with the next commit in the file), fixup
or edit
the commit.
This allows squashing, moving commits to another branch or rewriting history. Since rebase is such a powerful tool itâs highly
recommended to learn the behaviour for example with a git simulation.
Putting an existing project under version control
- If you want your project to be hosted on github - first create a new repository on github.
- Change your working directory into your existing projects directory
- Initialize the git repository:
- Add all local files (as wanted) to the repository
- If you want you can now set your user.name and user.email. When using github this is mandatory
git config user.email "example@example.com"
git config user.name "example"
One can also do that globally by adding the --global
option:
git config --global user.email "example@example.com"
git config --global user.name "example"
- Commit your changes to your local repository (do not follow that step if you want to sign your
commits. This is described in the next section!)
git commit -m "Commit log message"
If you want to write a longer logmessage just leave the -m line. And editor will popup and let you
write your log message. Write expressive log messages that describe what youâve changed.
- Now we have to add the remote origin if we donât want to use the repository only locally. This
should be either the https or ssh repository URI. When using github you can grab yours from the
repositories page. It should either look like
https://github.com/USERNAME/reponame.git
or
git@github.com:USERNAME/reponame.git
To add the repository reference to the origin:
git remote add origin git@github.com:USERNAME/reponame.git
- You can verify the remote with
- Now push your changes like you would do after any other
commit
- If you want to use that repository as upstream you can set
the -u flag and use
git push
afterwards instead of specifying
the remote during the push:
git push -u origin master
Removing an remote
If one wants to remove an remote to unlink a repository from their upstream or change
an invalid reference on can
To list all remotes one can use
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)
- Generate a new key:
- Select âRSA and RSAâ when asked for type of keys
- Decide which key length you want to use
- Select validity of the key. Normally keys should expire after a maximum of a few years
- You can use any Name and Mailadress you want. If you use githubâs mail privacy feature
itâs a good idea to use the same name as your github username and the same mailadress
as the generated noreply address
- Now you can also list all keys and their associated private keys:
gpg --list-secret-keys --keyid-format LONG
This command outputs 3 lines per key - these are sec, uid and ssb. Locate
the key you want to use to sign your commits and determine the key id. If
you see a line
sec 4096R/5198ACD84912ED02 YYYY-MM-DD [expires: ]
then the key-ID is 5198ACD84912ED02.
- Extract the public key:
gpg --armor --export 5198ACD84912ED02
- You can upload the public key block (including begin and end lines) to your
github profile settings.
- For later backup export private and public keys:
gpg --armor --export-secret-keys 5198ACD84912ED02 > signerkey.priv
gpg --armor --export 5198ACD84912ED02 > signerkey.pub
- You should also upload your key to a keyserver to make it easier to
for third parties to fetch your public key and verify your identity
(also based on the web of trust which is explained later).
gpg --keyserver pool.sks-keyservers.net --send-keys 4912ED02
- To tell git to use this key for signing either globally or on a per
repository basis, set user.signingkey property to the given key id
git config --global user.signingkey 5198ACD84912ED02
- Depending on your system configuration you may have to tell git about
the location of your gpg executable (this has been mostly seen on MS
Windows). An example for MS windows would be:
git config --global gpg.program "c:\Program Files (x86)\gnu\gnupg\gpg2.exe"
- If you now want to sign your commit, set the -S switch during commit:
git commit -S -m "commit message"
or
- In case one always wants to sign commits without specifying the
-S
flag
one can also set the commit.gpgsign
property to true
on either
global or repository scale:
git config --global commit.gpgsign true
Signing commits
Basically you just have to supply the -S
switch during commit.
or
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
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
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.
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:
- 0: No indication
- 1: Personal belief but no verification (for example for pseudonyms)
- 2: Casual verification (youâve seen an government issued ID card, passport, etc.)
- 3: Extensive verification
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
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
Windows, PuTTY and PLink, GUI
After installing PuTTY and git:
- Create a new SSH key with puttygen (use ED25519 format) and store private and public key somewhere on your machine.
- Upload the âPublic key for pasting into OpenSSH authorized_keys fileâ into your github Settings (add new SSH key)
- Modify the users environment to include GIT_SSH pointing to your plink.exe.
- 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â
- 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.
- Testing SSH connection. This can be done using plink:
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
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)
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:
If you have any conflicting changes git shows you the conflicts
during the pull and also with
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:
Then git add
the file or all files and git commit
them.
If you want to show a the list of log messages
or the differences between the current and previous version
To revert to the current head on the repository (i.e. delete uncommited
changes)
And to undo the last commit just do
git revert UNWANTEDCOMMITHASH
Good practice
Some practice tips:
- Writing meaningful log messages
- Keep your commits small
- Each commit should change exactly one thing (implement one feature, add one topic, etc.)
- If multiple commits in your local repository are logically related and change the same feature squash before pushing
This article is tagged: