Detached HEAD state and remote repositories 🤖👾👩‍💻

I’m currently working on a test automation framework stored in Azure DevOps, and so this post is designed to be a starting point for anyone looking to do something similar. My research had led me to believe that Azure DevOps behaves differently with Git than other remote repositories, so hopefully this guide will clear for you what I needed to know at the start, too. 🥳

Let’s get started! 👩‍💻

Contents 🏷️
👾 Git
👾 AzureDevOps
👾 Pushing to your DevOps branch
👾 Remote and local branches
👾 Merge changes from another branch
👾 Push changes to master DevOps remote branch
👾 Pulling and merging changes
👾 Resources

Git is a free and open source distributed version control system (DVCS). The automation framework is stored in a repository in AzureDevOps, and so we use Git to clone the repository to our computer. We then make changes to the framework on our computer and commit and push those changes to the repository.

Other team members working on the automation framework will be working on the framework in the same fashion on their own computers, and so when we push the changes to the repository we may have to merge the changes from each person together (i.e. if two team members were working on the same file).

I recommend watching this video for an explanation of branching and various Git terms, as well as to visit the Git website. Below is a schematic that ties together some Git terminology:

A Git schematic, showing the cloning of a remote repository on your local computer and how these are pushed back to the remote.

Setting up DevOps and an SSH key should be quite straightforward, and this page should help with that.

Navigate to the web address where your DevOps repository is located, and create your new remote branch by clicking ‘New branch’ from the drop-down menu:

Type in the name of your unique branch, as in the example below and ensure that it’s based on the ‘master’ branch (which is the default branch, i.e. the repository):

On your computer, follow the checklist below of how to setup a local repository on your computer based on the remote repository in DevOps using PowerShell:

  1. Create a local folder in which you want the repository to be located:
    • In your C:\Users\USERNAME folder of your computer, create a new folder. For the purpose of this exercise, we will call it ‘FolderName.’ This is now the directory for the automation framework that is currently not under version control and you want to start controlling it with Git.
  2. Direct Git to the local folder you’ve just created:
    • In PowerShell, type: cd C:\Users\USERNAME\FolderName . Press enter.
  3. Create a new Git repository in that folder:
    • Type: git init . Press enter. A secret .git folder will appear in your new folder.
  4. Now we need to clone the automation framework into our local folder.
    • First, type: git config --global http.sslverify "false" . Press enter.
    • Then type: git clone https://webaddress . Press enter. Follow the prompts in PowerShell – (it may ask you for your username and then password of your DevOps or server account).
  5. Navigate to the TestAutomation folder:
    • Type: cd TestAutomation . Press enter.
  6. To view all of the hidden branches type: git branch –a .

    • The green ‘master’ branch is the branch you are currently on, and is the default branch that Git has created for you in your local repository.
    • The remotes/origin/master branch is a branch named ‘master’ on the remote named ‘origin’ (in DevOps). It is referred to as ‘remotes/origin/master’ or ‘origin/master.’ (Link)
    • The ‘remotes/origin/HEAD’ is the default branch for the remote named ‘origin.’ (Link)
  7. Checkout the branch in which the most up-to-date automation framework is located: git checkout remotes/origin/refactor_login . (Link)

  8. You now have all of those files in your TestAutomation folder. However, what is a ‘detached HEAD’? A ‘detached HEAD’ is when you checkout a specific commit instead of a branch, which in the above example is commit 932651b (and you can cross-check this SHA-1 hash (the number) in DevOps).

  9. To push this to your branch in DevOps, type: git push -f origin HEAD:Charlotte (links: 1, 2). This forces the detached HEAD to be pushed into the Charlotte branch created in DevOps. If you navigate to the branch in DevOps, you should see all of the files there.
  10. Now you can start working on the automation framework on your computer.

