This control-repo
is stored in a Git version control system.
Whoever has to work on it should have basic Git
knowledge.
Here we are going to review Git essentials
and outline possible workflows
for Puppet code
development
, testing
and deployment
process.
Here is a very brief overview of Git essentials
. There are many online resources where to learn more about it, here is a brief list:
-
Git - The simple guide - A very basic introduction to
Git
. Used as starting point for this topic -
Pro Git - A free and rather complete book about
Git
-
A visual Git Reference -
Git
main concepts visualised and explained -
GitHub Help - Useful info about
Git
andGitHub
-
Try Git - A site where is possible to practice with
Git
-
Git Reference - An online reference
Once installed Git
provides a CLI command
which has several actions. Let's see the most used ones.
Create a new repository in the current directory:
git init
Checkout a repository: create a local copy from a remote server.
To clone via HTTPS (username and passwords are needed for private repos):
git clone https://github.com/example42/control-repo
To clone via SSH:
git clone [email protected]:example42/control-repo.git
Any Git repository
consists of three "trees":
- The Working Directory holds the actual files we are working on
- The Index also known as
staging area
containing files ready to be committed - The HEAD which points to the last commit on the
Git repository
Once we start to modify
, add
or delete
files in our Git repository
, we have to add them to the Index
before being able to commit them.
To add a specific file to the Index
:
git add <filename>
To add all the changed or new files from the current Working directory
to the Index
:
git add .
To add all the changed, new and deleted files from the current Working directory
to the Index
:
git add --all .
To visualize the status of our files (the ones added to the Index
and ready to be committed, or the ones created or changed, which are only in the Working Directory
and not yet on the Index
, write:
git status
When we are confident that the files added to the Index
are complete, we can commit our changes.
To create a commit with the changes in Index
and the given title:
git commit -m "Commit message"
To create a commit and open our editor to add a title (on first line of the text we edit) and eventually a description of the commit (on the following lines):
git commit
Now the files are committed to the HEAD
or our local working copy, but not in our remote repository yet.
To send those changes to our remote repository, we can run:
git push origin <branch>
NOTE: Usually the main branch of a Git repository
is called master, but in Puppet
control-repos
this is instead called, production to make it match Puppet's
default environment
.
Worth noting is that we might not be able to push directly to the production branch
: it's relatively common to work on a development branch
and then, after a proper CI pipeline
where relevant tests are done, promote the change to the production branch
.
We will review some sample development workflows
.
Branches can be considered different versions of the repository, changes made in a branch can be merge into another. They are typically used to develop features isolated from each other which, once completed and tested, are merged back into the master branch
(production
, in case of a Puppet
control-repo
).
To create a new branch named "development" and switch to it:
git checkout -b development
To switch back to production branch:
git checkout production
To merge another branch into our active branch
(e.g. to realign our development branch
to the content of the production branch
), first we move into our development branch
:
git checkout development
Then we merge eventual additional contents of production branch
into the development branch
:
git merge production
If the same files have been modified in both the branches, a conflict may be present and automatic (fast-forward
) merging could not be possible. In these cases, we are responsible to merge those conflicts manually by editing the files shown by git
. The involved commands could be as follows.
We move into our development branch:
git checkout development
We merge production into development and we see conflict errors:
git merge production
To show the conflicting files:
git status
We need to edit the file, where we will see in patch format
(the same we see when using the diff command
) the different changes on the file. We need to remove the diff placeholders (Lines like === or >>>) and edit the code in the expected way:
vi <file>
To add the file to the Index
:
git add <file>
To review and commit our conflict resolution:
git commit
In case we did something wrong that we want to revert, we can use the following commands, according to the circumstance (read this tutorial for more details).
To replaces the changes on the given file in our Working Tree
with the last content in HEAD
(Changes already added to the Index
, as well as new files, will be kept):
git checkout -- <filename>
To drop all our local changes and revert back to the latest local commits:
git reset --hard
To undo the changes done in the given commits:
git revert <git_commit_id>
Other useful commands often used when working with Git
:
git log # Show git commits history
git log --name-status # Show commits history and the changed files in each commit
git log --pretty=oneline # Shot commit history using one line per commit
git pull # Update the local repository with the newest commit from remote origin
git diff # Show the differences between Working Directory and Index
git diff HEAD # Show the differences between Working Directory and HEAD
git diff production development # Show the differences between production and development branches
Git
can be configured using the git config
command or by editing the ~/.gitconfig
file.
Some configurations examples:
git config color.ui true # To enable colorful output
git config format.pretty oneline # Show log on just one line per commit
git config user.name 'My Name' # To configure the username to show on our commits
git config user.email '[email protected]' # To configure the email to show on our commits
Git
is a very versatile tool which allows distributed development also for very complex projects.
We can follow different workflows for our code, which defines the steps and procedures to follow to promote code changes from local development
to public development
.
These are some popular workflows, with a brief comment, we should follow one that better fits our needs (and skills):
-
GitFlow A very popular, but somehow complex, workflow, involving
different branches
forfeatures
,releases
andhotfixes
. -
GitHub Flow - A much simpler workflow based on master to which
Pull Requests
are made fromfeature branches
-
GitLab Flow - A workflow similar to
GitHub flow
with some variations.
This control-repo
provides some commands related to Git
.
To install useful git hooks
for Puppet files
checking (by default downloaded from https://github.com/drwahl/puppet-git-hooks) use one of these, alternative, commands:
bin/git_install_hooks.sh # Direct bash command
It's possible to specify the git repo
URL to use (hooks are looked in the commit_hooks
directory, so that directory should exist in our repo):
bin/git_install_hooks https://github.com/my/puppet-git-hooks
We can customize the kind of checks to do by editing the file:
${control_repo_dir}/.git/hooks/commit_hooks/config.cfg
in particular we might prefer to set CHECK_PUPPET_LINT='permissive'
to avoid commit block on Puppet lint
errors which are syntactically correct but may have code style problems (so mostly aesthetic).
NOTE: that existing git hooks
are not overwritten by this task.
When working on our control-repo
, besides it's own Git repository
, we may have, in the modules/
directory external modules with their own Git repositories
. To quickly check the git status
of the main control-repo
and of the other eventual modules, run:
bin/git_status.sh