07 May 2019 - tsp
Last update 27 Feb 2022
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:
git init
and if not done globally
git config user.email "example@example.com"
git config user.name "example"
git add WHATEVER
git commit -S -m "Log Message"
git commit -S
git commit -m "Log Message, not signing commit"
git commit
git push origin master
or remembering the origin and master:
git push -u origin master
and after that only
git push
git pull
git remote add origin git@github.com:USERNAME/reponame.git
git branch branchName
git checkout branchName
git checkout master
or
git checkout branchName
git checkout targetBranch
git merge sourceBranch
git branch -d branchName
git status
<<<<<<< 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.
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.
git init
git add .
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"
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.
git commit
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
git remote -v
git push origin master
git push
afterwards instead of specifying
the remote during the push:
git push -u origin master
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
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)
gpg --gen-key
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.
gpg --armor --export 5198ACD84912ED02
gpg --armor --export-secret-keys 5198ACD84912ED02 > signerkey.priv
gpg --armor --export 5198ACD84912ED02 > signerkey.pub
gpg --keyserver pool.sks-keyservers.net --send-keys 4912ED02
git config --global user.signingkey 5198ACD84912ED02
git config --global gpg.program "c:\Program Files (x86)\gnu\gnupg\gpg2.exe"
git commit -S -m "commit message"
or
git commit -S
-S
flag
one can also set the commit.gpgsign
property to true
on either
global or repository scale:
git config --global commit.gpgsign true
Basically you just have to supply the -S
switch during commit.
git commit -S
or
git commit -S -m
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
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.
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
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.
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
After installing PuTTY and git:
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
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 .
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
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
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"
git push
git push origin master
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>"
To show all configuration options that have been configured (for example via git config)
git config --list
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.
cd
shell command) and initialize the
gti SCM:
git init
git add .
git commit -m "Initial commit"
or for a longer message
git commit
If you also want to sign your commits (see above) use -S
additionally
remote
command
shown on the webpage
git remote add origin git@github.com:USERNAME/reponame.git
and push initially
git push -u origin master
Without branching (just a linear chain of changes).
git status
git add .
or only for single files
git add WHATEVER
git status
git commit
or with -m
and optionally -S
as above
git push
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
Some practice tips:
This article is tagged:
Dipl.-Ing. Thomas Spielauer, Wien (webcomplains389t48957@tspi.at)
This webpage is also available via TOR at http://rh6v563nt2dnxd5h2vhhqkudmyvjaevgiv77c62xflas52d5omtkxuid.onion/