Tech Tips

Git Best Practices for Industrial Automation

Published on
December 22, 2022

By following tried and true Best Practices, Controls Engineers can make the most of the tools at their disposal to maximize collaboration and code quality.

Let's look at some Git Best Practices for PLC Programmers


One of the more common questions Controls teams ask when starting with Git is: What goes in a repository?

Generally speaking, code that works together belongs in a repository together.  This may be the code for a single PLC, or in the case of a machine or process with multiple PLCs, it may contain the code for multiple PLCs that work together. When deciding how to structure your organization’s entire codebase within Git, It can help to think of some use cases: For example, if a problem is found in the programming of one PLC in one machine in a manufacturing line, is there a chance that fixing it will also require substantial changes to other PLCs?  If so, maybe the code for those PLCs should be tracked in a repository together.  On the other hand, if changing the code on one PLC is relatively independent of the code running on another PLC, it can be easier to track those projects in separate repositories. Undoing a set of changes on a repository with only one PLC, with a commit checkout, for instance, allows users to revert to a previous version of one PLC’s code, without altering the state of the code for any other PLCs. This option also allows for an organization to have more granular read/write permissions for their code; admins can assign custom teams of users with read or read/write access to individual repositories.

If your Controls team maintains a common codebase, with a base project or libraries, such as Rockwell AOIs, which are used across multiple individual projects, it may make sense to group these items together into one or more repositories, distinct from any repositories containing projects destined for building and uploading to a PLC


Commit Small, Commit Often

Break up programming tasks to be as granular as possible. This is generally a useful strategy in PLC programming, as it facilitates modularity, improving code maintainability and reusability, but the benefits don’t stop there. Committing small, but complete chunks of code facilitates unit testing, gives more opportunities to keep branches up-to-date by merging, and gives better control when reverting changes by keeping the content of commits distinct.

Fetch every time you start programming

Any time you sit down to start writing control logic, it’s a good idea to fetch from the remote repository, and pull any changes found, to stay up-to-date with your team.  This can be, for example, at the beginning of the day, or when starting a new development effort.  Even with good communication within your team, information can occasionally be dropped, and fetching frequently can help mitigate the effects of communication breakdowns.

Check your code before committing

Try not to commit broken code, and if you have to, do whatever you can to make sure you don’t push broken code to the shared remote repository before fixing it. Be sure to review Diffs before committing, to ensure exactly the correct changes are shown, and where possible, test code changes before committing. If you do have to commit incomplete changes, you can come back later and amend the most recent commit to complete it.  

Use custom commit messages

Although Copia can often provide an auto-generated commit message, it is generally a good idea to provide additional information with a custom commit message.  Along with good code commenting, concise commit messages help to ensure that every piece of control logic, and every change to it, is clear and easy to understand months or years down the line as a Controls team grows and evolves.  Additionally, custom commit messages allow Copia users to pull commits into external business apps like Jira

Good .gitignore settings

It’s important to make sure your repositories don’t get cluttered with unnecessary auto-generated or temporary files, which can stack up and increase a repository’s size and the number of files to sift through, without adding any value.  One of the best ways to keep clutter out of your repositories is with a sensible .gitignore file.  Thankfully, Copia users don’t generally have to worry about setting these manually, as every new repository is generated with a default .gitignore file containing reasonable base settings for all supported PLC Vendors, and temporary or background files should be filtered out of backups automatically.

Branch Out

Branches give users a tremendous amount of control over their code, and it’s extremely helpful to familiarize yourself with Branches and a branched workflow.

Give branches good names

When using a branched repository, it’s important to be able to quickly sort through branches to find what you’re looking for. Therefore, it helps to name branches clearly, and with a consistent convention.

Branching Conventions

It usually makes the most sense to try to structure your projects and repositories in a way that best fits your organization’s needs and current processes. That said, there are some existing conventions which can serve as useful starting points to tweak if needed.

Feature Branches

Using Feature Branches, looks, essentially, like a main repository, with a new branch for each individual development effort, potentially with branches off of these branches for additional granularity.  As individual tasks are completed, these branches are reviewed and merged back into their parent branches, until the changes make their way back to the main branch.  This method provides clear organization of the development of a project over time, and can help ensure that Controls engineers are kept tightly in sync as a team when developing PLC code.

Personal Branches

By organizing a repository with Personal Branches, each engineer gets their own branch as a scratch space for their development.  This method can give better oversight into each programmers’ contributions, and can allow engineers to work somewhat more independently; it is most effective when each Controls Engineer on a team is given responsibility over a distinct module or subsystem


GitFlow is essentially a modified, and more complex, version of a Feature Branch repository which splits the main branch into multiple pieces: a development branch, release branch, and main branch.  This method can provide a more structured process for code releases. However, it does require maintaining multiple long-lived branches; this entails merging changes on these long-lived branches back and forth in order to keep these multiple branches in sync throughout development, requiring additional effort and communication.

Trunk-based Development

