<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Nicole Stevens</title>
    <description>The latest articles on Forem by Nicole Stevens (@nicole).</description>
    <link>https://forem.com/nicole</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F312155%2Fd2951500-55f5-4b61-b2d9-9934d9fef30a.png</url>
      <title>Forem: Nicole Stevens</title>
      <link>https://forem.com/nicole</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/nicole"/>
    <language>en</language>
    <item>
      <title>Running MacOS on Windows 10 with WSL2, KVM and QEMU</title>
      <dc:creator>Nicole Stevens</dc:creator>
      <pubDate>Thu, 06 Aug 2020 10:01:20 +0000</pubDate>
      <link>https://forem.com/nicole/running-macos-on-windows-10-with-wsl2-kvm-and-qemu-21e1</link>
      <guid>https://forem.com/nicole/running-macos-on-windows-10-with-wsl2-kvm-and-qemu-21e1</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxy4c3cogi6hm234hz7hu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxy4c3cogi6hm234hz7hu.png" alt="Running MacOS on Windows 10"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note - Unfortunately this no longer works due to movement in the WSL offering for Windows 11 Dev Channel. Am leaving this here incase some of the workarounds for issues below help others in their projects!&lt;/p&gt;

&lt;p&gt;I needed to record a demo on a Mac, I don't own a Mac and was contemplating borrowing one from a friend. Then I realised, I finally had an excuse to give this a go! I've been itching to since I read - &lt;a href="https://boxofcables.dev/accelerated-kvm-guests-on-wsl-2/" rel="noopener noreferrer"&gt;Accelerated KVM guests on WSL 2&lt;/a&gt;, an awesome write-up on how to run accelerated &lt;a href="https://www.redhat.com/en/topics/virtualization/what-is-KVM" rel="noopener noreferrer"&gt;KVM&lt;/a&gt; guests on WSL2 from  &lt;a href="https://twitter.com/unixterminal" rel="noopener noreferrer"&gt;@unixterminal&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a walkthrough of how I used the excellent work of @unixterminal and &lt;a href="https://twitter.com/foxletfox" rel="noopener noreferrer"&gt;@FoxletFox&lt;/a&gt; and got my 3 year old XPS Intel i7 to run MacOS on Windows 10! Without their writeups and scripting this post probably wouldn't exist.&lt;br&gt;
I am still stunned how good the performance is having run through this! I've tried a couple of other Linux distro's too, seriously slick. &lt;/p&gt;

&lt;p&gt;Before starting check out the requirements from the top of the &lt;a href="https://boxofcables.dev/accelerated-kvm-guests-on-wsl-2/" rel="noopener noreferrer"&gt;"Accelerated KVM guests on WSL2"&lt;/a&gt; post. One thing that's not obvious is your CPU needs to support virtualisation. Unless you're running an Intel CPU from the early 2000s or even earlier you should be OK. If your CPU does support virtualization it might not be enabled in your BIOS, it's worth a check before you start. If you're already running a hypervisor, it's likely this is good to go.&lt;/p&gt;

&lt;p&gt;You'll also need to be running a &lt;a href="https://insider.windows.com/en-gb/" rel="noopener noreferrer"&gt;windows insider&lt;/a&gt; build of Windows 10. The insiders Fast ring which is mentioned in the pre-requisites is now the Dev channel. One of the features required didn't come into Windows 10 until build 19619 and the &lt;a href="https://techcommunity.microsoft.com/t5/virtualization/amd-nested-virtualization-support/ba-p/1434841" rel="noopener noreferrer"&gt;nested virtualisation support for AMD&lt;/a&gt; didn't come in until  build 19636 either, so that's a must if you are on AMD too. The &lt;a href="https://insider.windows.com/en-gb/" rel="noopener noreferrer"&gt;windows insider&lt;/a&gt; page currently lists 19042.423 as the highest build available in Beta and 19041.423 as Release Preview, so for the moment this will not work correctly without using the Dev channel.&lt;/p&gt;

&lt;p&gt;The insider channel renaming is &lt;a href="https://blogs.windows.com/windowsexperience/2020/06/15/introducing-windows-insider-channels/" rel="noopener noreferrer"&gt;described here&lt;/a&gt;. Dev channel is described as &lt;em&gt;Ideal for highly technical users. Insiders in the Dev Channel will receive builds that is earliest in a development cycle and will contain the latest work-in-progress code from our engineers. These builds will have rough edges and some instability that could block key activities or require workarounds.&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;With this in mind, think twice about running the Dev channel on your main machine, or if you wouldn't consider yourself a highly technical user! If you're OK with that, dive right in :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Follow the steps in &lt;a href="https://boxofcables.dev/accelerated-kvm-guests-on-wsl-2/" rel="noopener noreferrer"&gt;"Accelerated KVM guests on WSL2"&lt;/a&gt; until you reach the section titled &lt;strong&gt;Important note about building a module in WSL:&lt;/strong&gt; Time was fairly tight for getting this up and running, I wasn't going to be tweaking performance and I didn't want to keep loading the KVM for Intel module manually, so:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9n40irq0t6tj5ucti6wh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9n40irq0t6tj5ucti6wh.png" alt="Virtualisation options"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;KVM for Intel processors was selected as above, note that the AMD selection is below it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Carry on from "Exit the Virtualization" paragraph until you get to this command:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

 kvm-ok


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you've followed the steps carefully and hit all the pre-reqs when you execute kvm-ok you should see:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

INFO: /dev/kvm exists
KVM acceleration can be used


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If not you are likely to see:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

INFO: Your CPU does not support KVM extensions
KVM acceleration can NOT be used


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you are seeing the above you are definitely running a Windows 10 Dev channel, run back through the steps once more, you might have missed something.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check nested KVM is OK&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're getting "KVM acceleration can be used" you can proceed with the steps in the post.&lt;/p&gt;

&lt;p&gt;The next steps is:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;cat&lt;/span&gt; /sys/module/kvm_intel/parameters/nested


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;When executing this command N was being returned. Having traced back through the steps it was time for a search which yielded an &lt;a href="https://github.com/microsoft/WSL/issues/4193#issuecomment-647003288" rel="noopener noreferrer"&gt;issue from the WSL github repo&lt;/a&gt;. So reverting back to the step &lt;strong&gt;Install your kernel in WSL 2 and enable nested KVM&lt;/strong&gt; the .wslconfig was changed to:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;nestedVirtualization&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true
&lt;/span&gt;&lt;span class="nv"&gt;kernel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;C:&lt;span class="se"&gt;\\&lt;/span&gt;Users&lt;span class="se"&gt;\\&lt;/span&gt;&amp;lt;username&amp;gt;&lt;span class="se"&gt;\\&lt;/span&gt;bzImage
&lt;span class="nv"&gt;debugConsole&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true
&lt;/span&gt;&lt;span class="nv"&gt;pageReporting&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true
&lt;/span&gt;&lt;span class="nv"&gt;kernelCommandLine&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;intel_iommu&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;on &lt;span class="nv"&gt;iommu&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pt kvm.ignore_msrs&lt;span class="o"&gt;=&lt;/span&gt;1 kvm-intel.nested&lt;span class="o"&gt;=&lt;/span&gt;1 kvm-intel.ept&lt;span class="o"&gt;=&lt;/span&gt;1 kvm-intel.emulate_invalid_guest_state&lt;span class="o"&gt;=&lt;/span&gt;0 kvm-intel.enable_shadow_vmcs&lt;span class="o"&gt;=&lt;/span&gt;1 kvm-intel.enable_apicv&lt;span class="o"&gt;=&lt;/span&gt;1



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You'll need to restart WSL once more and check the command once more.&lt;/p&gt;

&lt;p&gt;Note the command line args are almost identical to those added to kvm_intel.conf, I haven't investigated why the nested setting isn't picked up from the conf file.&lt;/p&gt;

&lt;p&gt;Also note that setting debugConsole opens up the WSL debug console, you can turn this and pageReporting off later by removing them from the .wslconfig file and restarting WSL. I left it in for a while in case I needed to troubleshoot further.&lt;/p&gt;

&lt;p&gt;The check for nested KVM now returned a Y as required:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;cat&lt;/span&gt; /sys/module/kvm_intel/parameters/nested
Y


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Config X for WSL2.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Having run a far few X servers in the past I just wanted something that just worked without a lot of setup. Therefore, I went for X410 which is £9ish in the Microsoft store, but as I'm planning to use this until GUI support comes out later in the year, it was worth the price for the easy setup.&lt;/p&gt;

&lt;p&gt;Install as normal in the store then add the environment variable in the steps to your .bashrc:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;cd&lt;/span&gt; ~
nano .bashrc


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwdmt5qpsbip1stm4i4vw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwdmt5qpsbip1stm4i4vw.png" alt="Add DISPLAY environment variable to .bashrc"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once nested KVM is up and running and you've configured WSL to send X output to windows, you are ready to try a distro. If you keep following the post at this point you'll set up an Ubuntu 20.10 daily build. I ran through this as a check to see if everything was working, the steps for this were exactly the same as in the post.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Setup for MacOS VM&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;a href="https://github.com/foxlet/macOS-Simple-KVM" rel="noopener noreferrer"&gt;MacOS-Simple-KVM&lt;/a&gt; GitHub repo is linked from the original post. It is described as "set up a simple macOS VM in QEMU, accelerated by KVM." If you ran through setting up the Ubuntu 20.10 daily build in step 4 you'll already have seen &lt;a href="https://www.packetflow.co.uk/what-is-the-difference-between-qemu-and-kvm" rel="noopener noreferrer"&gt;QEMU&lt;/a&gt;  being mentioned. You might be thinking, why are there two types of virtualization technologies? The key part is in how KVM and QEMU differ, which is summed up nicely in this &lt;a href="https://www.packetflow.co.uk/what-is-the-difference-between-qemu-and-kvm" rel="noopener noreferrer"&gt;post&lt;/a&gt;. KVM uses the CPU virtualization extensions for Intel and AMD, and QEMU is performing the virtual hardware emulation, or to put it another way, KVM is QEMU's "go faster stripes"!&lt;/p&gt;

&lt;p&gt;The steps were followed as listed but with the following tweaks. First clone the git repo in, make sure to use the linux filesystem as it is &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/compare-versions#use-the-linux-file-system-for-faster-performance" rel="noopener noreferrer"&gt;faster&lt;/a&gt; at the moment on wsl2 than windows (/mnt).&lt;/p&gt;

&lt;p&gt;This walkthrough is using Ubuntu so it's the top line to install QEMU, Python and Pip if you haven't already got them:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;qemu-system qemu-utils python3 python3-pip


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Run jumpstart.sh to fetch the MacOS media of your choice:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

./jumpstart.sh &lt;span class="nt"&gt;--mojave&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I also went with Mojave.&lt;/p&gt;

&lt;p&gt;Now create a hard disk, I went with 32GB, I wanted to try and go a little lower but on investigation I found some issues logged where less than 32GB looked to be creating issues for other users:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

qemu-img create &lt;span class="nt"&gt;-f&lt;/span&gt; qcow2 MacOS.qcow2 32G


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Note I've changed the name of my disk, by this point I had a few VM's setup so wanted to make it more obvious! &lt;/p&gt;

&lt;p&gt;Edit basic.sh to add the VM disk into the VM :&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

    &lt;span class="nt"&gt;-drive&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;SystemDisk,if&lt;span class="o"&gt;=&lt;/span&gt;none,file&lt;span class="o"&gt;=&lt;/span&gt;MacOS.qcow2 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-device&lt;/span&gt; ide-hd,bus&lt;span class="o"&gt;=&lt;/span&gt;sata.4,drive&lt;span class="o"&gt;=&lt;/span&gt;SystemDisk &lt;span class="se"&gt;\&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now make sure the X server from step 4 is running as QEMU will try and use graphics mode by default. If it isn't running when you run basic.sh in this next step it'll have for a minute or so then fail:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

./basic.sh


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The VM boots but there are some errors:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fec63zhfd1xnl9j86g9ba.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fec63zhfd1xnl9j86g9ba.png" alt="Errors running basic.sh"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The top section boxed in red is caused by the -cpu line in &lt;a href="http://basic.sh" rel="noopener noreferrer"&gt;basic.sh&lt;/a&gt;. The standard settings in the basic.sh file are sending instructions around performance enhanced features to the host CPU which it &lt;a href="https://www.linux-kvm.org/page/Tuning_KVM" rel="noopener noreferrer"&gt;cannot understand&lt;/a&gt;.  The box in green are errors related to sound, I'm not so worried about those, and explain my sound related issues with Ubuntu above. You can edit basic.sh further to straighten these out, but the VM still booted with these errors present.&lt;/p&gt;

&lt;p&gt;The VM boots to the Clover boot manager, where you can use your keyboard to hit return (no mouse at this point) and "Boot macOS Install from macOS Base System" will begin:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fir12bk5gk4f9y4zxjukv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fir12bk5gk4f9y4zxjukv.png" alt="Clover boot manager"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The macOS utilities screen is now displayed and you should have mouse support.  If your mouse pointer is out of synchronisation with the one on the VM you will need to adjust the settings in the basic.sh file. Shut the VM down using the apple icon top left and edit basic.sh in nano once more:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frodofnejdggpg1br5s7u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frodofnejdggpg1br5s7u.png" alt="Setting the usb device to tablet"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The usb device line needs to be altered from usb-mouse to usb-tablet. Run basic.sh once more and your mouse should now align.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj0x1z15bby2a9vuhuqpq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj0x1z15bby2a9vuhuqpq.png" alt="Using Disk Utility"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As mentioned in the steps from the &lt;a href="https://github.com/foxlet/macOS-Simple-KVM" rel="noopener noreferrer"&gt;macOS-Simple-KVM&lt;/a&gt; instructions, you need to partition the disk first. If you enter Disk Utility, find your QEMU HARDDISK from the left hand menu and Erase it and partition it.&lt;/p&gt;

&lt;p&gt;You can now return back to the macOS Utilities menu and choose Reinstall macOS, from here it is the same as a standard reinstall, this does take quite a while! No further tweaks were required from this point on:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhghfixdqvbni7aampydu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhghfixdqvbni7aampydu.png" alt="Install complete"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can move in and out of fullscreen with ctrl+alt+backspace and remove the VM banner with "Machine View" at the top with ctrl+alt+F.&lt;/p&gt;

&lt;p&gt;If you now leave your setup as-is with no further tweaks you will be sent into the Clover bootloader each time you reboot or run your VM:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxudk9bi11zip80nfwp2u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxudk9bi11zip80nfwp2u.png" alt="Clover with multiple disks"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've got a few more options to choose from than you will have as I'd been playing around with things before I took this. The key thing is you need to use the arrow keys to choose "Boot macOS from macOS", this will boot your install and you are good to go!&lt;/p&gt;

</description>
      <category>wsl2</category>
      <category>windows</category>
      <category>macos</category>
      <category>wsl</category>
    </item>
    <item>
      <title>Windows Terminal - port a scheme from iTerm2, customise your own scheme and use a custom font</title>
      <dc:creator>Nicole Stevens</dc:creator>
      <pubDate>Wed, 20 May 2020 19:09:55 +0000</pubDate>
      <link>https://forem.com/nicole/windows-terminal-port-a-scheme-from-iterm2-customise-your-own-scheme-and-use-a-custom-font-fga</link>
      <guid>https://forem.com/nicole/windows-terminal-port-a-scheme-from-iterm2-customise-your-own-scheme-and-use-a-custom-font-fga</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://devblogs.microsoft.com/commandline/windows-terminal-1-0/"&gt;Windows Terminal 1.0&lt;/a&gt; was released at Microsoft Build 2020. There are &lt;a href="https://docs.microsoft.com/en-us/windows/terminal/customize-settings/color-schemes"&gt;docs&lt;/a&gt; on how to customise your theme and &lt;a href="https://terminalsplash.com/"&gt;sites&lt;/a&gt; to download them from. But what if you want to use different fonts and a scheme that's not available to just copy?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yNLjUpv_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1o1dslttnaqu35l37eu8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yNLjUpv_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1o1dslttnaqu35l37eu8.png" alt="My Windows Terminal Ubuntu"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is &lt;a href="https://www.microsoft.com/en-gb/p/windows-terminal/9n0dx20hk701?activetab=pivot:overviewtab"&gt;Windows Terminal&lt;/a&gt; with the awesome &lt;a href="https://marketplace.visualstudio.com/items?itemName=robertrossmann.remedy"&gt;Remedy Theme&lt;/a&gt; from VSCode, which isn't readily available for Windows Terminal. The font is &lt;a href="https://github.com/tonsky/FiraCode"&gt;Fira Code&lt;/a&gt; which contains &lt;a href="https://en.wikipedia.org/wiki/Orthographic_ligature"&gt;ligature&lt;/a&gt; support, converting multi-character representations to &lt;a href="https://github.com/tonsky/FiraCode#whats-in-the-box"&gt;glyphs&lt;/a&gt;. This is how the prompt displays icons for Git, using &lt;a href="https://github.com/justjanne/powerline-go"&gt;powerline-go&lt;/a&gt; setup for bash.&lt;/p&gt;

