One of the most important functions of r10k is its ability to dynamically manage your Puppet environments.
When environments were originally built into Puppet they were meant to be static in nature. Each environment had to be defined beforehand in the master's puppet.conf file in a section, like so:
[master]
# Environment independent settings
vardir = '/var/lib/puppet'
[production]
modulepath = '/etc/puppet/environments/production/modules'
[testing]
modulepath = '/etc/puppet/environments/testing/modules'
[development]
modulepath = '/etc/puppet/environments/development/modules'
Static Puppet environments were frequently used to implement a pipeline for developing Puppet code. New Puppet code would be developed and deployed to the development environment, pushed to testing for validation, and then finally pushed to the production for general deployment.
This static nature of Puppet environments turned out to be inflexible in practice. With a predefined list of environments it could be very cumbersome to develop on different parts of a Puppet codebase in isolation; you could either develop multiple features in the same environment and risk cross pollution, or manually create new environments every time you needed isolation.
Dynamic environments work by dynamically determining the settings for Puppet environment when the environment is used, rather than by defining an explicit section in puppet.conf. This works by making the current environment (in the '$environment' variable) part of of the path to environment specific settings, like modulepath, manifest, and so forth.
[master]
environmentpath = $confdir/environments'
Running puppet agent -t --environment myenv
will cause $environment to be
expanded to 'myenv', so the modulepath for that environment will be set to
'/etc/puppet/environments/myenv/modules'.
This approach of allowing environments to be defined on the fly is a complete reversal of the original architecture of environments. This approach means that it can be very easy to create new environments, update existing environments, and remove environments that aren't needed anymore. It's common practice to create a temporary environment to test an idea and destroy it shortly after. R10k is designed to enable this sort of fluid workflow.
R10k predominantly uses version control systems to implement dynamic environments. This works by inspecting the VCS repositories containing your Puppet code and checking out that code on your masters so, that there's a 1:1 connection between a branch in your VCS repository and a Puppet environment on your masters. This approach allows you to define the way you want to work and use that with your chosen VCS, and r10k will make Puppet implement that workflow.
Different version control systems will implement dynamic environments in slightly different ways; check out the VCS specific documentation for more information.