If you've spent any time in industrial automation, you probably have a story. Maybe it's the time a technician overwrote the wrong version of a program during a breakdown at 2 AM. Maybe it's the mystery machine that runs a slightly different build of the code and nobody knows why. Or maybe it's the final_v3_ACTUAL_FINAL_USE_THIS_ONE.ap17 sitting in a shared drive somewhere.
These aren't just inconveniences - they're engineering risks. And Git, the version control system that powers GitHub, is how the software world solved this problem decades ago. This tutorial will show you how to bring those same tools into your automation workflow, whether you're working with Siemens TIA Portal, Beckhoff TwinCAT, Rockwell Studio 5000, or Codesys.
Allen-Bradley hardware used in our materials (Micro800 controllers, HMI panels and accessories) is supplied by our technology partner Elmark Automatyka, an authorized Rockwell Automation distributor.
Why Git for PLC Code?
Version control gives you three things that a shared drive never can:
A full history of every change. Every commit is a snapshot in time. You can see exactly what changed, when, and who made the change - down to a single rung of ladder logic or a single line of structured text.
The ability to work in parallel without overwriting each other. Branches let multiple engineers work on the same project simultaneously without stepping on each other's changes.
A safe way to experiment. Try a new approach on a branch. If it works, merge it. If it doesn't, throw it away. The main codebase stays clean.
Git Basics - Explained for PLC Engineers
You don't need to become a software developer to use Git effectively. Here's the core vocabulary, framed for the automation world.
Repository (repo): Think of it as your project folder - but one that remembers every version of itself. A repository lives locally on your machine and (optionally) remotely on GitHub, where the whole team can access it.
Commit: A saved snapshot of your project at a specific point in time. A good commit message describes what changed and why - not just "update" but "Fixed speed ramp on conveyor 3 - was causing e-stop on startup."
Branch: An independent line of development. You might have a main branch for production-ready code, a develop branch for active work, and a feature/new-safety-zone branch for a specific change you're testing. Branches are cheap and disposable.
Merge / Pull Request: When work on a branch is ready, you merge it back into main or develop. On GitHub, this is done through a Pull Request (PR) - which gives teammates a chance to review the code before it's merged.
Remote: The copy of your repo that lives on GitHub. You push your local changes to the remote, and pull updates from it.
.gitignore: A file that tells Git which files to ignore - compiled outputs, temp files, backups. Crucial in PLC projects where IDEs generate a lot of noise.
Platform-Specific: Getting Your Code Into Git
This is where automation differs from standard software development. Most PLC IDEs save projects in proprietary binary formats that Git can't diff meaningfully. The solution is to work with exportable text-based formats - typically XML - that can be read, compared, and tracked line by line.
Siemens TIA Portal
TIA Portal stores projects as binary .ap files by default, which are not suitable for direct version control. The recommended approach is to export your program blocks, PLC data types and tag tables to text files and version those instead.
- Use the Version Control Interface (a workspace linked to the project tree) to export blocks, PLC data types and tag tables as SimaticML
.xmlfiles, or right-click SCL and STL blocks and use Generate source from blocks to get plain text sources. In TIA Portal V21 graphical LAD and FBD blocks can also be exported as readable text (see TIA Portal V21 version control in Git). - For more advanced automation, the TIA Portal Openness API allows you to script exports, making it possible to automate the export step as part of your save workflow.
- Store only the exported XML in your Git repository - not the
.approject file itself. - Add a
.gitignoreentry for*.ap*, temp folders, and any simulation logs.
Tip: Consider writing a small script that exports all blocks automatically before you run
git commit. This removes the manual step and reduces the chance of forgetting to export before committing.
Beckhoff TwinCAT
TwinCAT is the most Git-friendly of the major PLC platforms. Projects are stored natively in an XML-based format, which means you can commit your project files directly without any special export step.
- Simply add your TwinCAT project folder to a Git repository and commit as you work.
- TwinCAT solution files (
.sln,.tsproj,.plcproj) and source files (.TcPOU,.TcDUT,.TcGVL) are all text-based and will produce clean, readable diffs. - Your
.gitignoreshould exclude the_Bootfolder,_CompileInfo, and any.tmccompiled outputs.
This tight integration with Git is one of TwinCAT's significant advantages for teams that care about traceability.
Rockwell Studio 5000
Studio 5000 saves projects as binary .ACD files. Like TIA Portal, the solution is to export to an XML-based format before committing.
- Export your project using File → Save As → L5X to produce a
.L5Xfile, which is an XML representation of your full program. - Commit the
.L5Xfile to Git - this gives you meaningful diffs between versions. - The
.ACDfile can optionally be committed too, but treat it as a binary blob; it won't produce useful diffs. - Your
.gitignoreshould exclude.ACDfiles (or mark them explicitly as binary with.gitattributes) unless you specifically want to store them.
Codesys
Codesys projects can be exported in an XML-based format (.export files) which are suitable for version control.
- Use Project → Export to produce an XML export of your project or individual POUs.
- For integrated version control, the CODESYS Git add-on (available in the CODESYS Store) connects the CODESYS Development System directly to a Git repository, so you commit, diff and branch from inside the IDE instead of exporting by hand.
- Commit the exported XML files and maintain a clear export convention across your team so everyone's exports are consistent.
B&R Automation Studio and other platforms
B&R Automation Studio keeps a project as a folder tree of mostly text files (Structured Text sources, variable and type declarations, XML package files), so like Beckhoff's TwinCAT it works with Git almost directly. For HMIs, drives and robots the rule is the same as for PLCs: if the tool can export a text or XML format, version that; if it only saves binary files, commit them as binary and describe the change well in the commit message.
Project Folder Structure
A consistent folder structure is the foundation of a maintainable project. Here's a structure that works well for most automation projects:

machine-project/
├── plc/
│ ├── exported/ # Exported XML source files (what goes in Git)
│ └── README.md # Notes on how to import/export
├── hmi/
│ └── exported/ # HMI project exports
├── docs/
│ ├── functional-spec/ # Functional design specifications
│ ├── electrical/ # Electrical schematics (PDFs or source)
│ └── io-list/ # I/O mapping spreadsheets
├── scripts/
│ └── export.bat # Automation scripts for export workflow
├── tests/
│ └── fat-checklist.md # Factory acceptance test procedures
├── .gitignore
└── README.md # Project overview, machine details, how to get started
The key principle: everything that defines how the machine behaves should be in the repository. That includes not just code, but specs, I/O lists, and test procedures. When a new engineer joins the project, they should be able to clone the repo and have everything they need.
Branching and Change Management
A simple branching strategy goes a long way. Here's one that works well for automation teams:
main - Always contains the latest production-ready, tested code. Only merge here after code has been reviewed and validated. Tag every release (e.g., v1.0.0, v1.2.3) so you can always get back to exactly what was running on the machine.
develop - The active integration branch. Engineers merge their feature branches here for integration testing before anything goes to main.
feature/<description> - Short-lived branches for individual changes. Examples: feature/add-vision-system, feature/fix-conveyor-timeout. One engineer, one task. Merge and delete when done.
machine/<name> - For multi-machine projects where the same codebase is deployed with different configurations, use branches (or better, Git tags) to track the exact version running on each machine.
hotfix/<description> - For urgent fixes that need to go directly to production. Branch from main, fix, merge back to both main and develop.
Tagging Releases
When you commission a machine or deploy an update, tag the commit:
git tag -a v2.1.0 -m "Post-FAT release - all safety functions validated"
git push origin v2.1.0
This means you can always check out the exact code that was running on the machine at any point in time. For audits, warranty claims, or incident investigations, this is invaluable.
Team Collaboration
Writing Good Commit Messages
A commit message is a note to your future self (and your colleagues). The difference between a useful history and a useless one is commit message discipline.
❌ Weak: update
✅ Better: Fixed false e-stop trigger on safety zone 2
✅ Best: Fixed false e-stop trigger on safety zone 2 - debounce timer was set to 0ms, increased to 50ms per safety review SR-204
The format: start with an imperative verb, keep the first line under 72 characters, and add detail in the body if needed.
Pull Requests as Engineering Review
A Pull Request isn't just a software concept - it's a structured change review, which automation engineers already understand as MOC (Management of Change). Before any change merges to main:
- The engineer opens a PR describing what changed and why.
- A second engineer reviews the code - checking logic, naming, safety implications.
- Any issues are discussed and resolved in the PR comments.
- The PR is approved and merged.
This creates a permanent, auditable record of every deliberate change to the codebase - the closest thing automation has to a formal red-line review process, but fast and searchable.
Using Issues for Change Tracking
GitHub Issues work well as a lightweight change request system. Before starting work, open an issue describing the problem. When you open your PR, reference the issue (Closes #42). When the PR merges, the issue closes automatically - giving you a traceable thread from problem statement to code change.
Binary file formats: seeing differences in ladder and function block diagrams
The hardest part of Git for PLC programs is not Git itself. It is the file formats. Git compares text files line by line, so for a binary file it can only tell you that something changed, not what. That is why every platform section above talks about exports: an XML or text based export turns a binary project into changed files that Git can actually diff.
Even with XML, differences in ladder logic and function block diagrams are not always pleasant to read, because one moved contact can change many lines of XML. A few practical tips:
- Use the vendor's compare tool for the logic review. TIA Portal can compare two projects offline/offline or a project with the CPU online/offline. Rockwell ships the Logix Designer Compare Tool with Studio 5000, and CODESYS has a project compare as well. Git tells you which version of the code changed; the compare tool shows you the network or rung.
- Prefer text over XML where you can. SCL, STL and Structured Text diff as cleanly as any traditional software. For Rockwell Logix projects, the older L5K export is plain text, while L5X is XML.
- Tell Git which files are binary. In .gitattributes mark .ACD, .ap* and similar project files as binary, so Git never tries to merge them. For large binary archives, Git LFS keeps the repository small.
- Save the project, then export, then commit. Make that order a habit, or script it, so the entire project in the repository always matches what you tested.
Git vs SVN and other PLC version control systems
Git is not the only option, and many plants still run Subversion (SVN), often with TortoiseSVN on the engineering laptops. The main difference is the model. SVN has one central repository and every commit goes straight to the server, so you need network access to it. Git is distributed: every engineer has a full local repository with the whole history, works offline in the working directory on site, and pushes to a remote repository when back on the network.
For automation professionals the choice usually looks like this:
- Git with a hosting service. GitHub, GitLab, Bitbucket or Azure DevOps are the common Git providers. Access goes over HTTPS or SSH. If the code must not leave the company, the same tools are available self-hosted on your own server.
- SVN. Fine for a single team that already has it and works mostly in the office. Branching and offline work are weaker than in Git.
- Vendor and specialist tools. Some PLC version control systems are built specifically for industrial control: Rockwell Automation's FactoryTalk AssetCentre for Logix and ControlLogix plants, TIA Project Server for TIA Portal teams, and Git-based products such as Copia Automation that render ladder and function block diagrams visually. They add things plain Git does not have, like device backups and graphical diffs, at the cost of a license.
A sensible path for most teams: start with plain Git and exports as described here, and add a specialist tool only when you know which gap it closes.
Getting Started: Your First Commit
- Install Git on your engineering workstation: git-scm.com
- Create a GitHub account (free for private repos for individuals and small teams).
- Create a new repository on GitHub for your project.
- Clone it to your local machine:
git clone https://github.com/yourname/machine-project.git - Export your PLC project using your platform's export method and copy the files into the cloned folder.
- Add a
.gitignoreto exclude compiled outputs and IDE temp files. - Make your first commit:
git add .
git commit -m "Initial commit - exported TIA Portal project v1.0"
git push
You now have version-controlled PLC code, with a full history from this point forward.
Git for PLC programs - frequently asked questions
Is Git or SVN better for PLC programming?
For new projects, Git. It works offline, branches are cheap and almost every modern tool and Git provider supports it. SVN is still a valid choice if your team already uses it and does not need offline work or frequent branching.
Can I put the TIA Portal .ap project file in Git?
You can, but Git will only see a binary file that changed. Keep the project file in a backup or TIA Project Server and put the exported text and XML into Git, so code changes are readable in the history.
Do I need internet access to use Git on a machine?
No. Git works completely locally: you can commit on the commissioning laptop without any network access and push the latest changes to the central repository later.
Does Git replace management of change?
No, it supports it. Pull requests and code review give you a written, searchable record of every change to the PLC programs, but your plant's approval and testing rules still apply, especially for safety-related code.
Closing Thoughts
Version control isn't a software developer habit that automation engineers have to borrow reluctantly - it's a fundamental engineering discipline that the software world formalized. Industrial automation is late to the party, but the tools work just as well for ladder logic as they do for Python.
If you program Rockwell controllers, our Allen-Bradley course from RSLogix 500 to Studio 5000 covers the projects you will be versioning, and for Siemens the TIA Portal LAD/FBD course.
Start small: one project, one repo, one consistent export habit. Build the muscle memory. Once you've worked through a messy change control situation with Git backing you up - or once you've been able to roll back to a known-good state in twenty seconds during a breakdown - you won't go back.
Have questions about setting up Git for your specific platform or use case? Drop them in the comments below.