&lt;p&gt;This page is a walkthrough of how to set this configuration up, port themes from other terminals along with finding standard schemes for download. There's also a brief introduction on Powerline enabled fonts and where to download them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-reqs
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Download &lt;a href="https://www.microsoft.com/en-gb/p/windows-terminal/9n0dx20hk701?activetab=pivot:overviewtab"&gt;Windows Terminal&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Download &lt;a href="https://github.com/tonsky/FiraCode/releases/download/4/Fira_Code_v4.zip"&gt;Fira Code Font&lt;/a&gt; - note Light &lt;a href="https://github.com/tonsky/FiraCode/issues/941"&gt;isn't working&lt;/a&gt; with ligatures&lt;/li&gt;
&lt;li&gt;Download latest &lt;a href="https://github.com/robertrossmann/vscode-remedy/blob/master/resources/iTerm2/Remedy%20-%20Dark.itermcolors"&gt;Remedy iTerm Colors file&lt;/a&gt; and place into convert_color folder in &lt;a href="https://github.com/stevensnicole/winterm-themes"&gt;this repo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Download &lt;a href="https://code.visualstudio.com/download"&gt;Visual Studio Code&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Windows terminal settings and using a readily available scheme from GitHub
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kFZ4dd7z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/li7mqlyizyrtdegy9u9j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kFZ4dd7z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/li7mqlyizyrtdegy9u9j.png" alt="My Windows Terminal Cmd"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a themed command prompt profile, it's a good place to start as it uses a scheme readily available to copy from GitHub called &lt;a href="https://github.com/mbadolato/iTerm2-Color-Schemes/blob/master/windowsterminal/Firewatch.json"&gt;Firewatch&lt;/a&gt;. If you click on the down arrow at the top of your windows terminal, your Windows Terminal menu opens. At the bottom of the menu is Settings:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CuR6hQeB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2qdxb3gdm7t6ek8cd669.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CuR6hQeB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2qdxb3gdm7t6ek8cd669.png" alt="Windows Terminal Settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose Settings and the settings.json file will open for editing in VSCode. There are some great &lt;a href="https://docs.microsoft.com/en-us/windows/terminal/customize-settings/global-settings"&gt;msdocs&lt;/a&gt; on how to edit your settings. Here you are going to start by adding a new scheme.  Schemes are added into the schemes section of the settings.json file, which is near the bottom of the page: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6tSygqV_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xmwnn55nk3upcdrmuzku.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6tSygqV_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xmwnn55nk3upcdrmuzku.png" alt="Windows Terminal Settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy the &lt;a href="https://github.com/mbadolato/iTerm2-Color-Schemes/blob/master/windowsterminal/Firewatch.json"&gt;Firewatch&lt;/a&gt; scheme, including the curly braces and paste it into the settings.json between the square brackets, it should now look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xbx0fbGZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/u6nf6j9qiv8mzrq1rgdw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xbx0fbGZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/u6nf6j9qiv8mzrq1rgdw.png" alt="Windows Terminal Settings with Firewatch"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you don't like the look of that scheme, go up a level in the GitHub repo, there are hundreds more, with screenshots &lt;a href="https://github.com/mbadolato/iTerm2-Color-Schemes"&gt;here&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;The scheme is named "Firewatch", this name is used to reference the scheme. The reference can be used in the default profile, which will apply it to all profiles, or a single profile. A profile is each terminal type that has been set up in Windows Terminal, such as Command Prompt, Powershell or &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/faq"&gt;WSL&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this example, the firewatch scheme is only to be applied to the command prompt. Scroll up in the settings.json file until you see &lt;em&gt;// Make changes here to the cmd.exe profile.&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PJ7rICaG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uaejjfq43bk4cb8iu9ta.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PJ7rICaG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uaejjfq43bk4cb8iu9ta.png" alt="Windows Terminal Settings Cmd"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To reference the firewatch scheme add&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;"colorScheme": "Firewatch"&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
 into the cmd.exe profile, make sure you add a comma after&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;"hidden": false,&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q6IowUkx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ee4pna0hzy2mmkmpcd8d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q6IowUkx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ee4pna0hzy2mmkmpcd8d.png" alt="Windows Terminal Settings Cmd"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save the file, if you have the Command Prompt open in your windows terminal it will change automatically. Note that settings at the profile level override those at the default level.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting up your own theme and converting one from iTerm2
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Creating your own Scheme
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://docs.microsoft.com/en-us/windows/terminal/customize-settings/color-schemes"&gt;color schemes&lt;/a&gt; section of msdocs gives the format required to create your own scheme. You can paste a second section into the schemes array (the square brackets) and give it a name other than one that already exists. For example, this could be "powershellScheme", add the named reference to another profile using&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;"colorScheme": "powershellScheme"&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
. Now as you edit the hex representation of the colours for powershellScheme and save the file, the changes will be displayed immediately in Windows Terminal.&lt;/p&gt;
&lt;h3&gt;
  
  
  Conversion from iTerm2
&lt;/h3&gt;

&lt;p&gt;Another way is to take a theme from a different terminal. The schemes structure uses a JSON variant of the iTerm2 colour scheme format. This format can be ported for use by many terminals as listed on the &lt;a href="https://github.com/mbadolato/iTerm2-Color-Schemes"&gt;iTerm2-Color-Schemes&lt;/a&gt; GitHub page. The scheme displayed on the first screenshot in this page is from the &lt;a href="https://marketplace.visualstudio.com/items?itemName=robertrossmann.remedy"&gt;Remedy&lt;/a&gt; VSCode theme. The &lt;a href="https://github.com/robertrossmann/vscode-remedy"&gt;Remedy GitHub repo&lt;/a&gt; contains the &lt;a href="https://github.com/robertrossmann/vscode-remedy/blob/master/resources/iTerm2/Remedy%20-%20Dark.itermcolors"&gt;.itermcolors&lt;/a&gt; file which enables the same theme in iTerm2. You can also export schemes directly from iTerm2 to .itermcolor files.&lt;/p&gt;

&lt;p&gt;The .itermcolors file looks complicated, but it can be ported for use in Windows Terminal using an itermcolors to hex convertor. There are many scripts available to do this on various sites, for this walkthrough a &lt;a href="https://github.com/charliebillen/ConvertItermColoursToHex"&gt;PowerShell converter&lt;/a&gt; example and a &lt;a href="https://gitlab.com/hackebrot/palette"&gt;go convertor&lt;/a&gt; will be shown.&lt;/p&gt;
&lt;h4&gt;
  
  
  Conversion with PowerShell
&lt;/h4&gt;

&lt;p&gt;For PowerShell, download the &lt;a href="https://raw.githubusercontent.com/charliebillen/ConvertItermColoursToHex/master/ConvertFrom-ItermColoursToHex.psm1"&gt;ConvertFrom-ItermColoursToHex.psm1&lt;/a&gt; and save as a file of the same name. To load in the module, open a PowerShell terminal and from inside the same folder you downloaded the psm1 file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Import-Module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;/ConvertFrom-ItermColoursToHex.psm1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GMvXiN7H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ut8mjcddycypn2a5ruk3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GMvXiN7H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ut8mjcddycypn2a5ruk3.png" alt="Load PowerShell Module"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the module imported, it can be used to convert a .itermcolors file. You'll need to have an .itemcolors file to convert in the directory you run the following command from. Step 3 in the prereqs has the GitHub repo for Remedy Dark, which has been renamed to "remedy-dark.itermcolors"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;Get-Content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;/remedy-dark.itermcolors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ConvertFrom-ItermColoursToHex&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JvXikZr6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1zeidoze2dg0knaoa0ra.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JvXikZr6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1zeidoze2dg0knaoa0ra.png" alt="Convert with PowerShell"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The names listed correspond to the equivalents in the Windows Terminal scheme. Open the settings file within Windows Terminal once more. Copy a scheme within the settings.json file and rename the scheme as "Remedy-dark". Now match up the names and overwrite the hex values as shown, note they are not in the correct order:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8h8N4kha--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tgxhowqpr4fv6p53ij5w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8h8N4kha--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tgxhowqpr4fv6p53ij5w.png" alt="Remedy Dark"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Assign the name reference to a profile, in this case, I'd like the scheme to be my default colour scheme. Scroll to the top of the page and add&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;"colorScheme": "remedyDark"&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
 into the defaults section:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RYPyyhWj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/aakyck8wsm600eyv1nuw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RYPyyhWj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/aakyck8wsm600eyv1nuw.png" alt="Default Scheme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save the file, and all of the profiles will have the same theme, unless you have a colour scheme defined at the profile level.&lt;/p&gt;
&lt;h4&gt;
  
  
  Conversion with Go
&lt;/h4&gt;

&lt;p&gt;To complete the same steps using go on a Ubuntu WSL distro. Install go if you don't already have it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;golang-go
go version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Download the &lt;a href="https://gitlab.com/hackebrot/palette/-/raw/master/palette.go"&gt;palette.go&lt;/a&gt; file and save as a file of the same name. With go setup, you can run the script. Note you'll need to have an .itemcolors file to convert in the directory along with your palette.go script. Step 3 in the prereqs has the GitHub repo for Remedy Dark itermcolors file, which has been renamed to "remedy-dark.itermcolors". In the same Ubuntu WSL distro that you installed go on, cd to the directory with your script and color file in and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run palette.go &lt;span class="nt"&gt;-colors&lt;/span&gt; remedy-dark.itermcolors
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fty0dQ6g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/apizbc0uzuyput3jw3h8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fty0dQ6g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/apizbc0uzuyput3jw3h8.png" alt="Remedy Dark in go"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The output this time is slightly different, the hex values are in the correct order, but the names do not tally. "Ansi 0 Color" is "black", "Ansi 1 Color" is "red" and so on. Copy a scheme within the settings.json file and rename the scheme as "Remedy-dark". Now match up the top 16 rows and overwrite the hex values as shown, then copy "Background Color" into "Background" and "Foreground Color" into Foreground.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8h8N4kha--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tgxhowqpr4fv6p53ij5w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8h8N4kha--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tgxhowqpr4fv6p53ij5w.png" alt="Remedy Dark"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Assign the name reference to a profile, in this case, I'd like the scheme to be my default colour scheme. Scroll to the top of the page and add&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;"colorScheme": "remedyDark"&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
 into the defaults section:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fty0dQ6g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/apizbc0uzuyput3jw3h8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fty0dQ6g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/apizbc0uzuyput3jw3h8.png" alt="Default Scheme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save the file, and all of the profiles will have the same theme, unless you have a colour scheme defined at the profile level.&lt;/p&gt;
&lt;h2&gt;
  
  
  Changing your font
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/microsoft/cascadia-code"&gt;Cascadia Code&lt;/a&gt; became the default font for all profiles automatically generated by Windows Terminal in release 0.11. Cascadia Code is an awesome font for developers, but I'm a fan of &lt;a href="https://github.com/tonsky/FiraCode"&gt;Fira Code&lt;/a&gt; and &lt;a href="https://www.jetbrains.com/lp/mono/"&gt;JetBrains Mono&lt;/a&gt;. If you &lt;a href="https://github.com/tonsky/FiraCode/releases/download/4/Fira_Code_v4.zip"&gt;downloaded FiraCode&lt;/a&gt; and installed the fonts from the pre-reqs steps you are ready to go.&lt;/p&gt;

&lt;p&gt;Open your Windows Terminal settings once more and scroll to the defaults section for profiles, this will set the same font for all of your profiles. Add the following into defaults:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"fontFace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fira Code"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fontSize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QOr_ZJ62--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qocqhmu8lepe2i4zqwgs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QOr_ZJ62--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qocqhmu8lepe2i4zqwgs.png" alt="Default Scheme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save the file and the font settings will be applied.&lt;/p&gt;

&lt;p&gt;As described in the introduction, Fira Code contains Powerline Glyphs, which means it will automatically show the special characters in my prompt (See the "What about a funky prompt!" section below). If you are sticking with Cascadia Code, you'll need to &lt;a href="https://github.com/microsoft/cascadia-code/releases"&gt;download&lt;/a&gt; the Cascadia Code PL fonts which are not shipped with Windows Terminal. The process to install and use the font is the same as above, except the fontFace is&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;"fontFace": "Cascadia Code PL"&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;You don't have to stick with Cascadia Code or Fira Code either, the &lt;a href="https://github.com/powerline/fonts"&gt;Powerline Fonts&lt;/a&gt; GitHub repo contains many fonts that have been patched for Powerline.&lt;/p&gt;

&lt;p&gt;Note - if your fonts don't automatically load after you've shut WIndows Terminal down and re-opened it, I found that installing the Font for all fixed this. I haven't looked into why.&lt;/p&gt;

&lt;p&gt;If you are running Windows Terminal 1.1 preview or above and have a font that support it, you can now also specify a weight:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"fontFace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fira Code"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fontSize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fontWeight"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"light"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What about a funky prompt!
&lt;/h2&gt;

&lt;p&gt;There are a few ways to do this, however, msdocs has a good &lt;a href="https://docs.microsoft.com/en-us/windows/terminal/tutorials/powerline-setup"&gt;tutorial&lt;/a&gt; which is how the prompt in these screenshots is setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  SSH With Windows Terminal profile
&lt;/h2&gt;

&lt;p&gt;Thomas Maurer has a great &lt;a href="https://www.thomasmaurer.ch/2020/05/how-to-ssh-into-an-azure-vm-from-windows-terminal-menu/"&gt;tutorial&lt;/a&gt; on how to set up profiles to SSH you straight in, it focuses on Azure VM's but the&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;commandline&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
 can be altered to any address.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>terminal</category>
      <category>shell</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Create an Azure Pipeline for a .NET Core Webapp and configure for Continuous Integration (CI)</title>
      <dc:creator>Nicole Stevens</dc:creator>
      <pubDate>Mon, 06 Apr 2020 15:27:06 +0000</pubDate>
      <link>https://forem.com/cloudskills/create-an-azure-pipeline-for-a-net-core-webapp-and-configure-for-continuous-integration-ci-4a3n</link>
      <guid>https://forem.com/cloudskills/create-an-azure-pipeline-for-a-net-core-webapp-and-configure-for-continuous-integration-ci-4a3n</guid>
      <description>&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;Step 1 - Setup the ASP.NET Core Webapp project&lt;/li&gt;
&lt;li&gt;Step 2 - Understanding the build and publish process&lt;/li&gt;
&lt;li&gt;Step 3 - Create a build pipeline&lt;/li&gt;
&lt;li&gt;Step 4 - Manually running a pipeline&lt;/li&gt;
&lt;li&gt;Step 5 - Configuring for Continuous Integration&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Create an Azure Pipeline for a .NET Core Webapp and configure for Continuous Integration (CI)
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;In parts &lt;a href="https://dev.to/cloudskills/getting-started-with-git-and-azure-devops-1i7a"&gt;one&lt;/a&gt; and &lt;a href="https://dev.to/cloudskills/working-with-the-feature-branch-workflow-and-pull-requests-27pi"&gt;two&lt;/a&gt; of this guide, you have been working with editing the &lt;code&gt;readme.md&lt;/code&gt; and pushing markdown changes to your Azure DevOps repo. To create a build pipeline in Azure DevOps you are going to need to work with some code.&lt;/p&gt;

&lt;p&gt;In this part of the guide, you will install .Net Core and configure a .Net Core webapp project so that only the parts of the project that require to be under source control are stored in your Azure DevOps Repo. You will examine how the build process you use on your machine needs to be mirrored in an Azure DevOps Pipeline for a successful build. There is a key takeaway from this exercise, no matter the language used, the process to build locally needs to be mapped to the Azure Pipeline.&lt;/p&gt;

&lt;p&gt;Once your build process has been mirrored you will automate the process which runs the build. These steps are the start of a journey towards Continuous integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Before working through this guide you will need the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;An &lt;a href="https://azure.microsoft.com/en-us/"&gt;Azure Subscription&lt;/a&gt;, you can create a free account.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An &lt;a href="http://dev.azure.com/"&gt;Azure DevOps Organisation&lt;/a&gt;, the basic plan starts with the first five users for free.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A local installation of &lt;a href="https://git-scm.com"&gt;Git&lt;/a&gt;, following the &lt;a href="https://git-scm.com/book/en/v2/Getting-Started-Installing-Git"&gt;install guide&lt;/a&gt; for your OS. If you are using Windows, ensure the box is checked to &lt;strong&gt;Enable Git Credential Manager&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8ks-QeCw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1q4a96jp7fcbukala2f9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8ks-QeCw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1q4a96jp7fcbukala2f9.png" alt="Enable Git Credential Manager"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you installed VSCode before Git, you will also be presented with this option:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--C_0fkoDv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uyabdmu1z9z5ngxsj153.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C_0fkoDv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uyabdmu1z9z5ngxsj153.png" alt="Choosing the default editor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This allows you to launch VSCode as the default code editor or difference tool, straight from git on the command line.  Please leave as VSCode for this guide, you can reinstall later to pick a different IDE.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;An installation of &lt;a href="https://dotnet.microsoft.com/download"&gt;.NET Core&lt;/a&gt;, choose to Download .NET Core SDK for your OS and install. Once the installation is complete open a new command window and check .NET Core was installed properly by entering the command &lt;code&gt;dotnet&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qfSAKufE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vzk4hhuutuo7j6log704.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qfSAKufE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vzk4hhuutuo7j6log704.png" alt="Checking the .NET Core install"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you receive the output about from dotnet help, the installation was successful.  If you receive the following error:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--csG5xLDi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gelx9tpnnftteccy1x43.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--csG5xLDi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gelx9tpnnftteccy1x43.png" alt=".NET Core install path error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sure you open a new command window and try the command once more.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1 — Setup the ASP.NET Core Webapp project &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;As part of the pre-requisites, you installed .Net Core SDK ready to build a .Net Core project. To help understand how the Azure DevOps build pipeline is built, you'll look at some of the functionality of the .Net Core CLI. Once you've explored some of the key commands for the .Net Core CLI, you will create a new .Net Core Webapp project and configure the project for pushing to an Azure DevOps Repo.&lt;/p&gt;

&lt;p&gt;.Net Core is cross-compatible across operating systems, this means you can run it on Windows, MacOS or Linux. When you installed .Net Core, the .Net Core CLI was automatically installed by the install process. This gives you access to the commands required to develop, build, run and publish .Net Core applications from the command line. You can fire up a command prompt, terminal on Linux or a Powershell/command terminal in Windows and use the same &lt;code&gt;dotnet&lt;/code&gt; commands. The .Net Core CLI can also be called by graphical IDE's such as Visual Studio or Visual Studio Code, opening up access to the same commands from a user interface.&lt;/p&gt;

