Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GitVersion has a bug, your HEAD has moved after repo normalisation. #1627

Closed
LordMike opened this issue Mar 6, 2019 · 19 comments
Closed

GitVersion has a bug, your HEAD has moved after repo normalisation. #1627

LordMike opened this issue Mar 6, 2019 · 19 comments
Labels

Comments

@LordMike
Copy link

LordMike commented Mar 6, 2019

We have a peculiar issue that keeps happening on one specific commit, that is not at the tip of our branch. The latest commit in this branch does not exhibit the issue (so we're past it). I'm creating this issue because it might show some other problem you guys have (and because the exception told me to).

$ --- equivalent of dotnet-gitversion ---
GitVersion has a bug, your HEAD has moved after repo normalisation.

To disable this error set an environmental variable called IGNORE_NORMALISATION_GIT_HEAD_MOVE to 1

Please run `git log --graph --format="%h %cr %d" --decorate --date=relative --all --remotes=* -n 100` and submit it along with your build log (with personal info removed) in a new issue at https://github.com/GitTools/GitVersion
   at GitVersion.GitRepositoryHelper.NormalizeGitDirectory(String gitDirectory, AuthenticationInfo authentication, Boolean noFetch, String currentBranch)
   at GitVersion.GitPreparer.Initialise(Boolean normaliseGitDirectory, String currentBranch, Boolean shouldCleanUpRemotes)
   at GitVersion.ExecuteCore.ExecuteGitVersion(String targetUrl, String dynamicRepositoryLocation, Authentication authentication, String targetBranch, Boolean noFetch, String workingDirectory, String commitId, Config overrideConfig, Boolean noCache)
   at BuildLib.Tasks.ArtBuildTasks.DetermineVersionInfo(ChronosBuildBase buildBase) in C:\Project\Builder\BuildTasks.cs:line 27
   at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy`1.CreateValue()
   at BuildLib.Bases.ChronosBuildBase.<get_GenerateVersionInfo>b__40_1() in C:\Project\Builder\BuildBase.cs:line 118
   at System.Collections.Generic.List`1.ForEach(Action`1 action)
   at Nuke.Common.Execution.BuildExecutor.Execute(NukeBuild build, IEnumerable`1 executionList)
   at Nuke.Common.Execution.BuildExecutor.Execute[T](Expression`1 defaultTargetExpression)

Output of git log --graph --format="%h %cr %d" --decorate --date=relative --all --remotes=* -n 100: git-152228.txt

@LordMike
Copy link
Author

LordMike commented Mar 6, 2019

To clarify: The above means that a git status will show detached head.

@SwooshyCueb
Copy link

In my experience, GitVersion does not like working with a detached head. I'm running into a similar problem, but I've managed to work around it in some cases by running a pre-build script that will update the ref of the relevant branch to the relevant commit and check it out, but then, during normalization, GitVersion will sometimes undo this because it doesn't match the remote ref. (For whatever reason, updating the remote ref doesn't seem to fix this either, even with fetching disabled.)

@stale
Copy link

stale bot commented Jun 29, 2019

This issue has been automatically marked as stale because it has not had recent activity. After 30 days from now, it will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Jun 29, 2019
@pniederlag
Copy link
Contributor

pniederlag commented Jul 3, 2019

Using gitversion inside jenkins with automatic builds I ran into this quite often. For regular branches some 'git update-ref' magic helped prior to running gitversion. I am still struggling for way to get it done for pull-requests, which are intentionally merged onto the target branch on the jenkins-ci for testing,
... some kind of toggle or config to disable this check?

@stale stale bot removed the stale label Jul 3, 2019
@roryprimrose
Copy link

This is hitting us consistently and prevents us from using GitVersion in Jenkins on a linux agent via a docker image

@pniederlag
Copy link
Contributor

here is a snippet from my jenkins lib that seems to work, creating local branches from remote branches prior to starting gitversion did help me greatly

sh 'for MYBRANCH in $(git branch -r); do git branch $(echo $MYBRANCH | sed \'s#origin/##\') $MYBRANCH || echo "fine" ; echo $S; done'

full function:

// will create gitversion.properties and store them as file as well as making them available on global variable semverProperties
def createGitversionProperties() {
  // create local ref for each remote branch if not existent
  // attempt to stabilize gitversion
  sh 'for MYBRANCH in $(git branch -r); do git branch $(echo $MYBRANCH | sed \'s#origin/##\') $MYBRANCH || echo "fine" ; echo $S; done'
  // We must IGNORE errors Gitversion#1701
  docker.image(dockerToolImages.gitversion).inside("--entrypoint='' --env JENKINS_URL=http//empty/ --env IGNORE_NORMALISATION_GIT_HEAD_MOVE=1") {
      //sh "env"
      sh 'dotnet /app/GitVersion.dll -output buildserver'
  }
  semverProperties = readProperties file: 'gitversion.properties'
}

@sboardwell
Copy link

sboardwell commented Jul 26, 2019

Haha, @pniederlag just pipped me to the post 😄

My snippet is a little longer but should hopefully cover all bases.

I had the same problem. Here's our setup:

  • we are using the github-multi-branch plugin
  • we are using GitFlow
  • PRs are build with the PR branch merged with the HEAD of the target branch

Customisations to GitFlow (ignore if you don't have any)

We have a couple of small modifications to our GitFlow process (stable instead of master, dev instead of develop). This doesn't make a real difference to the process but just so you know why stable and dev turn up in the snippet below.

Just in case you have customisations, these need to be added to a GitVersion.yaml at the root of your project, like thus:

$ cat GitVersion.yml
mode: ContinuousDelivery
branches:
  master:
    regex: (stable|master)$
ignore:
  sha: []

The GitVersion Execution Block

We use kubernetes slaves and have the gitversion docker as a side-car container. You can replace the

    container('gitversion') {
        // 2 lines below are for debug purposes - uncomment if needed
        // sh 'dotnet /app/GitVersion.dll || true'
        // input 'wait'
        sh 'dotnet /app/GitVersion.dll'
        sh 'dotnet /app/GitVersion.dll > version.json'
    }

part with your chosen gitversion implementation such as the docker.image(... from @pniederlag

Which pitfalls is this snippet trying to cover.

  • The Branch Sources "Checkout to matching local branch" option (catering for both)
  • The detached HEAD situation caused by a merge to the target branch from an older source branch
  • Cleaning up and returning the workspace back to its original state. Just to be safe since I have no idea:
    • which plugins may use the git repository information afterwards
    • how Jenkins checks out branches and PRs, etc.

The Snippet

Finally 😉

Let me know if anything is unclear. I will edit this comment accordingly if needed.

def processGitVersion() {

    // special case if (a) it's a PR and (b) Merge commit
    // then we need to allow IGNORE_NORMALISATION_GIT_HEAD_MOVE = 1
    env.IGNORE_NORMALISATION_GIT_HEAD_MOVE = sh(
    returnStdout: true,
    script: '''
      # if on a PR
      if git config --local --get-all remote.origin.fetch | grep -q refs\\/pull; then
        # if is merge commit (i.e. has more than 1 parent)
        if [ $(git show -s --pretty=%p HEAD | wc -w) -gt 1 ]; then
          echo -n 1
        else
          echo -n 0
        fi
      else
        echo -n 0
      fi
    '''
    )

    // Determine the current checkout (branch vs merge commit with detached head)
    env.ORIGINAL_CHECKOUT = sh(
        returnStdout: true,
        script: 'git symbolic-ref HEAD &> /dev/null && echo -n $BRANCH_NAME || echo -n $(git rev-parse --verify HEAD)'
    )


    // Fetch CHANGE_TARGET and CHANGE_BRANCH if env vars exist (They are set on PR builds)
    sh '[ -z $CHANGE_BRANCH ] || git fetch origin $CHANGE_BRANCH:$CHANGE_BRANCH'
    sh '[ -z $CHANGE_TARGET ] || git fetch origin $CHANGE_TARGET:$CHANGE_TARGET'

    // Fetch default default branches needed for gitversion using gitflow.
    // NOTE: only fetch if the branch does not exist locally.
    // These are things like master or stable, develop or dev, release-* etc
   sh '''
   for b in $(git ls-remote --quiet --heads origin stable master dev develop release-* hotfix-* | sed "s:.*/::g"); do
       git rev-parse -q --verify $b > /dev/null && echo "Branch $b exists locally" || git fetch origin $b:$b
   done
   '''
    sh 'for b in $(git ls-remote --quiet --heads origin stable master dev develop release-* hotfix-* | sed "s:.*/::g"); do git fetch origin $b:$b; done'

    // Checkout aforementioned branches adding any previously existing branches to the EXISTING_BRANCHES file.
    sh '''
  touch EXISTING_BRANCHES
  for r in $(git branch -a | grep -E "remotes/origin/(stable|master|dev|develop|release-.*|hotfix-*|PR-.*)"); do
    echo "Remote branch: $r"
    rr="$(echo $r | cut -d/ -f 3)";
    {
      git checkout $rr 2>/dev/null && echo $rr >> EXISTING_BRANCHES || git checkout -f -b "$rr" $r
    }
  done
  cat EXISTING_BRANCHES
  '''

    // -------------------------------------------
    // **EDIT:** this has been solved by optionally setting the IGNORE_NORMALISATION_GIT_HEAD_MOVE when necessary (see above)
    // So instead of checking out BRANCH_NAME, we whatever ORIGINAL_CHECKOUT was.
    // -------------------------------------------
    // -------------------------------------------
    // Checkout the actual branch under test.
    // -------------------------------------------
    // If you were to keep the detached head checked out you will see an error
    // similar to:
    //    "GitVersion has a bug, your HEAD has moved after repo normalisation."
    //
    // See: https://github.com/GitTools/GitVersion/issues/1627
    //
    // The version is not so relevant in a PR so we decided to just use the branch
    // under test.
    sh "git checkout $ORIGINAL_CHECKOUT"

    container('gitversion') {
        // 2 lines below are for debug purposes - uncomment if needed
        // sh 'dotnet /app/GitVersion.dll || true'
        // input 'wait'
        sh 'dotnet /app/GitVersion.dll'
        sh 'dotnet /app/GitVersion.dll > version.json'
    }

    // re checkout because gitversion messes around with something causing a 
    // error: failed to unmarshal /home/jenkins/workspace/proj1/.git/config due to failed to 
    // unmarshal /home/jenkins/workspace/proj1/.git/config due to branch config: invalid merge
    sh "git checkout $ORIGINAL_CHECKOUT"

    // Clean up - delete local branches checked out previously, leaving any EXISTING_BRANCHES
    sh '''
    git branch | grep -v HEAD
    for r in $(git branch | grep -v $(git rev-parse --abbrev-ref HEAD)); do
      grep -E "^${r}$" EXISTING_BRANCHES && echo "Not deleting exsting branch '$r'." || git branch -D "$r"
    done
  '''

    // git reset hard to revert any changes
    sh 'git reset --hard'
}

@stale
Copy link

stale bot commented Nov 4, 2019

This issue has been automatically marked as stale because it has not had recent activity. After 30 days from now, it will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Nov 4, 2019
@stale stale bot closed this as completed Dec 4, 2019
@rominator1983
Copy link
Contributor

We are getting this a LOT on Teamcity. First I thought it might be just for history builds (where the tip of branch has moved on the remote) as is described in the initial issue post.
Since we are using the flag 'teamcity.git.fetchAllHeads' I think the bug could be caused by the flag for history builds.

But I have seen several occasions of this exception happening on one agent for the most recent main-commit (tip) and not happening on most other agents for the exact same commit which was always the tip of main.

So the question for me is how to tackle and track down the bug since it is becoming a huge problem in our build pipeline.

We could narrow down what causes the bug in the repo normalisation by checking for the commit-hash after each and every step during the normalisation. This would be for troubleshooting only and should be implemented so that it does not break any other behavior. What are your thoughts on that? Would you accept such a PR?

@arturcic
Copy link
Member

@rominator1983 please create a PR and there we can check and discuss

@rominator1983
Copy link
Contributor

i do now see that it might very well be that the handling in finally could hide another Exception. I will therefore remove the finally block

@rominator1983
Copy link
Contributor

i had to add a nuget.config to be able to restore on my machine. i won't add that change though

rominator1983 added a commit to rominator1983/GitVersion that referenced this issue Oct 25, 2022
rominator1983 added a commit to rominator1983/GitVersion that referenced this issue Oct 25, 2022
@rominator1983
Copy link
Contributor

there you go

@rominator1983
Copy link
Contributor

rominator1983 commented Oct 25, 2022

the build errors look like they are not related to my changes. dont know, how you deal with this stuff

@rominator1983
Copy link
Contributor

just been thinking. it would also be possible after repo normalisation to explicitly checkout the requested commit. of course this behavior would have to be controlled by another environment variable. what do you think?

@asbjornu
Copy link
Member

I think repository normalization is something we would want to remove from GitVersion, or at least move out to a separate part of it that has to be executed explicitly, rather than the implicit execution it is implemented with as of now. I'm therefore not keen on introducing more environment variables or arguments that are related to normalization.

@rominator1983
Copy link
Contributor

I see. I don't really know, what this is for really. It seems to be working in most cases. Unfortunately the failure rate I see is too much for build-environments.
The PR should be ready for approval/merge (build problems with some environments).

arturcic pushed a commit to rominator1983/GitVersion that referenced this issue Mar 19, 2023
arturcic pushed a commit to rominator1983/GitVersion that referenced this issue Mar 19, 2023
arturcic added a commit that referenced this issue Mar 19, 2023
…tionForNormalisationBug

Adds trouble shooting info for #1627
@ericnewton76
Copy link

ericnewton76 commented Jul 12, 2023

just updated from 5.10 to 5.12 and still seeing this problem. btw i absolutely love this versioning program!

running on jenkins, and because my jenkins refuses to properly handle tagged builds, (cant figure out why) i do

stage('Checkout') {
    checkout scm

    //have to pull tags during non-tagged builds
    bat "git fetch --tags"
}

btw i'm aware of the noTags: false option on checkout scm but its extremely cumbersome

and another annoying condition with my repos is my team USED TO cherry pick everything from release -> master so all my release branches never formally merge into master atm. This was because somebody couldnt figure out how to make Jenkinsfile work per branch and hardcoded a bunch of magic release numbers (which gitversion gets rid of)

@JapuDCret
Copy link

JapuDCret commented Jul 30, 2024

I have this issue in GitLab, whenever I build a pipeline of an older commit (or while a commit is being made, before gitversion is executed) - this is because GitLab checks out the Commit itself and leaves it therefore detached (unless the commit is the actual HEAD)

EDIT:
I fixed the issue it seems, I prepended the gitversion command with

  - git switch $CI_COMMIT_REF_NAME
  - git pull
  - git reset --hard $CI_COMMIT_SHA

and also added the argument /nonormalize (see also #3342)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

10 participants