Pushing to your DevOps branch
Once you’ve made changes to some of the files on your computer (in your local repository), such as configuring the test automation framework to your computer, you can use this section to push the changes to your DevOps branch.

  1. Open up PowerShell and navigate to your automation framework using something similar to cd YourFolder\TestAutomation and pressing enter.
  2. Type git status and press enter to show you what files have been modified:

  3. Then type git add -A (make sure the A is capital) and press enter to add them to the staging area.

  4. If you type git status and press enter, you will see that the files have been staged:

  5. Type git commit and press enter.
    • You will then be taken to vim where you are asked to type a message:

    • Type a meaningful message such as ‘Automation framework configured to Charlotte’s VM.’ Then press the escape button, type: :wq , and press enter.

  6. To (force) push this to your branch in DevOps, type: git push -f origin HEAD:Charlotte (where ‘Charlotte’ is the name of the branch that you created in DevOps) and press enter. PowerShell may ask you for your username followed by a password.
  7. To check that this has been pushed successfully:
    • Type in git status and press enter, where PowerShell will inform you that there’s nothing to commit:
    • Navigate to your branch in DevOps (and perhaps refresh the page if needed) and you should be able to see your latest push:

Remote and local branches
When first starting with Git and remote repositories, I made the mistake of believing that different branches were synonymous with different folders.
You have to create local branches and work on those because remote branches can’t be worked on directly. You update the local branch with git fetch, then merge into your current branch.

To update from a remote repository, we have to use git fetch origin HEAD:name-of-remote-branch.

However, when you checkout a remote branch, Git will tell you that you’re working in a detached HEAD state. Normally with Git, we do not want to be working in detached HEAD states but on branches. Normally we would checkout a branch, work on that branch, commit the changes locally and then push those changes to the master branch. However, it’s not the way Git works when working Azure DevOps (Azure DevOps apparently works differently from other remote repositories, too), and so we have to get used to working in the detached HEAD state.

Close PowerShell and reopen it. Navigate back to the TestAutomation folder (using cd folder-address-here and pressing enter), and type in git checkout master then press enter (this checks out the local master branch):

Git is telling me that I’m on the master branch currently. I can double-check this by typing in git status and pressing enter, and/or I can type git branch -a to list all of the branches:

In the above screenshot, the branch in green with the asterisk next to it is the branch on which we are. The red branches with remotes/origin/DevOpsBranchName lists the remote branches in Azure DevOps.

Let’s say we want to content of the Charlotte branch in DevOps. If I type git pull remotes/origin/Charlotte and press enter, I get an error:

For some reason, when using Git locally on your computer, it doesn’t recognise Azure DevOps branches as repositories. The way I can get the files in one of these remote branches into my local folder is to type git checkout remotes/origin/Charlotte and press enter:

Git is now telling me that I’ve checked out remotes/origin/Charlotte, and the files will be available locally in my computer’s folders. However, I am now in a detached HEAD state.

A detached HEAD state occurs when a specific commit is checked out instead of a branch. HEAD is a pointer to the latest commit in that branch. When it is detached that means you’re not sitting on a specific branch. Git is telling me that I’m now at commit 1d5e249 (this is known as a SHA number). If I navigate to the Charlotte branch in DevOps I can see that the last commit corresponds with the SHA and includes the accompanying message:

So, you don’t checkout the remote branch but the latest commit in that remote branch. Now, I can type git branch -a and press enter to view all of the branches:

As like before, anything in red that starts with ‘remotes/origin/…’ leads to one of the remote branches in Azure DevOps. The green ‘branch’ with the asterisk is the local ‘branch’ where we’re currently sitting (it’s not a branch but a detached HEAD state), and the white ‘master’ branch is the default local branch that is available for us to move onto should we chose. We can create other local branches, too. However, at the moment, we’re in the detached HEAD state.

The message has advised us to make new local branch so that we can retain the commits we create. To do with, we type git checkout –b branch new-branch-name and press enter. I’m going to create a new local branch called ‘CharlotteBranch’. You can see that I’m not on a detached HEAD anymore:

Now I’m working on CharlotteBranch with all of the files from commit 1d5e249 locally stored in my computer.

When using Git, it’s common to create a new branch for each new feature, bug, fix, or enhancement that you’re working on, in which each branch compartmentalises the commits related to a particular feature. Once completed, this is then pushed and/or merged into the master branch.