&lt;p&gt;Open up your command line of choice and execute the command from the pre-requisites &lt;code&gt;dotnet&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dk2vi0SS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ik56w40535axgb3v4g7y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dk2vi0SS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ik56w40535axgb3v4g7y.png" alt="dotnet command"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Previously you used this command to check that the .Net Core SDK had installed correctly. The &lt;code&gt;dotnet&lt;/code&gt; is the &lt;em&gt;driver&lt;/em&gt; command, it will always be the first word when working with the .Net Core CLI on the command line. The driver command will either execute a command or run a .Net Core app. When executed on its own as shown above, the &lt;code&gt;dotnet&lt;/code&gt; driver command gives instructions on how to get more help. Options can be added to the command, for example, the &lt;code&gt;dotnet&lt;/code&gt; driver command can take &lt;code&gt;--version&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RI1-Jt4i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/czvgtksujtefb137fwjo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RI1-Jt4i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/czvgtksujtefb137fwjo.png" alt="dotnet help command"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Taking the option of &lt;code&gt;--help&lt;/code&gt; from the driver command instructions listed above you can see the commands that can be executed with the dotnet driver. Enter &lt;code&gt;dotnet --help&lt;/code&gt; into your command line to explore this further:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LfmSbaRu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wmgupfqrxa01lnuwvhjq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LfmSbaRu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wmgupfqrxa01lnuwvhjq.png" alt="dotnet help command"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a full list of commands and their usage visit the Microsoft Docs &lt;a href="https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet"&gt;dotnet command reference&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Scanning up through the SDK commands you can see &lt;code&gt;new&lt;/code&gt; is listed, with the description stating this is the command to create a new .Net project. Each of these commands can take the &lt;code&gt;--help&lt;/code&gt; option to view help on their usage. Use &lt;code&gt;dotnet new --help&lt;/code&gt; to view the help on the &lt;code&gt;new&lt;/code&gt; command:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pXBMgp23--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/g2ktlrn1pfhncko2p4uq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pXBMgp23--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/g2ktlrn1pfhncko2p4uq.png" alt="dotnet new options"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The output here is split into three sections. The screenshot above shows the first section. These are the options. You can filter the template names using &lt;code&gt;--list&lt;/code&gt; or check for locally installed template updates with &lt;code&gt;--update-check&lt;/code&gt;. The option &lt;code&gt;--language&lt;/code&gt; allows you to pick between C#, F# or VB where the &lt;em&gt;template&lt;/em&gt; supports it, with C# being the default. To examine what templates are available, here is the middle section of the help output, the list of available templates:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uYon4sCK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7lyd5up06h39namti2x9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uYon4sCK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7lyd5up06h39namti2x9.png" alt="dotnet new templates"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The command &lt;code&gt;dotnet new&lt;/code&gt; uses the templates listed to create .Net Core projects based on the specified template. The template creates a project which will contain all of the files required to start building the application. Looking at the output above, the first column is the full template name, which gives the best description of what the template is for. The second column, Short Name, is the template name used when calling &lt;code&gt;dotnet new&lt;/code&gt;.&lt;br&gt;
For example, looking at the top line of the output, executing &lt;code&gt;dotnet new console&lt;/code&gt;, will create a project containing all of the files required to start building a console application.&lt;br&gt;
The third column displays whether F# and VB are available for the selected template. Taking the top line of the output once more &lt;code&gt;dotnet new console --language F#&lt;/code&gt; will create a .Net Core project that can be used to build a console application in F#. For this guide you will be building a Web Application in Azure DevOps, therefore, &lt;code&gt;webapp&lt;/code&gt; is the template name you will use when executing &lt;code&gt;dotnet new&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JJxf7y6e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/iqbrb5qbn9uch5xkijd1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JJxf7y6e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/iqbrb5qbn9uch5xkijd1.png" alt="dotnet new examples"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The final section of the &lt;code&gt;dotnet new&lt;/code&gt; output lists examples of how to use the command. Above are examples creating a model view controller app &lt;code&gt;mvc&lt;/code&gt; and a &lt;a href="https://www.nuget.org/"&gt;nuget&lt;/a&gt; config file &lt;code&gt;nugetconfig&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;You are now ready to create the project for the webapp. Change directory on your command line to the dotnetcoredemo git repo you linked to an Azure DevOps Repo in &lt;a href="https://dev.to/cloudskills/getting-started-with-git-and-azure-devops-1i7a"&gt;part one&lt;/a&gt; of this guide. If you have not followed part one, run through &lt;a href="https://dev.to/cloudskills/getting-started-with-git-and-azure-devops-1i7a"&gt;Step 1 - Setup a Repo in Azure DevOps&lt;/a&gt; to create the required Azure DevOps Project and Repo. &lt;br&gt;
List the contents of the repo using &lt;code&gt;dir /a /b&lt;/code&gt; on windows or &lt;code&gt;ls -al&lt;/code&gt; on a Mac or Linux:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MGdhg0nb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tfb1ttj3p3kbifarijw5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MGdhg0nb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tfb1ttj3p3kbifarijw5.png" alt="dir on repo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The local repository is pretty much empty, it has the readme you edited in the previous part of this guide and the .gitignore created by Azure DevOps. Create the .Net Core Webapp project files in this directory using &lt;code&gt;dotnet new webapp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DBoAiqVo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/q48bf4spkkbx1sgbvlpw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DBoAiqVo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/q48bf4spkkbx1sgbvlpw.png" alt="dotnet new webapp"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;dotnet new webapp&lt;/code&gt; command recreates the template structure in the directory it is run from, and then restores required packages to the template structure using &lt;code&gt;dotnet restore&lt;/code&gt;. The project is now ready to use, you can explore the project in Visual Studio Code by executing &lt;code&gt;code .&lt;/code&gt; from within the dotnetcoredemo folder:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0LXM1y_V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vfa8ynzv5w4k8g3ghmun.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0LXM1y_V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vfa8ynzv5w4k8g3ghmun.png" alt="greyed out object folder"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the explorer view of VS Code, you can see the outline of the template combined with the .gitignore and README.md from the local git repo. Looking to the top you'll see the obj folder is greyed out and the properties folder is a slightly darker colour of grey. This is due to the .gitignore you added in part one of the guide &lt;a href="https://dev.to/cloudskills/getting-started-with-git-and-azure-devops-1i7a"&gt;Step 1 - Setup a Repo in Azure DevOps&lt;/a&gt;. Open the .gitignore file in VS Code and scroll down to the Build Results section:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G2bRePFm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/oakqliijuxq6n2l56oem.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G2bRePFm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/oakqliijuxq6n2l56oem.png" alt="gitignore configuration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The folder obj has been flagged to be ignored, this is shown in the screenshot by being light grey. The obj folder and none of the files it contains will be pushed to the repo. If you scroll throughout the file, you'll see all the file types and folder names that should not have their files tracked in the git repository. Scroll to the .Net Core section, &lt;code&gt;**/Properties/launchSettings.json&lt;/code&gt;. The instruction tells git to ignore launchSettings.json when it's found under the Properties folder, but not to ignore other files in that folder. The instruction not to include every file in the Properties folder is why this folder is a darker grey than obj.&lt;br&gt;
The .gitignore keeps your repository lean, only code changes are tracked. This also stops binary objects such as compiled code packages, which git is not designed to version, from being stored in your repository.&lt;/p&gt;

&lt;p&gt;If you did not add the .gitignore for Visual Studio previously, you can create this manually. Switch back to your command line and run &lt;code&gt;git status&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5c9jkeOy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xrgyge3r2i6wvquxaxon.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5c9jkeOy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xrgyge3r2i6wvquxaxon.png" alt="gitignore git status missing obj directory"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This local repo has the .gitignore set for a .Net Core webapp so the Obj and Properties directories are not showing up in the changes above. Deleting the file and running &lt;code&gt;git status&lt;/code&gt; once more:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UIiWEal1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/oxp7i8i8tuicywte7sj4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UIiWEal1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/oxp7i8i8tuicywte7sj4.png" alt="gitignore git status with obj and properties"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The output from &lt;code&gt;git status&lt;/code&gt; above in "Untracked files" is what you will see if your .gitignore was not added. On the command line create a new and empty .gitignore file using &lt;code&gt;nul &amp;gt; .gitignore&lt;/code&gt; on windows or &lt;code&gt;touch .gitignore&lt;/code&gt; on MacOs or Linux. Open the folder with &lt;code&gt;code .&lt;/code&gt; and open the empty .gitignore file. Open a browser and navigate to &lt;a href="https://github.com/github/gitignore/blob/master/VisualStudio.gitignore"&gt;VisualStudio.gitignore&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5qdCSklz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/s4fou4uver0l36hvu4rs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5qdCSklz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/s4fou4uver0l36hvu4rs.png" alt="gitignore official repo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The .gitignore for Visual Studio is displayed. This .gitignore file is from the collection of .gitignore templates held at &lt;a href="https://github.com/github/gitignore"&gt;github&lt;/a&gt;. Click Raw to open the raw content of the .gitignore file. Select all, copy and paste the content into the empty .gitignore file open in VS Code. Save the .gitignore file and return to the command line. Re-issue &lt;code&gt;git status&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Xrp2Rjpk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rw6koio2g74yt7frvhy5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xrp2Rjpk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rw6koio2g74yt7frvhy5.png" alt="git status new gitignore"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The status of the updated .gitignore file is listed along with the untracked files. Note here, if you hadn't set up your .gitignore previously, the .gitignore file will be listed under "Untracked files". Notice that the Properties folder is still present showing there is a slight difference between the .gitignore provided by Azure DevOps and the one from github. For this guide leave the settings as is, however, it highlights how a .gitignore file needs to be tailored for your use case.&lt;/p&gt;

&lt;p&gt;You have created a .Net Core Webapp project from a template and set the local git repo to only push the changes that need to be tracked in version control. You are now ready to push your Webapp to the Azure DevOps repo. This process is identical to that performed when editing the README.md:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wa7GwL6K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/s4fuqc4sav27bn2e7oie.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wa7GwL6K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/s4fuqc4sav27bn2e7oie.png" alt="git push webapp"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your new webapp code has been pushed to your Azure DevOps Repo. Open the Repo in a browser to check the template code:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ekpu6xDj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zyragmz5flk0kew0i33p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ekpu6xDj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zyragmz5flk0kew0i33p.png" alt="view azure repo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 - Understanding the build and publish process &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;With your webapp code pushed up to the Azure Repo, you are now ready to create your build pipeline. The process of building the Webapp in Azure DevOps mirrors the process that you would type at the command line with &lt;code&gt;dotnet&lt;/code&gt; or execute in an IDE such as Visual Studio. If you have not built an app in .Net Core before, you can walk through the steps below to explore the process before you switch to Azure DevOps.&lt;/p&gt;

&lt;p&gt;Switch back to the command line and cd into the directory that your code resides in. The command to build an app in .Net Core is &lt;code&gt;dotnet build&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XxNZESe0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sa0madxgekq5yq4z0f8q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XxNZESe0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sa0madxgekq5yq4z0f8q.png" alt="dotnet build"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looking through the output above the first part of the build runs a restore (red box). The &lt;code&gt;dotnet build&lt;/code&gt; command runs &lt;code&gt;dotnet restore&lt;/code&gt; before the build process starts. The &lt;code&gt;dotnet restore&lt;/code&gt; command reads the project file and restores package dependencies using NuGet. &lt;a href="https://www.nuget.org/"&gt;Nuget&lt;/a&gt; is the &lt;em&gt;package manager&lt;/em&gt; for .Net. A package manager gives developers the ability to consume packages created by Microsoft or other authors for use in their code. A developer can also create packages for their teams and others to consume from NuGet. This is a common design pattern, reusable code.&lt;/p&gt;

&lt;p&gt;The project file name is listed next to the restore output dotnetcoredemo.csproj. Switch back to VS Code and open dotnetcoredemo.csproj.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uK_VPVRE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vgzqibukg00j54cc0fmv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uK_VPVRE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vgzqibukg00j54cc0fmv.png" alt="dotnet build"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a new empty project and you have not added any dependencies. If dependencies had been added to the project they would be listed where the empty space is marked on the screenshot above, which would look like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZEAyzzpS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6irw4lgpalaaj57brk90.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZEAyzzpS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6irw4lgpalaaj57brk90.png" alt="package dependencies"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looking back at VS Code, you can also see a bin directory has been created in your local repo. It is greyed out and marked to be ignored by the .gitignore. The bin directory is ignored as it contains binaries that should not be pushed to your repo. The bin directory was created by the second part of the &lt;code&gt;dotnet build&lt;/code&gt; command. The output of this command was shown in the previous screenshot in the yellow box. &lt;a href="https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-build"&gt;dotnet build&lt;/a&gt; takes the dependencies in the project file and builds the dependencies and the code into binaries. You can see the compiled code output as .dll files to the bin folder listed within the yellow box of the &lt;code&gt;dotnet build&lt;/code&gt; output above.&lt;/p&gt;

&lt;p&gt;If you look through the path to the .dll files displayed in the build portion of &lt;code&gt;dotnet build&lt;/code&gt; it is &lt;code&gt;\bin\Debug\netcoreapp3.1\&lt;/code&gt;, it contains the word Debug. When you build a .Net Core application it's default configuration is to create a debug build. For a production build and for this guide, you want to use a release configuration, to do this use the --configuration option &lt;code&gt;dotnet build --configuration Release&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2TCKbCNM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/w6kzgwn3ly435nz588hq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2TCKbCNM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/w6kzgwn3ly435nz588hq.png" alt="package dependencies"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Switching back to VS Code, you will now have Debug and Release builds in the bin directory:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V_eyJjnV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3s7136hiq1fm6e503mn4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V_eyJjnV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3s7136hiq1fm6e503mn4.png" alt="vscode directories"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you open these folders you'll see the files that you need to run the application.  However, this is not the officially supported way to distribute the application. To prepare the application for deployment you need to run &lt;a href="https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish"&gt;dotnet publish&lt;/a&gt; &lt;code&gt;dotnet publish --configuration Release&lt;/code&gt; where the configuration option is the type of build you want to publish:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Rk2azO9k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/n3gidu76hwxiua145s1q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Rk2azO9k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/n3gidu76hwxiua145s1q.png" alt="dotnet publish"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The publish directory now contains all the files required to deploy your application.&lt;/p&gt;

&lt;p&gt;If you step back through the processes above you will see there are three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;dotnet restore&lt;/code&gt; - restore dependencies and code&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dotnet build&lt;/code&gt;   - build your code&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dotnet publish&lt;/code&gt; - publish for deployment&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you recall the very start of this step of the guide, you need to mirror the process from the command line to Azure DevOps. Therefore, the three steps above are those required to build and publish your webapp in Azure DevOps. Switch to Azure DevOps so you can explore this process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 - Create a build pipeline &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Switching back to Azure DevOps you should still be in the Azure Repo for the dotnetcoredemo project. Choose Pipelines in the left-hand menu and then Pipelines once more:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Mq1KQbxj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jt5e4bihdo0y0p4lzqp1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Mq1KQbxj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jt5e4bihdo0y0p4lzqp1.png" alt="select pipelines "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An Azure &lt;em&gt;Pipeline&lt;/em&gt; is used to automate building a project.  You can build your code, test your code, analyze the quality of your code and feedback the results all within one pipeline. Thus providing some of the fast feedback loops that are a corner-stone of DevOps.&lt;/p&gt;

&lt;p&gt;To start creating a Pipeline, click Create Pipeline:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QmKwv28D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/v1253zz42sd567z46quj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QmKwv28D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/v1253zz42sd567z46quj.png" alt="create pipeline"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You now have the choice to start creating a Pipeline in YAML, by selecting where your code is stored. Building a pipeline in YAML is best practice when using Azure DevOps. It allows you to version control your pipeline in the same code repository as your code. However, when you start to configure Pipelines, it is best to use the UI. This allows you to explore the basics of a pipeline by adding items to the pipeline manually. For manual work with the pipeline, you will need to use the classic editor. Click on the classic editor:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RtWp6PqE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qvokvta5w8wdw7secbz5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RtWp6PqE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qvokvta5w8wdw7secbz5.png" alt="choose classic editor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The classic editor starts with the choice of where to select your repository from. The repository selector defaults to Azure DevOps, with the current project and Azure Repo loaded if you have one. You can also select which branch of your Azure Repo to build from. Your Git workflow set up in part 2 of this guide expects builds to be from the master branch. The settings should be all defaulted in for you, so click continue:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--USuUPkcA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vt53lt9d3otpn0f97t0h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--USuUPkcA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vt53lt9d3otpn0f97t0h.png" alt="classic editor choose repo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The classic editor is pre-loaded with templates to carry out different types of build. You are building a .Net Core Webapp, so scroll down through the templates and click on ASP.NET Core and then click Apply:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ql5iGQRK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6x2x72arkn8jcir6d3i0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ql5iGQRK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6x2x72arkn8jcir6d3i0.png" alt="classic editor choose template"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The template for a .Net Core pipeline is loaded. Looking at the &lt;em&gt;tasks&lt;/em&gt; that have been created for you, you'll see they almost mirror the steps we looked at for publishing a .Net Core application locally. A &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/tasks?view=azure-devops&amp;amp;tabs=yaml"&gt;task&lt;/a&gt; in Azure DevOps are steps required to automate a process, in this case, a build, within a pipeline.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BjCf-GkU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0d2aelhlmptzhugfrbe1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BjCf-GkU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0d2aelhlmptzhugfrbe1.png" alt=".net core tasks"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is an extra task - Test, this will run tests as defined in your code repository. Testing code using unit tests at the build stage is another essential part of DevOps. However, for this guide there are no test tasks defined in your repository, therefore we can delete this task. Click on Test, then in the top right click Remove:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--57wSYlG_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/b49rjpoyojs0t5420j19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--57wSYlG_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/b49rjpoyojs0t5420j19.png" alt=".net core delete test task"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The test task is removed and the pipeline now mirrors the steps for publishing a .Net Core application you explored in Step 2 of this part of the guide. Click on Pipeline at the top:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sCs1az7d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4vuufmcvt3y3g8ir6750.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sCs1az7d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4vuufmcvt3y3g8ir6750.png" alt="pipeline settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These are the settings for the pipeline.  You can configure the following for this configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Name - you can alter the pipeline name to fit the pipeline you are creating. Change this to dotnetcore-CI.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Agent Pool&lt;/em&gt; - an &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/agents?view=azure-devops&amp;amp;tabs=browser"&gt;agent&lt;/a&gt; is a Virtual Machine which has software already installed ready to run the tasks in your pipeline. An Agent Pool is a group of agents of identical specification and configuration. An agent pool can be utilized across one or more projects in an Azure DevOps Organisation. Agent pools are hosted by Microsoft or Self Hosted (Private). The default is a Microsoft hosted pool named Azure Pipelines, this is what you will use for the build in this guide. You can see it is Microsoft hosted by selecting the dropdown:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NhtOM-Ch--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/scs5izgcxcvfa49rs6ue.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NhtOM-Ch--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/scs5izgcxcvfa49rs6ue.png" alt="agent pool choices"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Agent Specification&lt;/em&gt; - you chose the default of a Microsoft hosted agent pool, which enables the agent specification drop-down. The agent specification dropdown gives you the option of selecting a specific operating system to suit the requirement of your build. Each &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/hosted?view=azure-devops#use-a-microsoft-hosted-agent"&gt;specification&lt;/a&gt; can have slightly different software pre-installed to run the build tasks. You can choose from MacOs, Windows, Linux, select the dropdown to explore the options. .Net Core is cross-platform and can be built on Linux so leave the specification as ubuntu-16.04:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HO9KOroA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ek1z5bxx6i4rdthytiit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HO9KOroA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ek1z5bxx6i4rdthytiit.png" alt="agent specification"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pipeline settings are correctly configured, now click on Agent Job 1. A &lt;em&gt;job&lt;/em&gt; is a series of tasks that are run sequentially. A &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/phases?view=azure-devops&amp;amp;tabs=classic"&gt;job&lt;/a&gt; runs on an Agent. In this guide we are creating a build, so edit the name of the job to Build. Leave the rest of the job configuration at the defaults. Click on Restore:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l7z31Yik--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/pqy8ptxmqox29yby99vw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l7z31Yik--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/pqy8ptxmqox29yby99vw.png" alt="dotnet restore task"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the right-hand pane is the heading .Net Core, with an information icon next to it. Click the information icon:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qJBf8FQ7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/l9smcbgwbvrpw544gy4i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qJBf8FQ7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/l9smcbgwbvrpw544gy4i.png" alt="information icon"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you see the information about the task. This is the .Net Core CLI task, it has the same functionality as running &lt;code&gt;dotnet&lt;/code&gt; on your local command line. It is the dotnet driver. Exploring the options for this task:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Task version&lt;/em&gt; - each task is versioned to stop issues with backwards compatibility when new functionality is released for a task. Leave this as 2.*.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Display name - this is the name shown in the job on the left-hand side of the pane, leave as Restore.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Command&lt;/em&gt; - this is the command sent to the dotnet driver, in this case it is restore. If you click the dropdown for the command you can see the same commands you viewed when running &lt;code&gt;dotnet --help&lt;/code&gt; on the command line:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vboNQ5iM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ycnh2tlmbtgfh0e3oz9f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vboNQ5iM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ycnh2tlmbtgfh0e3oz9f.png" alt="dotnet help"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choosing Restore gives the same functionality as running &lt;code&gt;dotnet restore&lt;/code&gt;. Leave this as restore. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Path to project(s) - if you recall from Step 2 of this guide, &lt;code&gt;dotnet restore&lt;/code&gt; restores the dependencies from the .csproj file. This path defines where to find the .csproj file within the project.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The defaults are all acceptable here, click Build:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7gO3gUNi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vceibdhxfcrm0em5l7xr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7gO3gUNi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vceibdhxfcrm0em5l7xr.png" alt="dotnet build task"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first four configuration options shown are identical to that of the Restore task above. However, the command is using &lt;code&gt;build&lt;/code&gt;. If you recall the build section of Step 2 of this part of the guide, you have the option to build a Debug or Release optimised build. To do this you use the &lt;code&gt;--configuration&lt;/code&gt; parameter. You can see this at the bottom of the screen-shot above defined as the Argument &lt;code&gt;--configuration $(BuildConfiguration)&lt;/code&gt;. Items defined with $() are &lt;em&gt;Variables&lt;/em&gt;. Variables can be created at the Pipeline level and used throughout the Pipeline. To see this click on Variables towards the top left of the two panes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xx_cSm-H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6cdnvynw0t5blfrkog81.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xx_cSm-H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6cdnvynw0t5blfrkog81.png" alt="pipeline variables"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The BuildConfiguration variable has been set up by the .Net Core template to Release. This pipeline will build a release optimised application. Click on Tasks and click on Publish:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EP7sk11D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ijlj1ysbcaaaukvaicb2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EP7sk11D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ijlj1ysbcaaaukvaicb2.png" alt="dotnet publish task"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once again the first four configuration options have the same function, with this task using the &lt;code&gt;publish&lt;/code&gt; command. This task is set up to publish the .Net Core web project and zip up the output. If you look at the Arguments for the &lt;code&gt;publish&lt;/code&gt; command, there is a new argument, &lt;code&gt;--output&lt;/code&gt;. This is instructing the publish to place the items being published into a specific directory. The directory &lt;code&gt;--output $(build.artifactstagingdirectory)&lt;/code&gt; looks like a pipeline variable. However, it is a &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&amp;amp;tabs=classic#build-variables"&gt;predefined variable&lt;/a&gt;, this has been automatically set by Azure DevOps. This defines a path on the agent where the published output will be copied to.&lt;/p&gt;

