In this two-part article series, I help you learn about, experiment with, and test Git submodules in Azure DevOps. You are reading Part I, in which I help you set up a lab environment so you can get to the actual lab work as quickly as possible.
While working with Azure and Bicep for Infrastructure as Code, I needed to write down instructions I could give DevOps teams on using Git submodules. I noticed that people often lack a lab to learn from. So, I decided to start with an accessible lab environment where they could play with the concept. That way, they get a better grasp of it before they use it anywhere near production. So, let’s dive in!
Prepare a small lab
For this lab, you need two projects in your Aure DevOps organization. You learn about the security settings required to make this work. If you do not have an Azure DevOps account and organization yet, please see Sign up for Azure DevOps – Azure DevOps Services | Microsoft Learn
It is free! Next, you’ll need an Azure tenant to deploy resources. For this lab, you don’t have to. But remember that by using temporary lab email addresses to create Microsoft accounts, you can have successive 30-day trials with 200$ credits for your needs.
Creating the projects
Log in to Azure DevOps and select your organization. Here, you create ProjectOne and ProjectTwo.
You do so by clicking on “New Project” and …
- Fill out the name and description.
- By default, the project is private, which is what we want for this exercise.
- We leave the advanced options on their defaults.
Creating the repositories In Azure DevOps
Now, you need some repositories to work with. So, create three repositories, two of which are in ProjectOne and one in ProjectTwo. The structure looks like this.
ProjectOne
MainRepoProjectOne
SubRepoProjectOne
ProjectOne
SubRepoProjectTwo
Now select ProjectOne. There is a repository called RepoOne that the tooling created for you. Select it, and use the menu to rename it to MainRepoProjectOne.
The second repository, the one for the submodule in ProjectOne, you create yourself.
Note that the repository type defaults to Git, which is what we want. Uncheck “Add a README.” In this lab, we start from an uninitialized repository.
Now, go to ProjectTwo and rename the default repository there to SubRepoProjectTwo.
Create a folder structure for the repositories on our workstation
Create a root folder on your local volume of choice. I do this on OneDrive as I carry my local folder structure over to my desktop(s) or laptop(s) anywhere I log into OneDrive. Granted, this is a bit easier on Windows than on Linux. Windows and Linux support Visual Studio Code, the editor I use.
In the root of your volume (OneDrive, in my case), create one folder
AzureDevOps
In Project AzureDevOps, create one subfolder with the name of your organization.
WorkingHardInIT
In WorkingHardInIT, create two subfolders for projects
ProjectOne
In ProjectOne, create two subfolders
MainRepoProjectOne
SubRepoProjectOne
ProjectTwo
In ProjectTwo, create one subfolder
SubRepoProjectTwo
So you have a structure that looks like below.
That’s it. The repositories are ready to demonstrate using Git submodules in your main Azure DevOps repository. All right!
Visual Studio Code and Git!
Install Visual Studio Code: winget install -e Microsoft.VisualStudioCode
Install Git: winget install -e Git.Git
These are the minimal requirements for the lab exercise. You use extra extensions in Visual Studio Code and possibly other tools for actual work, but this gets you going. While not a hard-core requirement, I also install PowerShell Core.
Install PowerShell Core: winget install Powershell –source winget
Get going with Git and remote repositories
Initialize the git repository locally
I initialize the Git repository locally and push it to Azure DevOps from the command line. You can also use the Git GUI tools or a Visual Studio Git extension. In the root folder of our repository (MainRepoProjectOne), execute the following.
That’s it. Locally, you now have a Git repository. I do something else before creating files and adding and committing them to the remote repositories. I configure my username and email for Git.
Configure the Git username and email
I push work to Azure DevOps or GitHub, which different organizations, businesses, or departments own. If I don’t set a username and email, it uses my local workstation’s user and the user@worktation as the email address. That is messy. If I set that up globally, it uses the same username and email address everywhere, no matter the organization or business. I like to set it to something generic globally but be more specific per Git repository.
So, while in the root of the Git main repository I just created, I executed the lines below.
git config user.name “WorkingHardInIT”
git config user.email workinghardinit@workinghardsmartint.work
So I can have a better-suited name indication and email that matches the organization where the repo lives. It prevents the organization from seeing a name like WorkingHardInIT (Black Bear Consulting) with the email workinghardinit@blackbear.com while committing to their repo at Polar Bear Consulting. You get the idea.
For the global config, I execute the following:
git config –global user.name “Smokey Bear”
git config –global user.email “smokeybear@capitan.bears”
That prevents the username and email in the commits from being autogenerated from the logged-in user and the email address from being generated from the computer’s name, like demouser@windows11vm01.datawisetech.corp or so. Still, it is generic and does not point to one specific organization.
Adding some files and subfolders to the local Git main repository
First, we’ll put a file in the root of our Git repository. I create an HTML file that gets pushed to a remote repo even when that file is empty. A text file needs content. In the root of the Git repository, execute
ni HelloFromMainRepo.html
Next, I create a subfolder and add a file to it. In the root of the Git repository, execute
- md InMainRepo
- cd .\InMainRepo\
- ni HelloFromSubFolderInMainRepo.html
Now let’s look at git status and see what is the status of my repository. Yes, there are changes!
Navigate to the root of the Git repository and run
- git add .
- git commit -m “Added first files and subfolder to MainRepoProjectOne”
Cool. But this main Git repository still only exists on our local machine. I will now push it to the Azure DevOps repository I created earlier. Make sure you are in the root folder of your Git Repo (MainRepoProjectOne) and execute the following.
Navigate to the root of the Git repository and run
- Git remote add origin https://workinghardinit@dev.azure.com/workinghardinit/ProjectOne/_git/MainRepoProjectOne
Now run
- git push -u origin –all
When I refresh the MainRepoProjectOne in Azure DevOps, I see the files and the commit message. The remote repository is now synced with the local changes we made, added, and committed to Git.
I will repeat this process in the folders for the two other repository folders. I list the commands for this setup with a screenshot of the final result.
SubRepoProjectOne
From the root folder for SubRepoProjectOne
- git init
- git config user.name “WorkingHardInIT working on SubRepoProjectOne”
- git config user.email workinghardinit@workinghardinint.work
- git status
- ni HelloFromSubRepoProjectOne.html
- md InSubRepoProjectOne
- cd .\InSubRepoProjectOne\
- ni HelloFromSubFolderInSubRepoProjectOne.html
- Git status
[Navigate back to the root folder SubRepoProjectOne]
- cd ..
- git status
- git add .
- git commit -m “Added first files and subfolder to SubRepoProjectOne”
- git status
- git remote add origin https://workinghardinit@dev.azure.com/workinghardinit/ProjectOne/_git/SubRepoProjectOne
- git push -u origin –all
SubRepoProjectTwo
From the root folder for SubRepoProjectTwo
- git init
- git config user.name “WorkingHardInIT working on SubRepoProjectTwo”
- git config user.email workinghardinit@workinghardinint.work
- git status
- ni HelloFromSubRepoProjectTwo.html
- md InSubRepoProjectTwo
- cd .\InSubRepoProjectTwo\
- ni HelloFromSubFolderInSubRepoProjectTwo.html
- Git status
[Navigate back to the root folder SubRepoProjectTwo]
- cd ..
- git status
- git add .
- git commit -m “Added first files and subfolder to SubRepoProjectTwo”
- git status
- git remote add origin https://workinghardinit@dev.azure.com/workinghardinit/ProjectTwo/_git/SubRepoProjectTwo
- git push -u origin –all
Can I play with submodules now?
Yes! I completed the prep work. In part II we’ll dive into that. But for now, wrap your head around the lab we set up. Practice some basic git commands. Play with a remote repo! See how it behaves. If you break it, don’t worry. Delete the lab and start over. The Git & DevOps scene requires practice and a “wax on – wax off” mentality to learn.
Photo by Yancy Min on Unsplash
Note that I created three independent Git repositories. They exist locally in their dedicated folder structures and separate repositories in two different projects in Azure DevOps.
Let’s learn how to use git log to see what I last did in Git.
- git log
- git log –oneline
I add an extra HTML file to the MainRepoProjectOne root folder
- ni NewFileInMainRepoRoot.html
- git add .
- git commit -m “Added NewFileInMainRepoRoot.html to the MainRepoProjectOne”
I still need to push this to the remote repository in Azure DevOps. For now, the changes are local. In the log, you can see that I added and committed the last file to git. Usually, I’d push this to the remote repository, but I am using it to show the relationship and behavior between the main remote repository and the submodule remote repository.
Now, it’s time for me to add a Git submodule. But that will be for Part II of this series. But do keep reading and follow the flow! Remember that when you close this repo in Visual Studio Code, you can come back and continue anytime. Gits knows where you left off. To be continued in Part II!