Trunk-based Development is a somewhat more centralized overall workflow than the other conventions listed here, and is currently considered best practice by many for traditional code development; it is, essentially, a Feature Branch workflow with an emphasis on the main branch.  Engineers can branch off to create new features, but branches are short-lived, limited to a handful of small commits before merging back into the main branch.  This makes a repository’s overall structure fairly simple to set up and understand, and can enable a faster development and deployment cycle by streamlining the overall process of introducing new code into the main branch for release. Because of the use of the main branch as the source of ground truth, and the more frequent merges back into the main branch, it is extremely important when using Trunk-based Development that individual developers test their contributions and participate in frequent code reviews of individually smaller contributions, to ensure the quality of code on a repository’s main branch.  Trunk-Based Development can be especially useful when coupled with comprehensive automated code testing, to provide an additional layer of protection on the quality of the main branch.

Use Branch Protections

Branch Protections allow users to restrict changes to, and prevent the deletion of, any branch in a repository.  Users or custom teams can be whitelisted for pushing, merging, and code reviews, providing tight control over the quality of the contents of any number of branches.  Branch Protections are generally good to implement, where possible, and are especially useful for a GitFlow repository, where the flow of changes from a development branch through to the main branch should be carefully gated to ensure only high quality, thoroughly tested PLC code makes it into release versions.

Delete Stale Branches

If your branching conventions involve short-lived branches, or branches created for a distinct programming task, it can help keep your repositories tidy to delete those branches once they have served their purpose, and the code has been reviewed and merged into a longer-lived branch.

Code Reviews and Releases

Use Frequent Code Reviews

A robust Code Review process assists Controls teams both in producing high quality code, and in maintaining a tight development cycle; in Git-based Version Control, Code Reviews are performed via Pull Requests, or PRs.  Not only do Pull Requests facilitate a formalized Code Review process, but along with frequent Commits, they help perform the important task of documenting everything that goes into developing a PLC project.

It is generally a good idea to perform a PR before merging, especially if merging into a branch with other active development ongoing, such as a repository’s main branch; Branch Protections can enforce this process.

Keep Pull Requests Atomic

Depending on your Branching Conventions, Pull Requests may contain anywhere from a small handful of granular commits, up to significant changes across several sections of a PLC project, recorded across a large number of commits. For example, when programming using Trunk-based development, code reviews will ideally be smaller, yet more frequent, than with a standard Feature Branch repository, or with GitFlow.  

Regardless of this, it is important that a pull request only contains changes that can be grouped together, as a distinct subsystem, module, or other multi-step programming task. Mixing multiple programming efforts into a single Pull Request can cause confusion during review, and can prevent good, complete code from merging if an unrelated, but included, piece of logic breaks the overall functionality of a machine.

Releases and Commit Tags

With most Branching Conventions, it’s helpful to be able to manually mark specific versions as “Releases”, ready to build and install into a machine for commissioning. In some cases, such as with GitFlow, Releases are naturally organized as subsequent commits on a single branch, but even in this case, there are benefits to using Releases and Commit Tags (referred to simply as ‘Tags’ in Git documentation), such as the ability to easily mark sub-versions and other unofficial milestones internally. Releases, additionally, allow Controls teams to mark a Release with additional status information as the release undergoes final testing and documentation and announcements are prepared, and ensure all release versions are easy to track down and retrieve

Good Backup Practices

Following Best Practices for Git Version Control helps ensure the quality of the code that makes it onto the plant floor, and gives continual access to all recorded development versions. With PLCs, there is an additional element at play: the state of the control logic after commissioning. Parameters may be modified from their initial defaults during commissioning, and more significant changes may be made after the fact, for a variety of reasons; maybe to improve throughput, or fix a bug in a previously undiscovered edge case.  Whatever the reason may be, these changes may be relegated to the live version of PLC code, rather than being saved and committed into the Version Control repository, so it’s a good idea to maintain a rigorous process for backing up the version of control logic running on actual hardware in the field.  This will guarantee that all changes and improvements are tracked and are always available, which will help a Controls team minimize both machine downtime and rework.  Copia’s solution for Device Backups, DeviceLink™, simplifies and automates many of the steps for managing manufacturing device backups for a robust Device Backup process.

Leverage External Tools

Quickly communicating information about updates, issues, code reviews, and backups within a Controls team is key to maintaining a tight development loop and meeting project deadlines;  with that in mind, it can be extremely useful to leverage existing integrations with business applications, like Jira or Slack, that may already be an integral part of your company’s development processes.  Fortunately, Copia makes this simple with Webhooks, allowing users to easily configure automated notifications for various events and changes in a repository.


When used correctly, Git-based Version Control is not only extremely powerful, but also highly customizable, and gives users tremendous freedom to structure repositories and workflows to fit their specific needs. Hopefully, this guide serves as a useful starting point, and provides some general guidelines to help you realize the maximum benefit possible from your Version Control strategy.  See how Copia can help improve your Version Control Solution with a free trial.