&lt;p&gt;The defaults here are as required, click Publish Artifact:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KceAxXDT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/28c8int24slhy814xy5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KceAxXDT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/28c8int24slhy814xy5i.png" alt="publish task"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the point &lt;code&gt;dotnet publish&lt;/code&gt; finishes on the Agent, the application is still on the agent and needs to be copied out and made available for use. At the top left of the right-hand side pane, click the information icon next to Publish build artifacts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iplFuSEt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/198u0jy65rgs68e0f4wi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iplFuSEt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/198u0jy65rgs68e0f4wi.png" alt="publish task info"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/utility/publish-build-artifacts?view=azure-devops"&gt;publish build artifacts&lt;/a&gt; task enables you to copy your published build out to Azure DevOps or a file share. The item published at the end of the build is known as an &lt;em&gt;artifact&lt;/em&gt;, it is a collection of source code and dependencies that make up a deployable component of an application. In the case of this guide, there is only one component so the artifact is the application.&lt;/p&gt;

&lt;p&gt;Looking through the task options, Task version and Display name have the same purpose as previously described tasks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Path to publish&lt;/em&gt; - this is the path on the agent to get the artifact from. You can see the template has been set up to use the same variable &lt;code&gt;$(build.artifactstagingdirectory)&lt;/code&gt; that was used for the &lt;code&gt;dotnet publish&lt;/code&gt; task. This ensures that the output from the &lt;code&gt;dotnet publish&lt;/code&gt; task is published as the artifact.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Artifact name&lt;/em&gt; - the name of the artifact you wish to create.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Artifact publish location&lt;/em&gt; - choose between publishing the artifact within Azure DevOps for other pipelines to use or on a file share:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Tu4maXlE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8j9eqnn0x8og3qadloyf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Tu4maXlE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8j9eqnn0x8og3qadloyf.png" alt="publish task location"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can leave all of these at the default options. Your pipeline is now ready to run!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 - Manually running a pipeline &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;You have set up the job and it's tasks for your pipeline, but so far it has not been saved. Click Save and queue at the top of the classic pipeline editor page. Now click Save and queue in the drop down, this saves the pipeline and queues it to run:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h11w8ImU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/n0mxnuhtb15wodwupa9j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h11w8ImU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/n0mxnuhtb15wodwupa9j.png" alt="save and queue"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This brings up the Run pipeline page, which enables you to manually run your pipeline. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4WumenLj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r9vonl7z3wb8e0ermh5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4WumenLj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r9vonl7z3wb8e0ermh5i.png" alt="run pipeline"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Save comment is optional, however, you can add a meaningful comment to your run. The rest of the options are taken from the pipeline setup.  You will notice that the top three drop-down boxes are taken from the Pipeline settings you explored near the top of this step in the guide. Click Save and Run to run your pipeline:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NBIvUqVH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/swjjb4rqphn17q19t7u5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NBIvUqVH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/swjjb4rqphn17q19t7u5.png" alt="run build"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The run page loads and the job is queued. The pipeline is now trying to get a build agent from the hosted pool, this is why it is queued. Once the build agent is assigned the Job starts to run:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4W2hdp_p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/akck8t4cy93mpubw38wn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4W2hdp_p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/akck8t4cy93mpubw38wn.png" alt="running build"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Until it is either listed as a Successful or Failed build:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8zGHSNa3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xjd6xwtoktw02dvj1elh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8zGHSNa3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xjd6xwtoktw02dvj1elh.png" alt="Successful build"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At any point you can click on the name of the job to look at the status of each task in the build.  Click on the job name to explore the output that is displayed by the running tasks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Rr3wzbNz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zdyk3u0gf8x64f4h1slu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Rr3wzbNz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zdyk3u0gf8x64f4h1slu.png" alt="job details"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The top of the list of tasks is the job summary, here you can see the pipeline settings, how long the job ran, and that an artifact was produced. The artifact message is a link, click on it to view the artifact that was published:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uhDCY1T2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/unoq6nq0cm1hp3cxl1u3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uhDCY1T2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/unoq6nq0cm1hp3cxl1u3.png" alt="published artifact"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can expand the drop folder and see the zip file that was published. If you hover the mouse to the right of either the zip file or drop folder you can download the output. Download and open the zip file, it has the same structure as your /Release/Publish folder had in Step 2 of this part of the guide:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VgMxZfOP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wt8pcu7mg9bfs5aah2aj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VgMxZfOP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wt8pcu7mg9bfs5aah2aj.png" alt="published zip"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The build status had already marked the build as successful, however, you have just checked this by looking at the published artifact. Now you can explore some of the output from the steps in the build. This process can also be used to debug the build in the case of failure. If any of the steps had failed, the status circle to the left of the task name would have contained a red cross. Click the back arrow at the top left by Artifacts, scroll down and click the job name and then click "Checkout dot...":&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M8On9kDQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uzwalzkh04pfn8kzvqgw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M8On9kDQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uzwalzkh04pfn8kzvqgw.png" alt="published zip"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first task the agent must perform is to fetch the repo and checkout the master branch. You didn't have to perform this task locally as you already had your code in your local repo. The commands in blue in the output windows are the &lt;code&gt;git&lt;/code&gt; commands being issued. The build agent is performing the same sequence of commands to fetch the code and check it out, they just look slightly different:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;git init "home/vsts/work/...&lt;/code&gt; - the path to initialise the git repo in is being passed to init, rather than calling init from inside the folder.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;git remote add origin&lt;/code&gt; - this is identical to the command you would call on your local command line.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;git -c http.extraheader="AUTHORIZATION: bearer ***" fetch --force --tags ..... origin&lt;/code&gt; - this is a git fetch. &lt;code&gt;-c http.extraheader="AUTHORIZATION: bearer ***"&lt;/code&gt; is overriding part of the git config with a bearer token to add into the header. The stars show the bearer token has been hidden as it is a secret. This token gives the agent access to the Repo, the agent does not have to login. The fetch is fetching the origin remote, you can see &lt;code&gt;origin&lt;/code&gt; at the end of the command.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;git checkout --progress --force adfd5b...2825d&lt;/code&gt; - this is a git checkout, it is switching to the SHA checksum of the last commit to master when the build job started:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UWNBmTfI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vk7qklw2yhvvasl9lw37.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UWNBmTfI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vk7qklw2yhvvasl9lw37.png" alt="published zip"&gt;&lt;/a&gt;&lt;br&gt;
You can verify the SHA is correct by switching to the commit history in the Azure Repo. The initial 8 characters of the SHA checksum are displayed, however, if you hover to the right of history line, you can copy the SHA checksum from the "More" menu to see it is identical. Note, you must compare the ones in your repo/checkout output, as they will be different from the ones shown here.&lt;/p&gt;

&lt;p&gt;The command &lt;code&gt;git checkout origin master&lt;/code&gt; will switch to master as it looks when the git checkout command is run. If there was a time delay in acquiring a build agent, it is possible further pushes to master have happened in that time. This is why the SHA checksum is used, it guarantees that the code being built is how it looked when the pipeline run started.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now click on the Build task:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dfSrjg2q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rbczyiinfwktsgicn59e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dfSrjg2q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rbczyiinfwktsgicn59e.png" alt="published zip"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see the &lt;code&gt;dotnet build&lt;/code&gt; command in blue, it is being passed the full paths to the .csproj file, along with some options for logging. It is, however, performing an identical process to that carried out locally on your machine. You can verify this by comparing the &lt;code&gt;dotnet build&lt;/code&gt; output from your command line, to that displayed in the task output. You should see the only difference is the output paths.&lt;/p&gt;

&lt;p&gt;Click on the other steps to familiarise yourself with how task output looks between different types of tasks.&lt;/p&gt;

&lt;p&gt;You've now finished exploring a manual run of an Azure Pipeline. However, you do not want to be triggering a build manually after every pull request! Automating the builds will add further value, this is part of the process for Continuous Integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5 - Configuring for Continuous Integration (CI) &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/devops/learn/what-is-continuous-integration"&gt;Continuous integration (CI)&lt;/a&gt; is the process of automatically building and testing code when it is committed to version control. This can be on every push, or a pull request completion. The process can also be automated for changes from one or more branches.&lt;/p&gt;

&lt;p&gt;Azure DevOps supports CI through &lt;em&gt;triggers&lt;/em&gt; on the pipeline. A trigger can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;CI trigger - builds are triggered on every push to a branch or branches.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;PR trigger - builds are triggered on a push to a  pull request on specified branches.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scheduled trigger - builds are scheduled for specific times of the day/week. This can be useful for a testing team new to DevOps who would like to start with a nightly build.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pipeline trigger - this is for large products with dependant components. If a change is detected in a dependant component, the trigger will fire off a new build.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To set this up in Azure DevOps, you will need to edit your pipeline. Enter the Pipelines menu:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hY1VlsNA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/62ra8en0e2ka2e4m0cjg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hY1VlsNA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/62ra8en0e2ka2e4m0cjg.png" alt="pipelines list"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click your pipeline name:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_tztS6D0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/l9durq2z8udwxrsa5ss4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_tztS6D0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/l9durq2z8udwxrsa5ss4.png" alt="pipelines edit button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you can view the runs for your pipelines. Click Edit in the top right:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MI3Er4rA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wc71y31zh0b6pgex42v1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MI3Er4rA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wc71y31zh0b6pgex42v1.png" alt="pipelines triggers tab"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You are taken back into the pipeline classic editor you worked with to set up the pipeline. Towards the top, click the triggers tab:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rnvy4jh5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/z9zkt5o9pdiev27j2jx5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rnvy4jh5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/z9zkt5o9pdiev27j2jx5.png" alt="pipelines triggers options"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are the options as discussed in the CI introduction above.  It is not possible to use Build completion, also known as a Pipeline trigger, as there is only one pipeline in this project.&lt;/p&gt;

&lt;p&gt;You are setting up a Continuous Integration trigger for this pipeline. To do this, click the project name under Continuous Integration and tick Enable continuous integration:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vZj6EeFG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rss15eg8jtdwdqi1mqxl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vZj6EeFG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rss15eg8jtdwdqi1mqxl.png" alt="pipelines CI options"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are some options you can set on continuous integration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Batch changes while a build is in progress - if you work on a large team where there are frequent pushes and/or PR completion pushes, you may end up queuing multiple builds while a build is still in progress. This checkbox will stop each of these pushes being queued as a separate pipeline run. It will queue one run of all the changes once the current build is complete.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Branch filters - include or exclude branches for the trigger.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Path filters - this is often used to exclude changes from a build, for example, "always trigger on master except for when there are changes to the reports folder". In which case you would exclude the path to the reports folder in the Path filter and include master in the Branch filter.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this guide, we are going to trigger on every push to master, so accept the defaults by clicking Save &amp;amp; Queue and Save:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DUXut2RT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/syycllwuru7tfs0mmilz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DUXut2RT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/syycllwuru7tfs0mmilz.png" alt="save and queue and save"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can optionally add a comment for your pipeline change, then click save:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nYX48vAw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vkfozx3d5w3c0hh5txw6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nYX48vAw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vkfozx3d5w3c0hh5txw6.png" alt="save and queue and save"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This saves the changes to your pipeline but does not manually kick off a build. To trigger this you will need to push a change to your Azure Repo.&lt;/p&gt;

&lt;p&gt;Switch back to VS Code, you are going to make a small change to the index page of the webapp to trigger the build. Open Pages/index.cshtml:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YCXNu_9W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2j4uragaor2zgm0tkr6z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YCXNu_9W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2j4uragaor2zgm0tkr6z.png" alt="save and queue and save"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Edit the header line to something appropriate:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OYIXRdaj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9vgde21stni48m11i64l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OYIXRdaj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9vgde21stni48m11i64l.png" alt="index page edit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save the index.cshtml page and switch to your command line to push the change to your repo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iMpb_-rL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/p4ubvjuk1ikqpqcdegod.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iMpb_-rL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/p4ubvjuk1ikqpqcdegod.png" alt="git push"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quickly switch back to Azure DevOps, and click on Pipelines:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fBWnupoQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/svlosr7gbpm6tyqsiuf7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fBWnupoQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/svlosr7gbpm6tyqsiuf7.png" alt="pipeline queued"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The pipeline has been queued. Click on the pipeline name to view the pipeline runs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Obx3yL8S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mpisrwpxadeeh8w4glgm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Obx3yL8S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mpisrwpxadeeh8w4glgm.png" alt="pipeline queued"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your first run states it was Manually triggered, the latest run says it was triggered by an individual CI. Your push to master has triggered the build.&lt;/p&gt;

&lt;p&gt;Congratulations, you have automated your build process!&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, you have explored how the .Net Core CLI works. You used the CLI commands to create a .Net Core Webapp project which you pushed to an Azure DevOps Repo. You examined the .gitignore file and how it is important to keep your code repository lean and to not check in binaries to your repo.&lt;/p&gt;

&lt;p&gt;You configured an Azure DevOps build pipeline, mirroring the build process from your local machine into the pipeline. You manually triggered your pipeline and watched the steps execute to view where you would debug the process if there was an error. Once the build was successful, you verified the published output by downloading the artifact and checking the contents of the compressed file.&lt;/p&gt;

&lt;p&gt;Finally, you automated the process by enabling a Continuous Integration trigger on the master branch of your Azure DevOps Repo. You tested the automation by pushing a change to master and verified that the build was triggered by the push.&lt;/p&gt;

&lt;p&gt;If you recall the definition of &lt;a href="https://docs.microsoft.com/en-us/azure/devops/learn/what-is-continuous-integration"&gt;Continuous integration (CI)&lt;/a&gt;: "It is the process of automatically building and testing code when it is committed to version control." If you also look back to the beginning of this part of the guide, Automated testing is displayed as a driver to the Continuous integration construct. To add further value to your newly automated build process, you must be automatically testing every build. The next part of this guide will add a test and a test task to your pipeline.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>devops</category>
      <category>dotnet</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Working with the Feature Branch Workflow and Pull Requests</title>
      <dc:creator>Nicole Stevens</dc:creator>
      <pubDate>Tue, 17 Mar 2020 11:22:15 +0000</pubDate>
      <link>https://forem.com/cloudskills/working-with-the-feature-branch-workflow-and-pull-requests-27pi</link>
      <guid>https://forem.com/cloudskills/working-with-the-feature-branch-workflow-and-pull-requests-27pi</guid>
      <description>&lt;h1&gt;
  
  
  Working with the Feature Branch Workflow and Pull Requests
&lt;/h1&gt;

&lt;p&gt;Stepping back to &lt;a href="https://cloudskills.io/blog/git-azure-devops"&gt;part 1&lt;/a&gt; of this guide you've been a lone developer, cloning your repository, making changes locally and pushing them back up to your remote. What happens when other developers need to make changes, at the same time as you, and in the same repository? How do you ensure the changes follow your coding standards and are of sufficient quality? This is where implementing a git workflow is crucial, to ensure changes are reviewed and merged back into the main code line. A common Git workflow for a team has the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;em&gt;branch&lt;/em&gt; for the changes you are going to make. A branch is an isolated version of the code that you can work on offline without impacting other developers on your team. A branch would typically be for a new feature or a defect fix.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Commit&lt;/em&gt; changes to your branch locally. You can keep track of your commit history locally while you work.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Push&lt;/em&gt; your changes to the remote repository, in the case of this guide, Azure DevOps.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a &lt;em&gt;Pull request&lt;/em&gt; so that one or more people on your team can review your changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Review&lt;/em&gt; the pull request. One or more team members perform a quality check on the code. The criteria for checks of these changes will often be laid out in a code review checklist which are likely to include the coding standards of your team or organisation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Complete&lt;/em&gt; the pull request. The team members who are required to review your changes agree that the criteria for changes have been met. The pull request is completed and the changes are merged into the main code line - the &lt;em&gt;master&lt;/em&gt; branch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Delete&lt;/em&gt; the branch. Once the code changes and history are merged, it's good housekeeping to delete the branch.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This workflow is often called the &lt;a href="https://docs.microsoft.com/en-us/azure/devops/repos/git/git-branching-guidance?view=azure-devops"&gt;Feature Branch Workflow&lt;/a&gt; or &lt;a href="https://git-scm.com/book/en/v2/Git-Branching-Branching-Workflows"&gt;Topic Branch Workflow&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The code in your master branch should pass tests, build cleanly, and always be current. Your master branch needs these qualities so that feature branches created by your team start from a known good version of code.  The workflow above enables this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before working through this guide you will need the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;An &lt;a href="https://azure.microsoft.com/en-us/"&gt;Azure Subscription&lt;/a&gt;, you can create a free account.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An &lt;a href="http://dev.azure.com/"&gt;Azure DevOps Organisation&lt;/a&gt;, the basic plan starts with the first five users for free.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A local installation of &lt;a href="https://code.visualstudio.com/download"&gt;Visual Studio Code (VSCode)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A local installation of &lt;a href="https://git-scm.com"&gt;Git&lt;/a&gt;, following the &lt;a href="https://git-scm.com/book/en/v2/Getting-Started-Installing-Git"&gt;install guide&lt;/a&gt; for your OS. If you are using Windows, ensure the box is checked to &lt;strong&gt;Enable Git Credential Manager&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8ks-QeCw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1q4a96jp7fcbukala2f9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8ks-QeCw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1q4a96jp7fcbukala2f9.png" alt="Enable Git Credential Manager"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you installed VSCode before Git, you will also be presented with this option:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--C_0fkoDv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uyabdmu1z9z5ngxsj153.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C_0fkoDv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uyabdmu1z9z5ngxsj153.png" alt="Choosing the default editor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This allows you to launch VSCode as the default code editor or difference tool, straight from git on the command line.  Please leave as VSCode for this guide, you can reinstall later to pick a different IDE.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An &lt;a href="https://cloudskills.io/blog/git-azure-devops"&gt;Azure DevOps Project&lt;/a&gt;. Check out &lt;a href="https://cloudskills.io/blog/git-azure-devops"&gt;part 1&lt;/a&gt; of this blog series, you'll be using the Azure DevOps Project and Repo created in Step 5.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1 — Configuring branch policies in Azure Repos
&lt;/h2&gt;