Merge changes from another branch
Note that git merge merges the specified branch into the currently active branch. This link helps with how to resolve any merge conflicts you may encounter.

  • Follow the instructions above to make the detached HEAD from the branch with the latest commit into a local branch on your computer.
  • Then type: git checkout "name of branch you want to merge INTO" and press enter.
  • Then type: git merge "name of branch you want to merge FROM" and press enter. (Link)
  • Delete the local branch you no longer need by typing: git branch -d "local branch name". (Link)
    Push changes to master DevOps remote branch
    After completing some work on your local branch (created after following the instructions in remote and local branches to create your own local branch), and now you want to push them to remote branches in DevOps:
  • To add all of the files you’ve changed, write: git add --all . Then press enter.
  • Then change to your local master branch: git checkout master . Press enter.
  • Merge the contents of the local branch (in which you worked on the files that you want to add to DevOps) to the local master branch: git merge "local-branch" . Press enter.
  • Commit the files: git commit . Press enter.
    • You will then be taken to vim where you are asked to type a message. Type a meaningful message such as ‘first commit to set up repository.’ Then press the escape button, and type in: :wq , and press enter.
  • Then push to master: git push origin master . Press enter.
  • To push this to another branch in DevOps, type: git push origin HEAD:RemoteBranch (where ‘RemoteBranch’ is the name of the branch that you created in DevOps) and press enter. PowerShell will ask for your username then followed by your password.
    Pulling and merging changes
    At the start of each new working day, before starting work on your branch you may wish to pull changes from the master repository so that you’re working with the most up-to-date automation framework. However, it’s recommended not to use git pull, but to use git fetch and then git merge. Why? Because git pull is magical and combines many steps in one, and so when something goes wrong it’s more difficult to understand why or what has gone wrong. The other problem is that by both fetching and merging in one command, your working directory is updated without giving you a chance to examine the changes you’ve just brought into your repository.

    After logging onto your computer for the first time of a day, and you want to pull changes from the remote master branch in DevOps onto your VM, follow these instructions:

  • git add --a
  • git commit (this ensures that any files you’ve been working on are saved in a commit; type your message then press the escape button, type :wq and press enter)
  • git checkout master (unless you already were working on the local master branch)
  • git fetch (type in your username and password when prompted)
  • git pullAfter I pulled from the remote master branch, I got a merge conflict in the config.ini file:

    Upon navigating to the conflict.ini file, I can see the merge conflicts. To see the beginning of the merge conflict in your file, search the file for the conflict marker <<<<<<<. You’ll see the changes from the HEAD or base branch after the line <<<<<<< HEAD. Next, you’ll see =======, which divides your changes from the changes in the other branch, followed by >>>>>>> BRANCH-NAME.

    Decide if you want to keep only your branch’s changes, keep only the other branch’s changes, or make a brand new change, which may incorporate changes from both branches. Delete the conflict markers <<<<<<<, =======, >>>>>>> and make the changes you want in the final merge.

    Then follow these instructions:

  • git add config.ini (where config.ini is the file in which you’ve just sorted out the merge conflicts)
  • git commit (change the merge message then press the escape button, type :wq and press enter)
  • git pull (and follow the username and password prompts)

    Below is also an example of what your commands may look like to pull the master branch onto your VM and then push your changes back into it:

  • git checkout master
  • git fetch
  • git checkout -b new_branch_name origin/master
  • … make amendments to code …
  • git add
  • git commit -m “Description of changes”
  • git checkout master
  • git merge new_branch_name
  • git push origin master
    When writing my PhD thesis and other publications in LaTeX, our research team used SourceTree, which is a great free Git GUI that I’d recommend. But GitHub was the remote repository and it all seemed much more straightforward using a graphical interface than just the command line. So I hope that this is a clear enough guide to get started with cloning an Azure DevOps repository and navigating your way around version control with some of the basic commands.

    Below are also some cool 😎 resources, too:

    👾 Kill All Defects: Agile Git Integration with GitWorkflows
    👾 DevConnected
    👾 Earth Lab: git clone, add, commit, push Intro version control git
    👾 Integralist: Git internals
    👾 Stack Abuse: Git: Merge Branch into Master
    👾 Andy Leonard: Azure DevOps, SSIS, and Git Part 0 – Getting Started
    👾 Cloud Skills: Getting Started with Git and Azure DevOps: The Ultimate Guide

  • Subscribe
    Notify of
    Inline Feedbacks
    View all comments