Let's Git to the Point
Start course

This course explores how to implement version control on Azure repos. It begins with an overview of what source control is and the different types of source control available. It then looks at the key elements of branching, different branching strategies, and how they impact the development process. You'll move on to learn about pull requests and merging as repository functions, and the different merging scenarios available to you. Finally, you'll be guided through using third-party systems in conjunction with Azure DevOps. This course contains several guided demonstrations from inside the Azure portal to give you real-world exposure to the concepts covered throughout the course.

If you have any feedback relating to this course, please feel free to reach out to us at with any questions or comments.

Learning Objectives

  • Understand what version control and Git-based repositories are
  • Learn about branching and the branching strategies
  • Learn about pull requests and merging in Azure DevOps
  • Set permissions on repositories and on TFVC in Azure DevOps
  • Use Azure DevOps in conjunction with build pipelines set up on other platforms

Intended Audience

This is an intermediate level course suited to developers, engineers, and project managers.


To get the most out of this course, you should have a basic understanding of the software development lifecycle. Knowing what's involved in deploying software to a production environment would also be helpful. If you want to follow along with the demonstrations in this course, you'll need to have an Azure DevOps account.


Here we see a graphical representation of a typical version control setup with remote repositories. Azure DevOps, GitHub, and Bitbucket Cloud are all examples of cloud Git-based remote repositories. A developer with Git installed locally uses Git commands, even if that is via a graphical interface to clone, fetch, fork or pull code from the repository to their local hard drive. They work on the code making changes and saving those changes with accompanying descriptions as commits to their local Git repo. Those commits are then pushed back to the Git structure in the remote repository where they remain until they are merged back into the main trunk through a process called a pull request. A pull request is a process of code review by other developers, preferably two or more followed by a merge operation.

Now I wanna talk about two things that are very closely related, code flow and branching strategies. It's a little bit of a chicken or egg situation, but suffice to say that they are interdependent and one impacts the other. Having said that, there are a number of best practices that should be followed no matter what strategy you adopt.

The master trunk should always be bug-free and a facsimile of what is in production. Branches, be they new features, versions, or bug fixes should have meaningful names and be related to a piece of work like new functionality, a work item, or a sprint. Commits should be frequent, relate to one code change and have an accurate and full description.

Now I want to illustrate with a simple and contrived example of why these best practices should be followed. Remember developers are people and have to read, interpret and review code changes before they are released. We want to add a customer search function to our software. First off, we need to add a branch from our known and good and stable master trunk code with a name describing what the branch is about. It's a new feature called customer search. We could just leave it at that, but in reality, the search is made up of three distinct pieces of functionality.

So we will split that into three branches off the customer search branch. This serves two purposes, firstly keeping each piece of work smaller and more manageable for testing, progress tracking and merging, and secondly if you want different people to work on the pieces simultaneously. Within each of these sub-branches we want work to be committed frequently and often, and I would say that what is illustrated would be the bare minimum. Committing after each piece of logic is completed helps with tracking changes, locating bugs and unwinding code changes if necessary. Each sub-branch is merged back to the customer search branch with a pull request where the code is reviewed.

Not to state the obvious, but reviewing a relatively small piece of code in one or a small handful of files is a relatively simple task as compared with code spread over potentially dozens of files. We've ended up with our code reviewed and successfully merged into the customer branch. This is where some of the branching strategies diverge, and I will look at why in the next section. But for simplicity sake, we can now merge our customer search branch back into the master trunk.

What if we didn't follow these best practices and we created a branch called customer update and assigned the work to a developer? That developer did the work we've just talked about and committed all of it to the update branch with the description, customer changes. Then they submitted a pull request to have their code reviewed and merged. Apart from the already mentioned issue of reviewing a larger chunk of code, where's the history of code changes? If those assigned to review the code don't have an intimate knowledge of this particular piece of work, they have little in the way of description clues to help them. As I've already said, developers are human, so reviewing and merging a relatively large amount of code will greatly increase the possibility of errors. Now, think about that one update branch spread across several developers and then have them merge their work back into the master trunk. In the real world, this scenario would be orders of magnitude bigger in scale and complexity. I really want to hammer home the importance of these simple conventions and how not using them will negate any cleverness you may adopt in your branching strategies.

About the Author
Learning Paths

Hallam is a software architect with over 20 years experience across a wide range of industries. He began his software career as a  Delphi/Interbase disciple but changed his allegiance to Microsoft with its deep and broad ecosystem. While Hallam has designed and crafted custom software utilizing web, mobile and desktop technologies, good quality reliable data is the key to a successful solution. The challenge of quickly turning data into useful information for digestion by humans and machines has led Hallam to specialize in database design and process automation. Showing customers how leverage new technology to change and improve their business processes is one of the key drivers keeping Hallam coming back to the keyboard.