&lt;p&gt;You can use branch policies in Azure DevOps to set rules that must be followed when working with branches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Require code reviewers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Limit who can work on branches&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Guarantee changes build before merging to master&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are all examples for branch policies. You are going to explore &lt;em&gt;Require code reviewers&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Open &lt;a href="https://dev.azure.com"&gt;Azure DevOps&lt;/a&gt; and open the dotnetcoredemo project you created in &lt;a href="https://cloudskills.io/blog/git-azure-devops"&gt;Part 1&lt;/a&gt; of this series. Hover over the &lt;strong&gt;Repos&lt;/strong&gt; menu item on the left, when the menu pops out click &lt;strong&gt;Branches&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T4Alxvw---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/my40uu2yziaj0wqakc6w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T4Alxvw---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/my40uu2yziaj0wqakc6w.png" alt="Repo Branches"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The default on this screen is to show all of the branches that you have created as the filter "Mine" has been automatically selected at the top. You haven't created a branch yet, so only the master branch will be shown, all users have the master branch under "Mine". Move your mouse to the right of the star (which signifies this is the default branch) and a three dot menu will be displayed:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lUXsN1h2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6rahhbm9x1lqgl4sdzia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lUXsN1h2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6rahhbm9x1lqgl4sdzia.png" alt="Branches hidden menu"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the &lt;strong&gt;...&lt;/strong&gt; context menu and choose &lt;strong&gt;Branch policies&lt;/strong&gt; at the bottom of the menu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7S70ghNw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1j6vlja2wyhldxpyxf4c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7S70ghNw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1j6vlja2wyhldxpyxf4c.png" alt="Branches More menu Branch Policies"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This opens up the Branch policies, where you can choose from the following options:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XKDIPfIw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nfqh6dat7i40b8hzgii9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XKDIPfIw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nfqh6dat7i40b8hzgii9.png" alt="Branch policy options"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The more commonly used options for branch policies are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Require a minimum number of reviewers&lt;/em&gt; - when a pull request is issued, you can set the number of reviewers that must &lt;em&gt;approve&lt;/em&gt; the changes before the changes are merged back into the branch.  You can also set the policy such that a reviewer cannot be the person who checked the code in. This will ensure that more than one set of eyes passes over your code, increasing quality and spotting mistakes before the code hits QA.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Check for linked work items&lt;/em&gt; - this links a pull request to one or more &lt;em&gt;work items&lt;/em&gt;. A work item is an Azure Boards unit of work, for example, a bug, feature or task. When this option is turned on, the comments against the commits in the pull request are checked for work item numbers. If none are found, the pull request can either be blocked or a warning message displayed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Check for comment resolution&lt;/em&gt; - A comment can be placed on a pull request. This will often happen if a reviewer requires clarity on code within the pull request, or if standards are not met. Checking this option requires all comments to be resolved, blocking the pull request completion. This can also be set to optional, displaying a warning if comments are still to be resolved, but the pull request will complete.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this example, tick &lt;strong&gt;Require a minimum number of reviewers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZaCtqBk0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6q7kg8emca3ypotrt4c7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZaCtqBk0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6q7kg8emca3ypotrt4c7.png" alt="Branch minimum number of reviewers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Set the reviewers to 2, and tick &lt;strong&gt;Requestors can approve their own changes&lt;/strong&gt;. In practice, it's unlikely this box would be ticked, a team would not want the person who wrote the code to review it. You are setting it in this guide to lessen the complexity of the example. Once completed, click &lt;strong&gt;Save changes&lt;/strong&gt; at the top.&lt;/p&gt;

&lt;p&gt;The master branch now requires two members of the team to approve a pull request before the changes can be merged back to master. However, at the moment you only have one team with one team member in this project. You can check this by hitting the project settings cog on the bottom left, then &lt;strong&gt;Teams&lt;/strong&gt; on the Project settings menu:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LwJ8UHLI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zt1vzqwm6miluc4bpr5u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LwJ8UHLI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zt1vzqwm6miluc4bpr5u.png" alt="Project team members"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is only one team on the list, the default project team. This was created when the project was created. The number under the &lt;strong&gt;Members&lt;/strong&gt; column shows how many team members are in this team.&lt;/p&gt;

&lt;p&gt;In the next step, you will add another team member by adding users into Azure AD and connecting your Azure AD to your Azure DevOps organisation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 — Integrate Azure DevOps with Azure AD
&lt;/h2&gt;

&lt;p&gt;In this Step you, are going to hook up your Azure DevOps organisation to &lt;a href="https://docs.microsoft.com/en-gb/azure/active-directory/fundamentals/active-directory-whatis"&gt;Azure Active Directory&lt;/a&gt; (Azure AD). Azure AD is the identity and access management service for Microsoft cloud services, including Azure and Office 365. Azure AD enables an organisation to grant it's employees access to resources within Azure. If you are familiar with an on-premises Active Directory, Azure AD is an implementation of some of the on-premises Active Directory functionality, including user management.&lt;/p&gt;

&lt;p&gt;You will add a new user to Azure AD, then add the same user to Azure DevOps, granting that user the permissions required to approve a pull request.&lt;/p&gt;

&lt;p&gt;First, login to the &lt;a href="https://portal.azure.com/"&gt;Azure Portal&lt;/a&gt; as the user you setup in the pre-requisites of &lt;a href="https://cloudskills.io/blog/git-azure-devops"&gt;Part 1&lt;/a&gt;. In the search bar at the top of the Portal, start to type &lt;strong&gt;Azure Active Directory&lt;/strong&gt; and click on the resource when the list of matching resources is displayed:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Z356J3hr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/w697f8y507aygrpyrext.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Z356J3hr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/w697f8y507aygrpyrext.png" alt="Search for Azure Ad"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This opens up the default directory for the associated Azure Tenant. The directory houses all of the users for the Tenant. Click &lt;strong&gt;Users&lt;/strong&gt; under the &lt;strong&gt;Manage&lt;/strong&gt; menu item:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iQTIvwBm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/krcjv2famry3az2mlapq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iQTIvwBm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/krcjv2famry3az2mlapq.png" alt="Search for Azure Ad"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If this Azure account was created specifically for following this guide, there will only be one user present in this directory. This is the user that you logged in as when you created the tenant. Hit &lt;strong&gt;New User&lt;/strong&gt; towards the top of the screen:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yyfl9ZN1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ee2rkzy0631n7s6uq819.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yyfl9ZN1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ee2rkzy0631n7s6uq819.png" alt="Search for Azure Ad"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the top of the New User page, you'll now have the option to Create a user or Invite a user. Invite gives you the ability to grant access to users who are not housed in your tenant, they do not have to be Azure AD or Microsoft accounts, they just need an email address. For this guide you are going to add a user within your tenant so choose &lt;strong&gt;Create user&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ovtCqiDQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/j7upmox0ivnlnwj4l8rm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ovtCqiDQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/j7upmox0ivnlnwj4l8rm.png" alt="Create user"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Scroll down to the Identity section, here you will add the User name, also known as the &lt;em&gt;User Principal Name&lt;/em&gt; and Name for the new user&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8HY_UF1l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6f06s1r1ffzgcfwksx1v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8HY_UF1l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6f06s1r1ffzgcfwksx1v.png" alt="Create user"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Azure AD and on-premises Active Directory, the User Principal Name is the unique identifier for the account. Therefore, the entry for &lt;strong&gt;User name&lt;/strong&gt; must be unique for the tenant. If you look to the right of the @ symbol you'll see the default domain name for the tenant, this is setup when you logged in and created this new tenant. Here I have masked the tenant name, if I had logged in as &lt;a href="mailto:devopsdemo@freemail.com"&gt;devopsdemo@freemail.com&lt;/a&gt;, my default domain name would be devopsdemofreemail.onmicrosoft.com. Therefore, the login when this user is created will be &lt;a href="mailto:henrykelly@devopsdemofreemail.onmicrosoft.com"&gt;henrykelly@devopsdemofreemail.onmicrosoft.com&lt;/a&gt;. You can also view the default domain name on the home page for Azure AD.&lt;/p&gt;

&lt;p&gt;The minimum values for creating a user are &lt;strong&gt;User name&lt;/strong&gt; and &lt;strong&gt;Name&lt;/strong&gt;, fill these in and then tick &lt;strong&gt;Show password&lt;/strong&gt;. Take a note of this password, you will need this when you login as the user the first time. Once the minimum values are entered correctly, the &lt;strong&gt;Create&lt;/strong&gt; button will activate at the bottom left. You do not need to change anything else on this page, so click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q7fIr_Tp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gj1jf8om5qnec78j9xbr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q7fIr_Tp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gj1jf8om5qnec78j9xbr.png" alt="List of uers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your newly created user is listed in the directory. Note that the &lt;strong&gt;Source&lt;/strong&gt; says Azure Active Directory. This means that this user is authenticated to an Azure AD account belonging to this active directory. If you had chosen &lt;strong&gt;Invite a user&lt;/strong&gt; a few steps ago this would say External Azure Active Directory.&lt;/p&gt;

&lt;p&gt;You now need to check you can login with this user. Open a different browser to ensure you are not using cached credentials. Login to the &lt;a href="https://portal.azure.com/"&gt;Azure Portal&lt;/a&gt; with your new user:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Pz3Wb9zv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4a3v2eyc4081h1xmtht1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Pz3Wb9zv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4a3v2eyc4081h1xmtht1.png" alt="New user first login"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will need to make sure you use your default name and then enter the password noted when you created this user. As this is the first time you have logged in as the new user, you will need to update your password:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QBmHyrhW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uwk868d8ekf74g2fehhz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QBmHyrhW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uwk868d8ekf74g2fehhz.png" alt="New user update password"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the password is updated and your new user has logged in without a problem you'll see the welcome screen:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gz2N2oco--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/z7tk43bg6kvqlszdczda.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gz2N2oco--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/z7tk43bg6kvqlszdczda.png" alt="New user welcome"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your user has been added correctly. At the moment the user is only an Azure AD user, the user does not have access to Azure DevOps. Switch back to &lt;a href="https://dev.azure.com/"&gt;Azure DevOps&lt;/a&gt; using your original user account which setup Azure DevOps in the pre-requisites. &lt;/p&gt;

&lt;p&gt;To add in users to Azure DevOps you are going to integrate Azure AD. Click on the Azure DevOps icon in the top right, this will take you to the Azure DevOps organisation home page. Click &lt;strong&gt;Organisation settings&lt;/strong&gt; at the bottom left.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oaSgJmFz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/f8blqikkoj6uxrlxqjbg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oaSgJmFz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/f8blqikkoj6uxrlxqjbg.png" alt="Azure DevOps Organisation Home Page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will show you the settings that affect the entire DevOps organisation. We want to integrate Azure AD so click &lt;strong&gt;Azure Active Directory&lt;/strong&gt; in the menu on the left:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8lh5NDnw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mifpjnsngev8dpoohj46.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8lh5NDnw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mifpjnsngev8dpoohj46.png" alt="Organisation Settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The connect to Azure Ad screen is displayed, click &lt;strong&gt;Connect directory&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ptc64Jlu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9y28q7zxcpjeor3xgfxk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ptc64Jlu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9y28q7zxcpjeor3xgfxk.png" alt="Connect directory"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the next screen, you can choose the Azure Active Directory which will connect the Azure DevOps organisation. The user you are signed in as created the organisation and the Azure tenant, so you can choose "Default Directory" in the dropdown to link the two.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YMdBPQuc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yzla89bh6quw3vi1jxkd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YMdBPQuc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yzla89bh6quw3vi1jxkd.png" alt="Connect directory"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can connect a directory to an Azure DevOps Organisation that was not created by the same user, the user must be a &lt;em&gt;member&lt;/em&gt; of the Azure AD and an admin or owner of the Azure DevOps Organisation, see this &lt;a href="https://docs.microsoft.com/en-gb/azure/devops/organizations/accounts/connect-organization-to-azure-ad?view=azure-devops"&gt;Microsoft Docs article&lt;/a&gt; for more information.&lt;/p&gt;

&lt;p&gt;Note the yellow warning box, this will not display when you choose your Azure Active Directory. This is shown as you have invited user(s) to this Organisation that are not in the Default Directory. You can see which users these are by clicking on the &lt;strong&gt;1 out of 2 member(s)&lt;/strong&gt; link:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NosEBlhf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7ecaxatvpkzahz7vvwfn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NosEBlhf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7ecaxatvpkzahz7vvwfn.png" alt="Disconnected Users"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The users listed will be disconnected from the Azure DevOps Organisation, unless they are added as members or guests to the Default Directory chosen for the connection.&lt;/p&gt;

&lt;p&gt;Hit &lt;strong&gt;Close&lt;/strong&gt; on the Disconnected user pop up and then &lt;strong&gt;Connect&lt;/strong&gt; on the Azure Active Directory Connection popup. It takes a few moments to connect the Directory and the Organisation, once this is complete you should see the Connect success popup.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--86cZoJvU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/e66prrc9rw072mvava2q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--86cZoJvU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/e66prrc9rw072mvava2q.png" alt="Connect Success"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hit &lt;strong&gt;Sign out&lt;/strong&gt; and sign back in again, hit the account you were just signed in as:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kMgnFxth--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cqaklg5lrcnl4eo9ugti.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kMgnFxth--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cqaklg5lrcnl4eo9ugti.png" alt="Sign back in"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you've signed back in, the Azure AD Organisation Setting will show the Default Directory as connected:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cVMfZ3aX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qsnjouuzsl6kf9qjom1h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cVMfZ3aX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qsnjouuzsl6kf9qjom1h.png" alt="Azure AD Connected"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now the Azure AD is connected you can assign some access privileges to your users. Staying in the &lt;strong&gt;Organisation Settings&lt;/strong&gt; click &lt;strong&gt;Users&lt;/strong&gt; in the left hand menu bar:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nBG-quLW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gmgkat861yg9nyqrgdn7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nBG-quLW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gmgkat861yg9nyqrgdn7.png" alt="User List After AD"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Azure AD is connected but there is only your user listed. Connecting the directory from Azure AD doesn't give all users in that directory access to the DevOps Organisation, it makes them available to add. Hit &lt;strong&gt;Add users&lt;/strong&gt; on the left:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dtjRgABU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/djrufghhs1ddfzlqy033.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dtjRgABU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/djrufghhs1ddfzlqy033.png" alt="Search for user"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;Users&lt;/strong&gt; box, start typing the name of the user you added to your directory, once the user comes up in the search click the name to add into the &lt;strong&gt;Users&lt;/strong&gt; box. Leave &lt;strong&gt;Access level&lt;/strong&gt; as &lt;strong&gt;Basic&lt;/strong&gt;, this grants the user access to most features in an organisation. Check out the &lt;a href="https://docs.microsoft.com/en-us/azure/devops/organizations/security/access-levels?view=azure-devops"&gt;about access levels&lt;/a&gt; msdoc for more information. Now click the &lt;strong&gt;Add to projects&lt;/strong&gt; dropdown and select the dotnetcoredemo project:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7E4vpNTu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uve40g9vmowktqxse91l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7E4vpNTu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uve40g9vmowktqxse91l.png" alt="Search for user"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Leaving &lt;strong&gt;Send email invites&lt;/strong&gt; ticked will send an email to all users selected in Add new users inviting them to the Azure DevOps Organisation.&lt;/p&gt;

&lt;p&gt;Now that the project has been chosen to grant access to, the &lt;strong&gt;Azure DevOps Groups&lt;/strong&gt; dropdown has been activated and set to &lt;strong&gt;Project Contributors&lt;/strong&gt; by default:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OnDk4vvv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/co8iu1ylms013hv2tgmw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OnDk4vvv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/co8iu1ylms013hv2tgmw.png" alt="Add user default groups"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The options here are showing the groups for &lt;a href="https://docs.microsoft.com/en-us/azure/devops/organizations/security/permissions-access"&gt;Default permissions and access&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Project Readers - Can view all items but are unable to make changes.&lt;/li&gt;
&lt;li&gt;Project Contributors - Can add, modify and delete items in the project.&lt;/li&gt;
&lt;li&gt;Project Administrators - Mostly the same as contributors but are also able to delete key items such as work items and share objects across a project such as dashboards and queries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Leave the selection as &lt;strong&gt;Project Contributors&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Don't hit add yet, go back up to the &lt;strong&gt;Users&lt;/strong&gt; box and hit the plus sign to add a new user. Type in an email address that is not in the connected Azure AD:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bHtQ1J6I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cpgfrlbozysh6uh76cs8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bHtQ1J6I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cpgfrlbozysh6uh76cs8.png" alt="Add non AD user"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can still add users outside of the connected Azure AD, but they will need to click the add url in their invite email for access.  Azure DevOps gives a warning of this at the bottom of the Add new users popup:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t96UN6Bw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7nnomke3e49wx4qwohxq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t96UN6Bw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7nnomke3e49wx4qwohxq.png" alt="Add non AD user warning"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remove the non Azure AD user by clicking the cross on the right of the email address. Click &lt;strong&gt;Add&lt;/strong&gt; to add your user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4XbYFXRh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cefeexl5pv4s465g1z3g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4XbYFXRh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cefeexl5pv4s465g1z3g.png" alt="User added"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The user is now listed.&lt;/p&gt;

&lt;p&gt;You can now go and check the user's access from within the project itself. Click &lt;strong&gt;Azure DevOps&lt;/strong&gt; in the top left, then the dotnetcore project pane. Click &lt;strong&gt;Project Settings&lt;/strong&gt; at the bottom left to bring the project settings menu up. Now click on &lt;strong&gt;Permissions&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--usygolDX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ucvhgu4fdbfmlhtjt6bw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--usygolDX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ucvhgu4fdbfmlhtjt6bw.png" alt="Permissions list"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The permission groups are listed, in the &lt;strong&gt;Members&lt;/strong&gt; column for &lt;strong&gt;Contributors&lt;/strong&gt; you can see two next to the icon. If you hover over the Members icon for the Contributors group, the avatars for the newly added user and a default permission group are displayed. Click on &lt;strong&gt;Contributors&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CLqILNri--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7afffby1il7lv44jtzdz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CLqILNri--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7afffby1il7lv44jtzdz.png" alt="Contributor default permissions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These are the default permissions settings for a contributor. Scroll down to view all of the permissions you can set. Scroll back up and click &lt;strong&gt;Members&lt;/strong&gt; at the top of the page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qLTsmj17--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xe306g4axxqev4mvgdx3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qLTsmj17--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xe306g4axxqev4mvgdx3.png" alt="Contributor members"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you can verify that the user you added is a contributor to the dotnetcoredemo project.&lt;/p&gt;

