Puppet and Git, 102: Feature Branches

In Puppet and Git 101, we looked at how to add our existing puppet code to our repo. We’re going to take a quick look at how to create a branch, add some code, commit it, and push it to our repo.

Create a Branch

For lack of something significant to do right now, we’ll add a notify command to the node definition for puppet.nelson.va. To do so, we will checkout a new branch called, appropriately, notify. You can call your branches whatever you want, I suggest you simply be consistent in your naming scheme. At work, I use a combination of a ticket number and a one or two word description of the feature, separated by hyphens. Normally our branch is going to be short lived and only exist locally (we’re going to make an exception to that for demo purposes), so it would be a moot, but it’s still a good habit to be in.

[root@puppet puppet]# git branch
* master
[root@puppet puppet]# git checkout -b notify
Switched to a new branch 'notify'
[root@puppet puppet]# git branch
  master
* notify

Add a notify statement to the manifests/site.pp file as below:

[root@puppet puppet]# cat manifests/site.pp
node 'puppet.nelson.va' {
  include ::base
  notify { "Generated from our notify branch": }
}

When we check the status now we will see that a file has changed, but it is not added to the commit. A commit would fail. We can add it to be tracked, or we can add it and commit in a single command.

[root@puppet puppet]# git status
# On branch notify
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   manifests/site.pp
#
no changes added to commit (use "git add" and/or "git commit -a")
[root@puppet puppet]# git commit -a -m 'Adds notify to puppet master node definition'
[notify 7899e2d] Adds notify to puppet master node definition
 1 files changed, 1 insertions(+), 0 deletions(-)

Note that I used the present tense in my commit message. This is a very religious argument, so I’ll just stop there 🙂

Change branches

Now that the change is committed, we can change branches very quickly and see the differences in the site manifest. Let’s check that out quickly.

[root@puppet puppet]# cat manifests/site.pp
node 'puppet.nelson.va' {
  include ::base
  notify { "Generated from our notify branch": }
}
[root@puppet puppet]# git checkout master
Switched to branch 'master'
[root@puppet puppet]# cat manifests/site.pp
node 'puppet.nelson.va' {
  include ::base
}
[root@puppet puppet]# git checkout notify
Switched to branch 'notify'
[root@puppet puppet]# cat manifests/site.pp
node 'puppet.nelson.va' {
  include ::base
  notify { "Generated from our notify branch": }
}

Swanky.

Pushing a branch

You’ve committed your branch, but it doesn’t show up on Github (on the project page, there’s a branch pulldown right above the file listing). If someone else wants to see your branch, they need to grab it from the puppet master. That’s probably okay…unless your master blows up and you lose the local repo. We need to push the branch to origin so it’s available elsewhere. We use the format git push <remote> <branch>.

[root@puppet puppet]# git push origin notify
Password:
Counting objects: 7, done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 409 bytes, done.
Total 4 (delta 1), reused 0 (delta 0)
To https://rnelson0@github.com/rnelson0/puppet-tutorial.git
 * [new branch]      notify -> notify

Once the branch is available on github, others can check it out from there and you have some level of resiliency against data loss. Next, we need to…

Merge the branch

Now that our new branch works, for all sufficiently low values of work, we want to merge the work into our master branch. You do this by checking out the master branch, then merging the notify branch into it. Don’t forget to push it to origin!

[root@puppet puppet]# git checkout master
Switched to branch 'master'
[root@puppet puppet]# git merge notify
Updating bc1e27b..7899e2d
Fast-forward
 manifests/site.pp |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
[root@puppet puppet]# git push origin master
Password:
Total 0 (delta 0), reused 0 (delta 0)
To https://rnelson0@github.com/rnelson0/puppet-tutorial.git
   bc1e27b..7899e2d  master -> master

Multiple Branches

What we did above was pretty simple, one branch for one feature and then we merged it back into master. In the future, we may work on concurrent branches at once. You might be working on a manifest definition for the puppet master and a colleague may be working on server01. Or you’re fixing two different problems with the same node. Git allows you to create multiple branches, make changes to different code (sometimes in the same file) and merge the branches independently. If you do make changes to the same code as someone else, there are methods to address this, too.

We’re not going to get into concurrent development, as this is a little beyond our focus of Puppet, but you should be aware of the functionality available to you, should you need it. Checkout this git branching model tutorial for more details.

Deleting a Branch

Our notify branch isn’t something we need to keep around anymore, now that the changes are merged into master. Delete it locally with git branch -d <branch>.

[root@puppet puppet]# git branch -d notify
Deleted branch notify (was 7899e2d).

Of course, it’s still available on github. If you need it again, you can pull it down with git checkout notify, as can anyone else who has cloned it. That might be okay for some feature branches – perhaps you have a perpetual development branch, or a v1.1 or v2.0 branch for a new version – but not for such a simple branch like this. We can delete it with either git push origin -d <branch> (git 1.7.0+) or git push origin :<branch> (git 1.5.0+). I’ll use the latter, as I like the brevity.

[root@puppet puppet]# git push origin :notify
Password:
To https://rnelson0@github.com/rnelson0/puppet-tutorial.git
 - [deleted]         notify

Refresh your Github page and you’ll see just one branch, master. You could, of course, also have deleted the branch on Github itself, but that’s no fun. Be aware that you cannot undelete branches via Github (except when done via a pull request). Because it’s a distributed VCS, you could always retrieve the branch from another copy of the repo. If you’re careful when deleting branches, you won’t have to worry about such issues.

Revert to v0.1

We’ve merged the notify branch into the master branch and then deleted it. What if we want to go back? There are a few ways to do so, which relies on (to me) archaic syntax involving checksums. Does git checkout c2e7af2b51 seem user friendly? Thankfully, we made a tag for v0.1 earlier. We can go back to that version very quickly, the same way we did before, and see the change in place by looking at the site manifest.

[root@puppet puppet]# cat manifests/site.pp
node 'puppet.nelson.va' {
  include ::base
  notify { "Generated from our notify branch": }
}
[root@puppet puppet]# git checkout tags/v0.1
Note: checking out 'tags/v0.1'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b new_branch_name

HEAD is now at bc1e27b... Initial puppet config
[root@puppet puppet]# cat manifests/site.pp
node 'puppet.nelson.va' {
  include ::base
}

As noted earlier, you are now in a detached HEAD state which means no changes. You’ll have to resort to one of the other methods if you need to make changes. Checkout master again to return to a normal status.

Environments

We didn’t do a whole lot of meaningful Puppet work today as we focused on git workflows. The next thing we need to do is set up are some environments. Each puppet agent requests a catalog from an environment. By default we only have a production environment, but we can define additional environments and give different agents different catalogs. Each git branch will be a different environment, and we’ll merge the features back in to master when they’ve tested out – exactly what we did today. We’ll use what we learned today to set up environments in the next piece.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s