Chapter 12: Git and Development Containers

Managing automation projects with Git

A playbook is code, so treat it like code. Git keeps every version of your project, shows exactly what changed and who changed it, and lets a team work on one project without overwriting each other's work.

Why automation belongs in Git

In chapter 2 you met infrastructure as code: the playbook describes the state your systems should be in. Once that description lives in Git, you gain three things:

Four places your work lives

Git keeps your project in four places. Step through one change, from cloning the project to pulling a teammate's work back:

Where your work lives in Git

PlaceWhat it holdsCommands that move work into it
Working treeThe files you edit, in the project directorygit clone, git pull, your editor
Staging areaThe draft of your next commitgit add
Local repositoryYour commits, in the hidden .git directorygit commit
RemoteThe shared copy everybody clones fromgit push

Tell Git who you are

Every commit records an author. Set your name and email once per user account; --global applies them to every repository you work in. The third setting tells git pull to merge a teammate's work with yours, which is the easiest way to start. Without it, a pull that has to combine two histories stops and asks you to choose a strategy.

git config --global user.name 'Student'
git config --global user.email 'student@workstation.lab.example.com'
git config --global pull.rebase false
git config --global --list

Clone a project

git clone copies a remote repository, with its full history, into a directory. Its argument is the remote's address. In this lab the remotes are directories on workstation; in a company it is usually an HTTPS or SSH URL from a Git server. The commands that follow are the same either way.

[student@workstation ~]$ git clone ~/git-repos/ops/web-motd.git web-motd
Cloning into 'web-motd'...
done.
[student@workstation ~]$ cd web-motd
[student@workstation web-motd]$ git log --oneline
fe7941c Warn that the MOTD is managed
8d7ff6c Add the MOTD project
[student@workstation web-motd]$ git remote -v
origin	/home/student/git-repos/ops/web-motd.git (fetch)
origin	/home/student/git-repos/ops/web-motd.git (push)

Git names the remote you cloned from origin. git push and git pull use it when you do not name another one.

The everyday cycle

Every change follows the same five steps: edit, check, stage, commit, push.

[student@workstation web-motd]$ echo 'Contact: ops@lab.example.com' >> templates/motd.j2
[student@workstation web-motd]$ git status --short
 M templates/motd.j2
[student@workstation web-motd]$ git diff
--- a/templates/motd.j2
+++ b/templates/motd.j2
@@ -1,2 +1,3 @@
 Welcome to {{ inventory_hostname }}.
 This host is managed by Ansible: local changes to this file are overwritten.
+Contact: ops@lab.example.com
[student@workstation web-motd]$ git add templates/motd.j2
[student@workstation web-motd]$ git diff --cached --stat
 templates/motd.j2 | 1 +
 1 file changed, 1 insertion(+)
[student@workstation web-motd]$ git commit -m 'Add a contact line to the MOTD'
[main df86f6e] Add a contact line to the MOTD
 1 file changed, 1 insertion(+)
[student@workstation web-motd]$ git push
To /home/student/git-repos/ops/web-motd.git
   fe7941c..df86f6e  main -> main

Bring in your teammates' work

A teammate may push while you work. git pull downloads their commits and updates your working tree. Pull before you start a change, and pull again if Git rejects your push:

[student@workstation web-motd]$ git push
To /home/student/git-repos/ops/web-motd.git
 ! [rejected]        main -> main (fetch first)
error: failed to push some refs to '/home/student/git-repos/ops/web-motd.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally. This is usually caused by another repository pushing to
hint: the same ref. If you want to integrate the remote changes, use
hint: 'git pull' before pushing again.
...output omitted...
[student@workstation web-motd]$ git pull --no-edit
Merge made by the 'ort' strategy.
 README.md | 1 +
 1 file changed, 1 insertion(+)
[student@workstation web-motd]$ git push

Git refuses the push so that it never silently discards your teammate's commit. The pull merges their commit with yours in a new merge commit; --no-edit keeps Git's default message for it instead of opening an editor. Now your history contains both changes and the push succeeds. If you both changed the same lines, Git stops and asks you to choose. Edit the file, then git add and git commit to finish.

Keep secrets and generated files out

Some files must never be committed. Others are created by tools and are not worth keeping:

List them in a .gitignore file at the top of the project and commit that file. Git then leaves them out of git status and git add -A:

vault-pass
ansible-navigator.log
*-artifact-*.json
[student@workstation web-motd]$ git check-ignore -v vault-pass
.gitignore:1:vault-pass	vault-pass

Undo a change you have not committed

You want toCommand
Throw away your edits to a filegit restore templates/motd.j2
Unstage a file but keep your editsgit restore --staged templates/motd.j2
See what one commit changedgit show df86f6e