&lt;p&gt;You can now go back to Branch policies and update the policy on the master branch. Using the project menu on the left hand side, hover over &lt;strong&gt;Repos&lt;/strong&gt; and then click &lt;strong&gt;Branches&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hzH05TR---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uo0p6syfv7rrmnh1myd8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hzH05TR---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uo0p6syfv7rrmnh1myd8.png" alt="Branch menu"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go back into Branch policies by clicking the hidden menu of three dots &lt;strong&gt;...&lt;/strong&gt; at the end of the &lt;strong&gt;master&lt;/strong&gt; branch. Then click &lt;strong&gt;Branch policies&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kqFMgun8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fxujh1zpkvy3aa5dpib0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kqFMgun8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fxujh1zpkvy3aa5dpib0.png" alt="Branch policies menu"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Scroll down to the bottom of Branch policies and click &lt;strong&gt;Add automatic reviewers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vOuSFjBN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bw8f1k5ru3ni55ps7ajh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vOuSFjBN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/bw8f1k5ru3ni55ps7ajh.png" alt="Branch policies add auto reviewers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the section &lt;strong&gt;Include the following reviewers&lt;/strong&gt; add the user you have just given contributor permissions to, along with yourself. Leave &lt;strong&gt;Policy requirement&lt;/strong&gt; at &lt;strong&gt;Required&lt;/strong&gt;. Note the option &lt;strong&gt;For pull requests affecting these folders&lt;/strong&gt;. In this text box you can set a path or paths within the branch that will trigger the automatic inclusion of specific reviewers. This gives you the ability to set senior engineers as automatic reviewers for key areas of your application. For this guide, leave the setting at the default and click &lt;strong&gt;Save&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YMGeSL9x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/z6yoy5tqb4ujhjzkq6rl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YMGeSL9x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/z6yoy5tqb4ujhjzkq6rl.png" alt="Auto reviewer search"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Setting the two users as &lt;strong&gt;Required&lt;/strong&gt; will mean a pull request cannot be completed on this branch until all of the required reviewers approve the request. The two reviewers are now listed under Add automatic reviewers:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xDtdqz89--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/imgi9picrpwktgvkhyh9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xDtdqz89--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/imgi9picrpwktgvkhyh9.png" alt="Branch policies menu"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The final part of this Step is to ensure users cannot bypass your newly created policy. On the project menu, click the &lt;strong&gt;Project settings&lt;/strong&gt; cog. Now click &lt;strong&gt;Repositories&lt;/strong&gt; under &lt;strong&gt;Repos&lt;/strong&gt; in the project settings menu. This displays the security settings for the repositories belonging to this project. Click &lt;strong&gt;Contributors&lt;/strong&gt; and you will see that the top option &lt;strong&gt;Bypass policies when completing pull requests&lt;/strong&gt; is &lt;strong&gt;Not set&lt;/strong&gt;.  Using the dropdown you'll want to choose deny, so that your policy must be followed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bRsgVQfc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/he644p1o1a9lvkf1fen1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bRsgVQfc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/he644p1o1a9lvkf1fen1.png" alt="Bypass policies"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The changed automatically saved and a green tick is displayed to the right of the box&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5xvYJjvn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/i8ns5023rsz88311uzyb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5xvYJjvn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/i8ns5023rsz88311uzyb.png" alt="Changes saved"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You are now ready to move on to the next step and work with feature branches and pull requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 — Pushing a local feature branch to Azure Repos
&lt;/h2&gt;

&lt;p&gt;Now you have the branch policies setup, you are ready to create a feature branch on your local machine, push it up to Azure Repos and create a pull request. &lt;/p&gt;

&lt;p&gt;Switch back to git and &lt;code&gt;cd&lt;/code&gt; to the dotnetcore directory you have on your local machine. Run &lt;code&gt;git status&lt;/code&gt; to check your local repo is up to date. The command &lt;code&gt;git branch&lt;/code&gt; is used when working with branches. If you run it standalone, git will list all of the branches in your local repo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0yQr0iP0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5bmzrjiavf8oqt1yens0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0yQr0iP0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5bmzrjiavf8oqt1yens0.png" alt="List branches"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You only have one branch currently, that's the master branch as displayed. You can also use &lt;code&gt;git branch&lt;/code&gt; to add a new branch. To do this re-issue the &lt;code&gt;git branch&lt;/code&gt; command with the branch name you would like to create tagged to the end of it &lt;code&gt;git branch users/nicole/home-blog-feature&lt;/code&gt;. Execute &lt;code&gt;git branch&lt;/code&gt; once more to list the branches in your local repo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Uw6p8SYz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5611xb6dpf0e6he5gsis.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Uw6p8SYz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5611xb6dpf0e6he5gsis.png" alt="Add a branch"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that master is green with a star on it's left and your new branch is white. This denotes that you are working on the master branch. Therefore, any changes you make during editing will be against this branch. You need to execute the &lt;code&gt;git checkout&lt;/code&gt; command to switch to the new branch, so that you can work in isolation on your new feature. To do this run &lt;code&gt;git checkout users/nicole/home-blog-feature&lt;/code&gt; to switch to your newly created branch. You can then re-issue &lt;code&gt;git branch&lt;/code&gt; to check you have switched branches:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DuBLdYqE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/do97ojiz9v5zg1osqnie.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DuBLdYqE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/do97ojiz9v5zg1osqnie.png" alt="Switch branches"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your new branch name is green with the star to the left, denoting it is the branch you have checked out.&lt;/p&gt;

&lt;p&gt;You may be wondering why the branch name is &lt;code&gt;users/nicole/name-blog-feature&lt;/code&gt; and not just &lt;code&gt;name-blog-feature&lt;/code&gt;? This is a common &lt;a href="https://docs.microsoft.com/en-us/azure/devops/repos/git/git-branching-guidance?view=azure-devops#name-your-feature-branches-by-convention"&gt;branch naming convention&lt;/a&gt;. As you get more familiar with git, you can use conventions such as these to filter a large repo, showing all feature branches or bugfix branches owned by specific users.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;code .&lt;/code&gt; to open VS Code and edit the README.md, paste in the markdown block shown below. This is to simulate making code changes in isolation in your application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fKnCMoRb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mzkyxfnjp6prbq55bkem.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fKnCMoRb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mzkyxfnjp6prbq55bkem.png" alt="Edit the readme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note the bar at the bottom left of VS Code, due to the integration with Git, VS Code displays which branch you are currently working on:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OEOSci_g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sjqe3guoxn4498dwgbfv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OEOSci_g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sjqe3guoxn4498dwgbfv.png" alt="VS Code branch"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save the file and switch back to the command line. From within the dotnetcoredemo folder run &lt;code&gt;git status&lt;/code&gt; to view the file changes. Add the changes with &lt;code&gt;git add .&lt;/code&gt; and commit with &lt;code&gt;git commit -m "added new blog feature"&lt;/code&gt;. You are now ready to push the changes to Azure DevOps. To do this you need to tell git to push your new branch to the remote for Azure DevOps, which is origin - &lt;code&gt;git push origin users/nicole/home-blog-feature&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L3TtyD8O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9yrcwri57h479vki20bx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L3TtyD8O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9yrcwri57h479vki20bx.png" alt="Push the new branch up"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you recall from &lt;a href="https://cloudskills.io/blog/git-azure-devops"&gt;part 1&lt;/a&gt; of this guide, you can check what you've called your remotes and where they are pointing using &lt;code&gt;git remote -v&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Switch back to Azure DevOps and click &lt;strong&gt;Branches&lt;/strong&gt; under &lt;strong&gt;Repos&lt;/strong&gt; on the project menu. You can now see two branches, the master and your new feature branch. You can see your name under author as you committed the changes and pushed the branch up to the Repo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1ZKE-rLR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/y22h489rrxhukgsmfn3f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1ZKE-rLR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/y22h489rrxhukgsmfn3f.png" alt="Display new branch"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note the folder users/nicole. This shows a small part of the power of a good branch naming convention. Using this convention, you can see all of the branches owned by each of the Repo users by expanding their folder. Hover over the feature branch name, you can now click on the &lt;strong&gt;home-blog-feature branch&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ewrDncDL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/74ordw9ze2o0y45so9pp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ewrDncDL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/74ordw9ze2o0y45so9pp.png" alt="Select the feature branch"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This takes you directly to the Files section of Azure Repos and into the selected branch to display the files that are part of this branch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zOGtaL6f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/kpa2v235qqnlgqjvzkxj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zOGtaL6f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/kpa2v235qqnlgqjvzkxj.png" alt="Branch files"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You are happy that your changes meet the feature requirements and now need to merge your changes back into the master branch. To do this you need to create a pull request by clicking on &lt;strong&gt;Create a pull request&lt;/strong&gt; on the right hand side.&lt;/p&gt;

&lt;p&gt;The top two dropdown boxes of the New Pull Request page show that you are requesting to pull the changes in the users/nicole/home-blog-feature branch into the master branch. Your commit message has been automatically added to the &lt;strong&gt;Title&lt;/strong&gt; of the pull request. This is one of the many reasons why you should be thinking about writing good commit messages. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oP9egVc---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5e6njs0zfidzms2nrs5w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oP9egVc---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5e6njs0zfidzms2nrs5w.png" alt="Create a pull request"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Moving down to &lt;strong&gt;Reviewers&lt;/strong&gt;, here you can add specific members of the dotnetcoredemo project to review your changes. However, you have already setup two users to auto review pull requests to the master branch. So to check this is working leave this blank. &lt;strong&gt;Work Items&lt;/strong&gt; can automatically link to items in Azure Boards if the correct item number(s) are in the commit message(s), or you can add them manually here.  If you scroll down below Create, you can see the file changes that are part of this branch. Click &lt;strong&gt;Create&lt;/strong&gt;. The Pull request is created and you are switched to the &lt;strong&gt;Pull requests&lt;/strong&gt; menu item under &lt;strong&gt;Repos&lt;/strong&gt; in the project menu. The pull request you just created is shown:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8q2-jqOy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mm68wk02ju6aoxdt8n10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8q2-jqOy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mm68wk02ju6aoxdt8n10.png" alt="Pull request overview"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the pull request page, it contains all of the information required to review the pull request. By default, you are taken into the Pull request overview tab. At the top, you can see the pull request has been set to active. Scanning further down below the description, the history of the pull request is displayed. No review of this pull request has started so the history shows that the pull request was created and your new user along with your username were added as required reviewers.&lt;/p&gt;

&lt;p&gt;Switching to look at the right hand side, at the top are the &lt;strong&gt;Policies&lt;/strong&gt; that have been set on this branch or path(s) within this branch. The red crosses next to each policy show that you have not met the requirements of the policies listed. If Azure Boards work items had been linked to this pull request, these would be listed on the right hand side under &lt;strong&gt;Work Items&lt;/strong&gt;. The work items are listed as links to allow swift access to related work items for review. Under &lt;strong&gt;Reviewers&lt;/strong&gt; are the required reviewers. If you had selected optional reviewers when the pull request was created, these would also be listed here, grouped under Optional. An email to all reviewers can be sent by clicking envelope icon to the right of &lt;strong&gt;Reviewers&lt;/strong&gt;. By default users are not notified that they are required to review a pull request, however, this can be setup in &lt;a href="https://docs.microsoft.com/en-us/azure/devops/notifications/manage-team-group-notifications?view=azure-devops"&gt;Notifications for the project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hit the &lt;strong&gt;Files&lt;/strong&gt; tab at the top:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A9FH2gmP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2e13mafdwmjq1s6r6jp0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A9FH2gmP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/2e13mafdwmjq1s6r6jp0.png" alt="Pull request files"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here the files that are different between your branch and master are listed.&lt;/p&gt;

&lt;p&gt;You are happy that the pull request satisfies the feature requirement and follows coding convention, so click &lt;strong&gt;Approve&lt;/strong&gt; near the top right to approve it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZccyhRhZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mcvk0glhkehrgqychbjf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZccyhRhZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mcvk0glhkehrgqychbjf.png" alt="Pull request approved"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A green tick and your user's avatar is placed next to the Approve button to show you have approved it. Click on the &lt;strong&gt;Overview&lt;/strong&gt; to the left of the Files tab:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--W2Tv05lv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xdarhv1w8q4kkukfuvhf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--W2Tv05lv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xdarhv1w8q4kkukfuvhf.png" alt="Pull request approved updated overview"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The overview screen has been updated with the approval. In the left hand column in the history of the pull request, the Approval is shown as the latest item of history. On the right, the &lt;strong&gt;Policies&lt;/strong&gt; have been updated to state that one of the two required reviewers have approved this pull request. Looking further down on the right under &lt;strong&gt;Reviewers&lt;/strong&gt;, there is a tick next to your user's name, you have reviewed and approved the pull request.&lt;/p&gt;

&lt;p&gt;You still cannot complete this pull request. The user you added as part of this guide must review and approve the pull request first. Open another browser and sign into as the new user. Note you'll need to include the Organisation on the URL. In this example, my organisation is &lt;code&gt;devopsdemo0755&lt;/code&gt;, so my url would be &lt;code&gt;https://dev.azure.com/devopsdemo0755&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Enter the dotnetcoredemo project, then navigate to the pull requests list page using &lt;strong&gt;Repos&lt;/strong&gt; on the left hand side menu, and then &lt;strong&gt;Pull requests&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Tovl5i7_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nebbm95xfmm80hf5xkqc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Tovl5i7_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nebbm95xfmm80hf5xkqc.png" alt="Pull request list"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The list displays that there is a required approval assigned to you. Click on the pull request name to enter the pull request overview page. You are going to approve this pull request, but first look at the options a user has after the review. Click on the dropdown arrow to the right of &lt;strong&gt;Approve&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6dfgwJVg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5fr3d5qf05hm62v264mg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6dfgwJVg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5fr3d5qf05hm62v264mg.png" alt="Pull request approve options"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Approve - agree with the changes as they are.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Approve with suggestions - approves the pull requests, but opens a text box to leave suggestions for the author to improve the code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Wait for author - you can add comments to the overview screen, this option signals that you wish the author to review your comments before continuing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reject - the changes are not acceptable, you must leave a comment to explain why.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hit &lt;strong&gt;Approve&lt;/strong&gt; in the list, the pull request approval screen is updated once more:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sBG2XQbZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yrqgm2srh3ztnmsmxg4c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sBG2XQbZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yrqgm2srh3ztnmsmxg4c.png" alt="Pull request updated overview screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the left hand history trail, the approval by your new user has been added. Moving to the right at the bottom, you have ticks next to both required &lt;strong&gt;Reviewers&lt;/strong&gt;. Moving to the top right, you have two ticks next to your &lt;strong&gt;Policies&lt;/strong&gt;. Two reviewers have approved and the required reviewers have approved. All of your &lt;strong&gt;Policies&lt;/strong&gt; have now been met, and the &lt;strong&gt;Complete&lt;/strong&gt; button has become enabled top right. Click the &lt;strong&gt;Complete&lt;/strong&gt; button to merge the changes into master:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5Tm1T25t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/k4fs3gz23ozxopd89pys.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5Tm1T25t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/k4fs3gz23ozxopd89pys.png" alt="Complete merge"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Complete pull request popup is displayed. The title of the pull request is brought through to become the complete comment. If there are any associated work items for this pull request, these can be automatically set to completed by ticking &lt;strong&gt;Complete associated work items after merging&lt;/strong&gt;. The user you are now logged in as does not have the permissions to delete the feature branch, so this option is greyed out. Click &lt;strong&gt;Complete merge&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--N1KpbcWP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cm3yhxeni5jykznky1zw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N1KpbcWP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cm3yhxeni5jykznky1zw.png" alt="Updated overview with complete"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The pull request is marked as complete, with the username that completed it and the complete comment is also displayed.&lt;/p&gt;

&lt;p&gt;Go back to the other browser which is logged into Azure DevOps as your original user. Click &lt;strong&gt;Repos&lt;/strong&gt; on the project menu, then &lt;strong&gt;Branches&lt;/strong&gt; and select the master branch. This opens the files that are on the master branch. You can see that the README.md has the commit against it that came from the feature branch you merged in. Scrolling down you can see the text in the README.md itself, confirming that the merge was successful.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MXEAtpyb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0ymsvgfguvl6e7vahxcl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MXEAtpyb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0ymsvgfguvl6e7vahxcl.png" alt="Complete merge branch view"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you now click the &lt;strong&gt;History&lt;/strong&gt; tab towards the top of the screen, you can see a detailed view of the commits against the master branch and where pull requests were merged in. This is showing a key part of how Git works on merging. Not only are your code changes brought across, but also the history of your changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7BfgzvOt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/a6pkwkmuwyyq9kjw05cy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7BfgzvOt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/a6pkwkmuwyyq9kjw05cy.png" alt="Complete merge branch view"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note, it is possible to condense the history of a branch when merging, this concept is beyond a beginners guide.&lt;/p&gt;

&lt;p&gt;You have confirmed that your code changes and commit history have now been safely merged into the master branch. You can now go ahead and delete the feature branch, the next step will take you through deleting a feature branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 — Deleting a feature branch
&lt;/h2&gt;

&lt;p&gt;When using Git it's considered good practice to delete your branches once you're finished using them. Apart from being a good housekeeping exercise, this practice means that all of the branches in your repo are current and actively being worked on.&lt;/p&gt;

&lt;p&gt;First, make sure you are in the Azure DevOps browser window which is logged in as your original user. If you are logged in as the new user, you will not be able to delete the branch in Azure DevOps as that user does not have permissions to do so. Navigate back to the branches list using &lt;strong&gt;Repos&lt;/strong&gt; on the main project menu and then &lt;strong&gt;Branches&lt;/strong&gt;. Move your mouse to the right of the branch which has been merged in the previous step. On the hidden menu of &lt;strong&gt;...&lt;/strong&gt; choose &lt;strong&gt;Delete branch&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tNcgyX0a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qrvmd4ee9oa7y4re35b1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tNcgyX0a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qrvmd4ee9oa7y4re35b1.png" alt="Delete branch option"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A popup is shown to check you are sure you want to delete the branch. Click &lt;strong&gt;Delete&lt;/strong&gt;, your branch is deleted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KK1CW0Ax--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/95mc5myna5wamdvxochv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KK1CW0Ax--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/95mc5myna5wamdvxochv.png" alt="Delete branch are you sure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you recall the Complete pull request screen from the previous step, there was the option to &lt;strong&gt;Delete users/nicole/home-blog-feature after merging&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4nLNezTf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4lkde6vbhfjjj9bjan56.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4nLNezTf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4lkde6vbhfjjj9bjan56.png" alt="Complete merge auto delete"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the user had the permissions, and the tick box had been checked, the branch would have been automatically deleted after the merge. Therefore cutting out the manual delete that you have just performed.&lt;/p&gt;

&lt;p&gt;The branch is now deleted in Azure DevOps, but you still have it on your local repo.  You can see this by switching back to the command line and executing &lt;code&gt;git branch&lt;/code&gt; having &lt;code&gt;cd&lt;/code&gt; to your git repo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AP3ljdXr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gpdh2cidc91xmssviah7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AP3ljdXr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gpdh2cidc91xmssviah7.png" alt="Display local branches"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The branch users/nicole/home-blog-feature is still present. You need to move off of the branch you want to delete, so switch to master using &lt;code&gt;git checkout master&lt;/code&gt;. Check you are on the master branch using &lt;code&gt;git branch&lt;/code&gt;. Now issue the delete branch command, this is performed using a &lt;code&gt;-d&lt;/code&gt; on &lt;code&gt;git branch&lt;/code&gt; with the branch name tagged to the end &lt;code&gt;git branch -d users/nicole/home-blog-feature&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--F9LwQDM8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zgpbwfmxpj535ywailg2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F9LwQDM8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zgpbwfmxpj535ywailg2.png" alt="Switch and delete"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This hasn't deleted the branch locally, the error message is saying that the changes in users/nicole/home-blog-feature have not been merged into the master branch. This is to stop users from deleting branches that have not been merged. So far the merge has only happened on the remote at Azure DevOps following completion of the pull request. Therefore, you need to pull the merged changes down from the remote to the local master branch with &lt;code&gt;git pull&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cSNLLhxU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hh5nd574wsydlmgpv8sw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cSNLLhxU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hh5nd574wsydlmgpv8sw.png" alt="Pull master"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You have now pulled the changes from the merged to master on the remote on to your local master. Note the section that is &lt;code&gt;Updating d65422c..4202971&lt;/code&gt;, if you recall the branch history page you looked at in the last step:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Qw4kJNRS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cq1bqrw648ltsa8sfuiq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Qw4kJNRS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/cq1bqrw648ltsa8sfuiq.png" alt="Branch history"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The red boxes are circling &lt;em&gt;commit ids&lt;/em&gt; these are unique identifiers for the commits to a repo. If you look at the first commit id in Azure DevOps and compare to the first one in the command line output, you'll see they are identical. Similarly with the last one in both screenshots. This gives you a small look into what is going on under the hood. If you recall from &lt;a href="https://cloudskills.io/blog/git-azure-devops"&gt;part 1&lt;/a&gt; of this series, a &lt;code&gt;git pull&lt;/code&gt; performs a &lt;code&gt;git fetch&lt;/code&gt; and then a &lt;code&gt;git merge&lt;/code&gt;. In this case &lt;code&gt;git pull&lt;/code&gt; fetches all the changes from the point where the local repo and remote repo diverged. This is from commit &lt;code&gt;d65422c&lt;/code&gt;. If there were changes to the master branch locally, &lt;code&gt;git pull&lt;/code&gt; would try to merge the changes. For this walkthrough there are no changes to merge, so the branch is now at commit &lt;code&gt;4202971&lt;/code&gt;, identical to that of the remote repo.&lt;/p&gt;

&lt;p&gt;If you had decided not to push the branch changes to the remote, you can force the deletion of a branch without a merge using &lt;code&gt;-D&lt;/code&gt; as described in the command line output.&lt;/p&gt;

&lt;p&gt;Try the branch delete command once more &lt;code&gt;git branch -d users/nicole/home-blog-feature&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PbRwyvNz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wto1h0ewm762g77bb7yu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PbRwyvNz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wto1h0ewm762g77bb7yu.png" alt="Branch deleted"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The branch deletes successfully, you can check this by issuing a &lt;code&gt;git branch&lt;/code&gt; and only the master branch exists locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this blog post you have explored feature branches and pull requests with Git and Azure DevOps. You created a local feature branch, this branch enabled you to code in isolation to other developers on your project. You committed your changes locally to your new branch, then pushed this branch to your remote. &lt;/p&gt;

&lt;p&gt;Next, you looked at how to integrate Azure AD to Azure DevOps, securing features of Azure DevOps to users in your Azure AD, therefore streamlining user management. You added a new user in Azure AD and assigned this user a Contributor role to your project in Azure DevOps. This enabled you to setup a minimum of two reviewers for a pull request within a branch policy.&lt;/p&gt;

&lt;p&gt;You created a pull request, using two required reviewers. You noted how each action in the pull request builds up a history for the pull request that can be viewed. You saw how the branch policies stopped the pull request from being completed until all policy requirements were met. Finally, you deleted you feature branch once your changes and history were safely in the master branch.&lt;/p&gt;

&lt;p&gt;This process simulated a small team working on changes and reviewing each others changes ensuring code quality. In the next part of this series you'll work with a sample .Net Core application and push it through a build pipeline.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>azure</category>
      <category>git</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Getting started with Git and Azure DevOps</title>
      <dc:creator>Nicole Stevens</dc:creator>
      <pubDate>Sat, 01 Feb 2020 20:14:26 +0000</pubDate>
      <link>https://forem.com/cloudskills/getting-started-with-git-and-azure-devops-1i7a</link>
      <guid>https://forem.com/cloudskills/getting-started-with-git-and-azure-devops-1i7a</guid>
      <description>&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;Step 1 - Setup a Repo in Azure Devops&lt;/li&gt;
&lt;li&gt;Step 2 - Cloning the Azure Repo&lt;/li&gt;
&lt;li&gt;Step 3 - Saving changes with commit and push&lt;/li&gt;
&lt;li&gt;Step 4 - Updating Code with fetch and pull&lt;/li&gt;
&lt;li&gt;Step 5 - Pushing an exitisting repository from the command line&lt;/li&gt;
&lt;li&gt;Step 6 - Working with GitHub&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;According to the &lt;a href="https://services.google.com/fh/files/misc/state-of-devops-2019.pdf" rel="noopener noreferrer"&gt;State of DevOps 2019&lt;/a&gt;, best practice use of version control is one of the foundations for improving Software Delivery and Operational (SDO) Performance. In this first part of a three part guide, you'll be working with Git and Azure DevOps to setup a repository which you'll use for source control. Source control, also known as version control, has many benefits, each of these benefits come together to create a feedback loop to a team working on the code under version control. These benefits include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Collaboration - teams can work concurrently, even on the same sections of code, which are merged together.&lt;/li&gt;
&lt;li&gt;Workflows - teams check the quality of each others code, ensuring compliance with coding standards.&lt;/li&gt;
&lt;li&gt;Versioning - source code can be tagged so that released versions of code can be referred back to.&lt;/li&gt;
&lt;li&gt;History - a full history of the code repository is maintained and linked to a users credentials. If changes are well commented, this can assist in issue resolution.&lt;/li&gt;
&lt;li&gt;Automation - actions within a version control system, such as checking in a code change, can be set to trigger other operations, such as compilation and testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you've worked your way through part one of this guide you'll be able to work with Git, a distributed version control system. You'll setup a code repository as part of a project in Azure DevOps, and a single repository in GitHub, enabling you to work with remote version control in the cloud. You'll be able to initialise both repositories, create copies of them locally and make changes to the files within those repositories locally. Once your changes are complete you'll be able to push those changes back to the Azure DevOps or GitHub repository, using the processes that will enable you to collaborate with a team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Before working through this guide you will need the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;An &lt;a href="https://azure.microsoft.com/en-us/" rel="noopener noreferrer"&gt;Azure Subscription&lt;/a&gt;, you can create a free account.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An &lt;a href="http://dev.azure.com/" rel="noopener noreferrer"&gt;Azure DevOps Organisation&lt;/a&gt;, the basic plan starts with the first five users for free.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A &lt;a href="https://github.com/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; account, sign up to the free plan, this gives you unlimited repositories.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A local installation of &lt;a href="https://code.visualstudio.com/download" rel="noopener noreferrer"&gt;Visual Studio Code (VSCode)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A local installation of &lt;a href="https://git-scm.com" rel="noopener noreferrer"&gt;Git&lt;/a&gt;, following the &lt;a href="https://git-scm.com/book/en/v2/Getting-Started-Installing-Git" rel="noopener noreferrer"&gt;install guide&lt;/a&gt; for your OS. If you are using Windows, ensure the box is checked to &lt;strong&gt;Enable Git Credential Manager&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fitq2hrqt3sk4e7ilzj44.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fitq2hrqt3sk4e7ilzj44.png" alt="Enable Git Credential Manager"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you installed VSCode before Git, you will also be presented with this option:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpe6tpezjfrczcrw42m01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpe6tpezjfrczcrw42m01.png" alt="Choosing the default editor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This allows you to launch VSCode as the default code editor or difference tool, straight from git on the command line.  Please leave as VSCode for this guide, you can reinstall later to pick a different IDE.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1 — Setup a Repo in Azure DevOps &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;In this step you will setup a project within Azure DevOps. An Azure DevOps project can be either public or private, where private projects require a user to be invited before the project can be viewed, cloned or contributed to.&lt;/p&gt;

&lt;p&gt;A repository is a place to store version controlled code, enabling one or more developers to collaborate on the code, keeping a history of all changes.  This is known as source control. You'll be adding a project which will automatically create a repository, this will enable you to add code and make changes to that code in further steps, simulating how an individual or team works with source control.&lt;/p&gt;

&lt;p&gt;First, you need to setup a project, open a browser and navigate to &lt;a href="http://dev.azure.com/" rel="noopener noreferrer"&gt;Azure DevOps&lt;/a&gt; and login the credentials which you used to create the Azure DevOps organisation in the prerequisites.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fk4s6lh1h7u5wmb71q2bq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fk4s6lh1h7u5wmb71q2bq.png" alt="Start free"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The option, Choose Start free with GitHub, is for teams already using source control in GitHub. In this guide you have no version controlled code and want the repositories to sit within Azure DevOps, so choose &lt;strong&gt;Start free&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Next enter a &lt;strong&gt;Project name&lt;/strong&gt;, the main steps in this guide use dotnetcoredemo. For &lt;strong&gt;Project visibility&lt;/strong&gt;  choose to use a private project, this gives you control over who has access to your project.  If you were running an open source project, this would be public. Last pick an appropriate &lt;strong&gt;Country/region&lt;/strong&gt; for your locality.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4l91pneqfppj0zxe2c30.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4l91pneqfppj0zxe2c30.png" alt="Create a project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The project is created and the project page for dotnetcoredemo is opened:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F496iyyy1nquib1o1otb6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F496iyyy1nquib1o1otb6.png" alt="Open new project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is an empty project, the menu on the left shows the services, Boards, Repos, Pipelines and Test Plans. For this step you want to be working with a repository so choose &lt;strong&gt;Repos&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhg703qqebjl1wxrimam6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhg703qqebjl1wxrimam6.png" alt="View empty Repo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a view of an empty repository, to work with this repository locally, either from the command line or from a client, you will need to generate credentials. On this page you can see a button marked &lt;strong&gt;Generate Git Credentials&lt;/strong&gt;, this will allow you to set a username and simple password to work with the repository.  However, it is not recommended, as these credentials have full access to the repository, along with other services and do not expire. The Microsoft Docs article &lt;a href="https://docs.microsoft.com/en-gb/azure/devops/repos/Git/auth-overview?view=azure-devops" rel="noopener noreferrer"&gt;Authentication overview&lt;/a&gt; for Azure DevOps recommends to use a Personal Access token, where scope of access and an expiration date can be set.&lt;/p&gt;

&lt;p&gt;To create a Personal Access Token, click to open the account settings menu which is top right, then choose &lt;strong&gt;Personal access tokens&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fra7zddlp8mgmk2r2cjxm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fra7zddlp8mgmk2r2cjxm.png" alt="Account settings menu, Personal access tokens"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can now see a list of all of your personal access tokens, as this was an empty organisation you will only see the default token created when the organisation was created.  Click on &lt;strong&gt;New Token&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fodga38r03mopdix896ra.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fodga38r03mopdix896ra.png" alt="List of Personal access tokens"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The form to create the Personal access token is displayed:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fffut9g1f8rj4w73weqrf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fffut9g1f8rj4w73weqrf.png" alt="Create PAT form"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Working through the options, &lt;strong&gt;Name&lt;/strong&gt; is the name of your Personal access token, it needs to be unique for your tokens. &lt;strong&gt;Organization&lt;/strong&gt; is your Azure DevOps organisation, at the moment you have one. However, if the logged in user has been granted access to multiple organisations, you can choose "All accessible organizations" from this dropdown. &lt;strong&gt;Scopes&lt;/strong&gt;, here you choose which services this Personal access token can work with. Select &lt;strong&gt;Custom defined&lt;/strong&gt;, as you will want to be using the principal of least-privilege.  Each &lt;a href="https://docs.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/oauth?view=azure-devops#scopes" rel="noopener noreferrer"&gt;scope&lt;/a&gt; maps to a set of permissions for one of the services you saw on the left when you entered Azure Devops for the first time.  For this guide you want to work with code, to read and write from the repository, so choose &lt;strong&gt;Read, write, &amp;amp; manage&lt;/strong&gt; and status from the &lt;strong&gt;Code&lt;/strong&gt; section. Scroll up and down through the Scopes to get an idea of how a Personal access token can be tailored, leave all other scopes unchecked. Click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9s5q92h3trtydsx2qqmx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9s5q92h3trtydsx2qqmx.png" alt="Create Personal access token success"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your Personal access token has been created and can be copied from the successful creation page. Note here the warning from Microsoft, once a Personal access token has been generated and this page closed, it cannot be recovered.  Therefore, you must store this securely.  If the token contents are lost, it can be regenerated. To regenerate a token, select the token in your Personal access token list and click regenerate:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgq821r298cjw2qzxshrp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgq821r298cjw2qzxshrp.png" alt="Create Personal access token regenerate"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The success screen is displayed once more and the regenerated token can be copied.&lt;/p&gt;

&lt;p&gt;If the token is compromised, it can be revoked, which removes the token from the PAT list.&lt;/p&gt;

&lt;p&gt;You now have a Personal access token to access your Repo, so the next step is to start working with the Repo locally. Click &lt;strong&gt;Azure DevOps&lt;/strong&gt; in the top left of the page to take you to your Azure DevOps Organisation home, choose the project that you created earlier, &lt;strong&gt;dotnetcoredemo&lt;/strong&gt; and you are returned to the project page with the resources for the project listed in the menu on the left. Click &lt;strong&gt;Repos&lt;/strong&gt; on this menu to enter the empty repository page. The repository is currently empty, you can choose to initialise it with some common repository files. &lt;/p&gt;

&lt;p&gt;Scroll down to the bottom of the Repo page to the &lt;strong&gt;Initialize with a README or gitignore&lt;/strong&gt; section. Ensure &lt;strong&gt;Add a README&lt;/strong&gt; is checked, this will create a readme file at the root of the repository. Typically, a readme gives instructions on how to use the repository, a readme file is a &lt;a href="https://daringfireball.net/projects/markdown/" rel="noopener noreferrer"&gt;markdown&lt;/a&gt; file. You will also want to add a .gitignore file, this file instructs git to ignore directories and file types that are required for your project, but should not be stored under source control in your repository. In this part of the guide we are going to use simple text files, but for an example of a working .gitignore, we will setup the project for .NET, so use the dropdown to select &lt;strong&gt;VisualStudio&lt;/strong&gt;.  Click &lt;strong&gt;Initialize&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5g11hdykizsl6mbv2rc6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5g11hdykizsl6mbv2rc6.png" alt="Initialise DevOps Repo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your Repo is no longer empty, you can see the file list which now contains the readme and .gitignore. The readme is stored at the root of the Repo and is automatically displayed on the page as it is expected to contain instructions on how to use the Repo. Click on the .gitignore file to view an example of a setup for a software development project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 - Cloning the Azure Repo &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;In this step you'll look at &lt;em&gt;cloning&lt;/em&gt; a repository to create a local copy on your file system, enabling you &lt;/p&gt;

&lt;p&gt;When working on code stored in a distributed system such as Git, which is the backend for an Azure DevOps Repo, you take a full copy of a repository by cloning the repository. This recreates the entire history of the repository locally on the users machine. Click &lt;strong&gt;Clone&lt;/strong&gt; in the top right:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F23tx9rfeq8f6e966fhzp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F23tx9rfeq8f6e966fhzp.png" alt="Git clone url"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;strong&gt;IDE&lt;/strong&gt; section there is the option to &lt;strong&gt;Clone in VS Code&lt;/strong&gt;, this will launch VSCode, prompt where to save the repository locally, and open VSCode session with the newly downloaded repository open as a folder in VSCode.  Looking at the screen shot below, you can also see the same feature is available with other IDE's:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv3jrewy9h7gxqy3zd5dl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv3jrewy9h7gxqy3zd5dl.png" alt="Git clone url"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this guide you are going to use Git on the command line, this will allow you to understand the mechanics of what each command is doing as it will not be hidden by an IDE.  To do this click the copy button (shown in red above).&lt;/p&gt;

&lt;p&gt;Open a command prompt locally, and &lt;code&gt;cd&lt;/code&gt; to the directory you would like to clone the repository into. Type &lt;code&gt;git clone&lt;/code&gt; at the prompt, this is the git command for cloning, and then paste in the URL copied from Clone Repository above, this instructs Git where to Clone the repository from:&lt;br&gt;
Hit return, and you will be prompted to enter a password. At the password prompt, paste in the Personal access token you saved earlier and hit return once more.  If the credentials are correct, the Repo is cloned:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcot9t86qpj09i8mbtbi2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcot9t86qpj09i8mbtbi2.png" alt="Git clone command"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The highlighted section in white shows the password being accepted for the Repo and the four objects being cloned to the machine locally. You only created two files, a readme and .gitignore, why are there four objects:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8jyawz2bzlycrhda3dcd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8jyawz2bzlycrhda3dcd.png" alt="Git file structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you list the contents of the directory structure using &lt;code&gt;dir /b&lt;/code&gt; (&lt;code&gt;ls&lt;/code&gt; on Mac), you can see the first object, the folder that contains the repository. &lt;code&gt;cd&lt;/code&gt; into the repository folder and list the contents once more, the items listed are the second and third objects, the two files you created in the Azure DevOps portal. Altering the list command slightly to output all files and folders using &lt;code&gt;dir /a /b&lt;/code&gt; (&lt;code&gt;ls -al&lt;/code&gt; on Mac), the hidden .git directory is displayed.  This is the forth object and is where Git tracks the local changes.  Note on a Mac the .gitignore will not be displayed on listing the folder contents without &lt;code&gt;ls -al&lt;/code&gt;, it is treated as a hidden file.&lt;/p&gt;

&lt;p&gt;Note - the first time you connect to your repository on a windows OS you will be prompted to enter the credentials you sign into Azure DevOps with:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1dsiyjfmmhv90rclgqxx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1dsiyjfmmhv90rclgqxx.png" alt="Git status command"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once successfully entered, the Git credential manager creates a Personal access token for you and caches it locally. You can view this by going back to the list of Personal access tokens in Azure DevOps:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6syl7iquvq7jnlhnblhy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6syl7iquvq7jnlhnblhy.png" alt="PAT list after Git credentials manager"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will see a third Personal access token, the name of which has been auto-generated based on the machine name Git generated it from.  You also have default Scope, which may need to be edited.&lt;/p&gt;

&lt;p&gt;You now have a locally cloned repository which has no changes from that on the server.  You can check this using the &lt;code&gt;git status&lt;/code&gt; command:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvk6jrmkhziouch8s6586.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvk6jrmkhziouch8s6586.png" alt="Git status command"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The highlighted section shows that there are no changes.  Next you'll look at adding changes back to the locally cloned repository and then into the Azure Repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 - Saving changes with commit and push &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;When you work with code within a repository, the repository needs to be instructed that you want changes you have made to the code within it to be &lt;em&gt;committed&lt;/em&gt; to the repository. The process of committing saves your changes to the repository, tracking the changes and linking them to your credentials. It is best practice to group your commits into work items, such as a defect fix from issue tracking software, or a completed task from a sprint. This will keep the changes small, updating often, this will avoid conflicts when merging back with other changes. Until the point of commit, changes are not tracked in the repository, only on the local file system.&lt;/p&gt;

&lt;p&gt;To see this in action you need to edit your local repository files, to do this you can launch VSCode from within the repository folder on the command line using the &lt;code&gt;code .&lt;/code&gt; command:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj57zkp4u02kqr4vphu9p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj57zkp4u02kqr4vphu9p.png" alt="Open VSCode from command line"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VSCode opens with the dotnetcoredemo repository opened in the explorer view on the left hand side. Clicking on the &lt;span&gt;readme.md&lt;/span&gt; opens the file in the editor:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8anx6zgkg6pmc8pm16eu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8anx6zgkg6pmc8pm16eu.png" alt="Open readme.md"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Edit the header change the text to &lt;code&gt;# Introduction to Azure Repos&lt;/code&gt; and save your changes. Switch back to the command prompt and run &lt;code&gt;git status&lt;/code&gt; once more from within the dotnetcoredemo directory:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpfdt4yym8jdtesouvfvi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpfdt4yym8jdtesouvfvi.png" alt="Git status with changes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Git status has picked up that there is a modification to a tracked file on the file system and has displayed this, if there was more than one change, all changes would be listed here. At this point the repository is not tracking the listed changes, the notice that &lt;strong&gt;Changes are not staged for commit&lt;/strong&gt;, indicates this is the case.  To track the changes you first need to &lt;em&gt;stage&lt;/em&gt; the changes. For this you need to issue the &lt;code&gt;git add&lt;/code&gt; command. You can stage a single file using it's filename with the &lt;code&gt;git add filename&lt;/code&gt; command or if you have more than one change to stage, you can use a full stop &lt;code&gt;git add .&lt;/code&gt;, to add all changes. If you now re-run &lt;code&gt;git status&lt;/code&gt; :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft0ybelmn504hxvo7rba5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft0ybelmn504hxvo7rba5.png" alt="Git status with staged changes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The filename is now shown in green, it has been staged and is ready to be committed to the repository to be tracked locally. Issue the commit command &lt;code&gt;git commit -m "commit message"&lt;/code&gt;, where the commit message describes the change, or details a work item such as a defect number:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9w99rdamwp8nh3tw84ny.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9w99rdamwp8nh3tw84ny.png" alt="Git commit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The unique identifier for the commit is displayed first, along with a summary of what has changed.  If you now issue a &lt;code&gt;git status&lt;/code&gt; as shown above, you can see that your local repository is described as 1 commit ahead of the Repo is was cloned from, this is because you have committed one change since you checked out from the Azure DevOps Repo.&lt;/p&gt;

&lt;p&gt;Your change has now been tracked locally, but you haven't updated the Repo to store the changes in Azure. To do this you need to use the &lt;code&gt;git push&lt;/code&gt; command to push the committed changes from your local repository in to the Azure Repo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F03pugn41b4vrle0hj4qh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F03pugn41b4vrle0hj4qh.png" alt="Git push"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see the git push command compressing the committed changes and pushing them to the Azure DevOps Repo. Once this process is complete, if you re-issue &lt;code&gt;git status&lt;/code&gt;, the message &lt;strong&gt;Your branch is up to date with 'origin/master'&lt;/strong&gt; indicates that the local and Azure DevOps Repo are back in synch.&lt;/p&gt;

&lt;p&gt;Switch back to the Azure DevOps portal, this time click on &lt;strong&gt;Commits&lt;/strong&gt; under the &lt;strong&gt;Repos&lt;/strong&gt; menu item on the left hand side:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmjkvuwdjjjy420s01wcl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmjkvuwdjjjy420s01wcl.png" alt="Azure DevOps Repos Commits"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Commits page shows the list of commits against this Repo, if you now click on the &lt;strong&gt;Commit&lt;/strong&gt; text of the Updated the readme commit you can inspect the differences in the files between the two commits:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpcwha796l1r03u69b9pv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpcwha796l1r03u69b9pv.png" alt="Azure DevOps Repos Commits Inline Diff"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This view shows the original line 1, it is in red with the minus sign in front of it, and it's new text in green with the plus sign at the beginning.  When there are multiple changes within a file, this view can be difficult to review, you can change this by clicking &lt;strong&gt;Inline diff&lt;/strong&gt; to switch to the side by side view:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4d182fm8lwv9qicv1p6p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4d182fm8lwv9qicv1p6p.png" alt="Azure DevOps Repos Commits Side by Side Diff"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next you will look at how to bring in committed changes from other users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 - Updating Code with fetch and pull &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Distributed version control systems such as Azure Repos enable teams of developers to work on code and commit changes at the same time. Therefore, there are times when you cannot be sure you have the latest version of the code. When this is the case, you will need to execute some Git commands to ensure you have the latest version in your local repository:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;fetch&lt;/code&gt; - downloads the changes from your remote repo, but does not apply them to your code. This allows you to take a look at the changes before applying them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;merge&lt;/code&gt; - applies the changes taken from a fetch to a branch on your local repository. Once you have looked at the fetched changes and decided they are suitable to add to your code, you choose to &lt;code&gt;merge&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;pull&lt;/code&gt; - combines the above, does a &lt;code&gt;fetch&lt;/code&gt; and then a &lt;code&gt;merge&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To simulate another developer making a change and pushing it to the Azure Repo, switch back to the Azure DevOps portal, click &lt;strong&gt;Files&lt;/strong&gt; under the &lt;strong&gt;Repos&lt;/strong&gt; menu item on the left hand side, and click on the README.md filename to open the file in &lt;strong&gt;Preview&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv10nlzzx88gwg15mfmv5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv10nlzzx88gwg15mfmv5.png" alt="Azure DevOps Repos File Preview"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If Azure DevOps knows how to display a filetype, such as Markdown, it will open in file preview, formatting the file appropriately. To edit the file click &lt;strong&gt;Edit&lt;/strong&gt; top right:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5rwxq9qg2ujecbs2om91.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5rwxq9qg2ujecbs2om91.png" alt="Azure DevOps Repos File Preview Edit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Edit the file and change the heading &lt;strong&gt;Getting Started&lt;/strong&gt;, click &lt;strong&gt;Commit&lt;/strong&gt; in the top right, you will now be prompted to enter a commit message:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftma91n4dg83mnjlszm03.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftma91n4dg83mnjlszm03.png" alt="Azure DevOps Repos Commit Message"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter your commit message and click &lt;strong&gt;Commit&lt;/strong&gt; at the bottom, in the background Azure DevOps is executing the same &lt;code&gt;git commit -m&lt;/code&gt; command you used in an earlier step. The difference being that Azure DevOps is committing the change to the Azure Repo and not locally. So if you switch back to VSCode and edit the &lt;span&gt;README.md&lt;/span&gt; file, you will see that the heading still says Getting Started.&lt;/p&gt;

&lt;p&gt;The local repository and the Azure Repo are now out of synch, to have the change reflected in the local repository you &lt;em&gt;pull&lt;/em&gt; the changes to your local repository.  This will execute a &lt;code&gt;git fetch&lt;/code&gt; and a &lt;code&gt;git merge&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy6ozypljoqo0dezo5ur7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy6ozypljoqo0dezo5ur7.png" alt="Azure DevOps Repos Commit Message"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The change made in Azure DevOps has now been pulled down to the local repository, if you switch back to VSCode, the change to the header line is now visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5 - Pushing an existing repository from the command line &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;You've explored working with a repository created with Azure DevOps, by cloning that repository locally, pushing to, and pulling changes from the Azure Repo. What happens if you have already got a local repository and need to push that repository to a new Azure DevOps project? To simulate this you need to &lt;em&gt;intialise&lt;/em&gt; a new git repository locally, you will then add a README to this repository and push it to a new Azure DevOps project.&lt;/p&gt;

&lt;p&gt;Initialising a repository creates an empty repository using the same method utilised by Azure DevOps in Step 1.  Both of these processes both use the &lt;code&gt;git init&lt;/code&gt; command.  When executing the command locally, it must be executed within folder that does not already contain a git repository, however, the folder does not have to be empty:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4bw9uvr4umav5g7fh0rd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4bw9uvr4umav5g7fh0rd.png" alt="Local repository initialisation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The process here is to make a new empty folder using &lt;code&gt;mkdir&lt;/code&gt; on the command line, &lt;code&gt;cd&lt;/code&gt; into that folder and then execute &lt;code&gt;git init&lt;/code&gt;. The section highlighted above shows the Git repository being initialised and then &lt;code&gt;dir /a /b&lt;/code&gt; (&lt;code&gt;ls -al&lt;/code&gt; on a Mac) to display that the repository is empty, apart from the newly created .git folder.&lt;/p&gt;

&lt;p&gt;Next, you need to add a file to simulate code being present in the local repository.  Execute &lt;code&gt;code .&lt;/code&gt; on the command line to launch VSCode within the repository and then create a README.md file for the repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fr11wvnpub0y6u2qzlvfx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fr11wvnpub0y6u2qzlvfx.png" alt="Local repository initialisation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter some text within the file and save. Switch back to the command line and execute &lt;code&gt;git status&lt;/code&gt; to verify that Git has picked up the change on the file system.  Now execute &lt;code&gt;git add .&lt;/code&gt; to stage all changes ready for commit, then commit the change using &lt;code&gt;git commit -m&lt;/code&gt; and add an appropriate message:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbk8fcpx1hha2zge9lvfr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbk8fcpx1hha2zge9lvfr.png" alt="Local repository add and commit README"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You now need to create a new project within Azure DevOps, so switch to the Azure DevOps portal and click &lt;strong&gt;Azure DevOps&lt;/strong&gt; top right to return to your Azure DevOps organisation, click &lt;strong&gt;New project&lt;/strong&gt; in the top right hand corner, this opens the add project page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6j9698mncc12t1z11yf0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6j9698mncc12t1z11yf0.png" alt="Local repository create Azure DevOps project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The create project page displayed is slightly different than the one displayed for a new Azure DevOps organisation.  You will need to enter the &lt;strong&gt;Project name&lt;/strong&gt;, making it the same as the folder name of your local repository. If you scroll to the bottom of the page, you can also select &lt;strong&gt;Version control&lt;/strong&gt; which always defaults to Git, but can be changed to Team Foundation Server.  Click &lt;strong&gt;Create&lt;/strong&gt; to create the new project.  When the new project is created, click on &lt;strong&gt;Repos&lt;/strong&gt; in the services menu on the left, you will see the same empty repo page as viewed in step 1. Scroll down to &lt;strong&gt;Push an existing repository from command line&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2p5rc7rr5vobzzxy7aw1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2p5rc7rr5vobzzxy7aw1.png" alt="Url for origin remote"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you can see the URL for the &lt;em&gt;remote&lt;/em&gt; called origin. A remote repository in Git is a version of the project hosted either on the internet or on a local network, in the case of this guide, within Azure DevOps. Origin is just the default name for the URL, it's shorthand name.  If you execute &lt;code&gt;git remote&lt;/code&gt; from inside a repository, all remotes for the repository are listed:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdjw96xkfs62ba9glt7n0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdjw96xkfs62ba9glt7n0.png" alt="List repository remotes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You have a new locally intialised repository with no remotes, so none are listed at this stage. Switch back to Azure DevOps and copy the first part of the command for pushing an existing repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzop12017y1dypgtn7833.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzop12017y1dypgtn7833.png" alt="Add remote called origin"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The remote has been added and re-issuing &lt;code&gt;git remote&lt;/code&gt; lists origin as a remote. You now need to push your changes up to the origin, to do this execute &lt;code&gt;git push origin master&lt;/code&gt;, this pushes all changes from the local master branch to the origin:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F80jhszr6jnkjwfkvn9m3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F80jhszr6jnkjwfkvn9m3.png" alt="Push local master to origin"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Switch back to Azure DevOps portal, click &lt;strong&gt;Repos&lt;/strong&gt; and then &lt;strong&gt;Files&lt;/strong&gt; on the services menu for the localgitinitdemo project, the Repo now reflects the repository pushed up from local:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdqdfpjyk3jbunke8js29.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdqdfpjyk3jbunke8js29.png" alt="Push local master to origin"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6 - Working with GitHub &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Azure DevOps Repos is just one of the Git backed source control systems where repositories can be stored remotely. GitHub is also a Git backed system, it was a forerunner to Azure DevOps Repos. GitHub is the industry standard collaboration platform for open source software projects, enabling developers to contribute to code repositories all over the world. In this Step you will look at working with GitHub repositories using Git.&lt;/p&gt;

&lt;p&gt;Sign into GitHub with the credentials used to create the GitHub login in the prerequisites step:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9mww04ymln03ib2sfk21.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9mww04ymln03ib2sfk21.png" alt="Empty GitHub project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is an empty project, there are no repositories in it yet. Click &lt;strong&gt;New&lt;/strong&gt; top right to add a new repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbzm9g8ao6jhm83o2bg4z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbzm9g8ao6jhm83o2bg4z.png" alt="Create GitHub repository"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The content this page requires is the same as that of an Azure Repo.  Enter a &lt;strong&gt;Repository name&lt;/strong&gt;, leave the repository at it's default of &lt;strong&gt;Public&lt;/strong&gt;, you can also initialise a README.md and a .gitignore. The extra dropdown allows you to choose an open source license for this repository, which is very common on GitHub.  Click &lt;strong&gt;Create repository&lt;/strong&gt;, the repository is created and the repository page is automatically loaded:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhgixmjvz8hnmzeaogss4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhgixmjvz8hnmzeaogss4.png" alt="Setup GitHub repository"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Scrolling down through the repository page, you can see git commands for creating a new repository or pushing a new repository from the command line.  These commands are exactly the same as those for Azure DevOps, the difference is the address of the remote, which is pointing at your GitHub repo.  To explore this start by initialising a local repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv52r8w1mapd7zjd9hr4l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv52r8w1mapd7zjd9hr4l.png" alt="Initilaise local GitHub repository"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The commands used here are identical to that of Azure DevOps, first create an empty folder with &lt;code&gt;mkdir githubdemo&lt;/code&gt; using the same name as the repo you created in GitHub. Next &lt;code&gt;cd&lt;/code&gt; into the folder and initialise with &lt;code&gt;git init&lt;/code&gt;. Use the &lt;code&gt;echo&lt;/code&gt; command to quickly create a README with a single header &lt;code&gt;echo # Welcome to GitHub &amp;gt;&amp;gt; README.md&lt;/code&gt; (&lt;code&gt;echo "# Welcome to GitHub" &amp;gt;&amp;gt; README.md&lt;/code&gt; on a Mac).  Execute &lt;code&gt;git add .&lt;/code&gt; and &lt;code&gt;git commit -m "message"&lt;/code&gt; to stage and commit your changes locally. You are now ready to push changes to the GitHub repository, however, even though it is a public repository, you still need permissions to access the repository. Switch back to the GitHUb repository in your browser, click on the profile icon in the top right, and click &lt;strong&gt;Settings&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffi1fmg5dygo99ct2xrgq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffi1fmg5dygo99ct2xrgq.png" alt="Initialise local GitHub repository"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Scroll down to the bottom of the Settings menu and click &lt;strong&gt;Developer settings&lt;/strong&gt;. In the left hand menu of the Developer settings page is &lt;strong&gt;Personal access tokens&lt;/strong&gt;.  GitHub uses a similar mechanism to grant access to it's repositories as Azure DevOps. Click &lt;strong&gt;Generate new token&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmmet67wldxpj2fhja8p1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmmet67wldxpj2fhja8p1.png" alt="GitHub Personal access token help"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once again you can see the similarity with Azure DevOps Repos. You need to enter a &lt;strong&gt;Note&lt;/strong&gt; to say who the token is for and grant the &lt;strong&gt;Scope&lt;/strong&gt;, in this case ticking &lt;strong&gt;repo&lt;/strong&gt; to grant access to public and private repositories with this token.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffbvr03vur4w01nae7p2m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffbvr03vur4w01nae7p2m.png" alt="GitHub new Pat options"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Scroll to the bottom of the page and click &lt;strong&gt;Generate token&lt;/strong&gt;, to generate the token:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwjc09je774dawhgxpo00.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwjc09je774dawhgxpo00.png" alt="GitHub generated token"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;The generated token page warms you that you must make a copy, as the token cannot be recovered. Once you have taken a copy of the token, navigate back to the repo page and take a copy of the first command for &lt;strong&gt;…or push an existing repository from the command line&lt;/strong&gt;*. Switch back to your terminal window and execute this command inside the folder where the &lt;code&gt;git init&lt;/code&gt; was run and README.md file created.  This creates a remote called origin which points at your GitHub remote. Now you can execute a &lt;code&gt;git push origin master&lt;/code&gt; to push the local master branch to your remote:  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcg4hg70b7b1hcpemoj9k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcg4hg70b7b1hcpemoj9k.png" alt="GitHub push"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note - on a Windows OS you will be prompted for your github credentials, when the page is displayed enter your username and password as if you were logging into GitHub on your browser:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpgulzmswgsvxryleyf3g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpgulzmswgsvxryleyf3g.png" alt="GitHub Credentials"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you've entered the credentials, if you switch back to GitHub in your browser and navigate back to the Personal access token page, you'll see that entering the credentials has created it's own Personal access token, setting a scope of Repo and Gist:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Foqglafu3qr8ztkekp5dr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Foqglafu3qr8ztkekp5dr.png" alt="GitHub windows credential manager Pat"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will only happen on Windows. On a Mac you will be prompted for your username, and then a password. At the password prompt you must enter the Person Access token that you generated.&lt;/p&gt;

&lt;p&gt;Once you have your changes pushed up, switch to the repository view in GitHub in your browser to check the changes have pushed successfully:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fczhezeehz28bv87xeai0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fczhezeehz28bv87xeai0.png" alt="GitHub check pushed code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The commit message entered is displayed against the commit, and the test added to the markdown can be seen within the &lt;span&gt;README.md&lt;/span&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;In this article, you've explored how to work with Git and Azure DevOps / GitHubs respositories. How to setup an empty repository, then push a current code line to it, or create from scratch within the portal or on the command line.  You've simulated updating your code following a change from a team member, and how to use access tokens to push code from a command line or IDE.&lt;/p&gt;

&lt;p&gt;The next part of this three part series will take you through setting up a workflow which enables the same code lines to be worked on by a team, merging changes, whilst keeping code quality and standard compliance in check.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>azure</category>
      <category>git</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
