Details
-
Bug
-
Status: Closed (View Workflow)
-
Major
-
Resolution: Fixed
-
None
-
Ubuntu 10.04 amd64
Description
The Git SCM plugin has suffered from this problem since I started using it. Rather than merge the changes to be built into a branch which tracks the remote I want to push to, it checks out one rev and merges the others on, resulting in a detached HEAD. My build expects to be run on a specific branch, and it fails because the repo isn't in that state.
Other people have encountered the same problem, and there doesn't seem to be any solution other than to fix things in the build steps, which is a big hassle.
Can we please get this issue resolved, or if it's been fixed, clear instructions on how to make it work?
I've attached the SCM portion of my job's config.xml. What I'm trying to do is build changes committed to branches in the origin repo (SG), merge those into SG-gold/master and push them back to SG-gold/master.
Here are the commands where things seem to go wrong:
[SG-experimental] $ git rev-parse gold/master
[SG-experimental] $ git checkout -f ceb23d234b1b21006f049d310501082b77b70ae4
[SG-experimental] $ git merge 172b2d433ee57509f8e886f5d734f226d49166dd
[SG-experimental] $ git tag -a -f -m "Hudson Build #35" hudson-SG-experimental-35
Warning : There are multiple branch changesets here
Rather than "git checkout gold/master", it finds the hash of gold/master and checks out that instead. This is the root of the problem.
In order to fix this, you have to put these in the first build step:
git branch -D temp_merge || true
git branch temp_merge ${BUILD_TAG}
git checkout master
git reset --hard gold/master
git merge temp_merge
This is error-prone and requires duplication of the merge target branch that's already in the Git configuration for the job.
Attachments
Issue Links
- is blocking
-
JENKINS-5856 Unable to Release a Git Project
-
- Closed
-
Activity
As I stated, I have tools which require that the repository be on a branch, which is not the same thing as being detached while pointing to the same commit. I'm referring to git-buildpackage here, which has the notion of a "debian branch" and an "upstream branch." In order to create the diff between the upstream source and the Debian changes, it runs "git diff upstream..debian" (or whatever you tell it the branches are). When you aren't on a branch, this isn't possible. It doesn't make sense to diff "upstream..random sha1", since you would never do that in a normal package development cycle.
Just because the files on disk are the same revisions with HEAD detached does not mean that it's the same. The context is important, and being in an unusual state causes things to break. I'm not the only one this is a problem for, as a reading of the Git plugin wiki clearly shows.
The push is not the issue. The build is the issue. If the build succeeds, the push works fine. What's broken is the state of the repo when the build happens. What's broken is that I say "merge into this branch," not "merge into detached head, then push back to this branch."
Can you give me a concrete list of the advantages of building this way versus merging into the branch I'm telling it to merge into?
I would also point out that your argument is contradictory. Building with a detached head is a good thing, except it's absolutely the same as not? That nonsensical.
Between this and JENKINS-5856, there definitely seems to be a need for the ability to checkout to a branch, rather than just detached HEAD. I'm still not entirely clear on all the git mechanics (and yet I'm the git plugin maintainer - yay for confusion!), but I've made a run at adding an option for checking out to a branch. It's in github at http://github.com/abayer/Hudson-GIT-plugin/tree/JENKINS-6856. If the local branch is specified in the project's advanced configuration, the "git checkout <ref>" commands will instead be "git checkout -b <local branch> <ref>". Which I think fits what you need.
Give it a look and let me know what you think.
Ok, I've merged that to master, and it'll be in the next release (tentatively 1.0, probably coming in the next week or two).
Integrated in plugins_hudson-git-plugin #8
Last round of tweaks for JENKINS-6856 - had to make sure branch actually existed before deleting it, and had to make sure we ignored branches with -> in parseBranches, since that can't be parsed by rev-parse
Andrew Bayer :
Files :
- src/main/java/hudson/plugins/git/GitAPI.java
I might be a bit late, but I will try to answer to two comments from ieure:
1. What I was trying to explain is that this particular line in your bug description is incorrect:
"Rather than "git checkout gold/master", it finds the hash of gold/master and checks out that instead. This is the root of the problem."
You're making the same mistake when you're saying: "Building with a detached head is a good thing, except it's absolutely the same as not? That nonsensical."
I didn't say that being in detached HEAD state is the same as not being in it. I said that both actions "git checkout gold/master" and "git checkout SHA-1" are having the same effect. Generally speaking, checkout to any remote branch (for example like origin/master) is ABSOLUTELY identical to checking out to SHA-1 this branch points to (actually, it is true for any SHA-1 commit ID). BOTH actions will lead to detached HEAD, which means that the HEAD will be pointing to the commit ID directly, it won't be pointing to the branch, i.e. it won't be a symbolic ref anymore.
You can take a look at it like this in any repo:
$ git checkout master
$ vi .git/HEAD
$ git rev-parse master
$ git checkout "SHA-1 from previous command" # (it will printout pretty much the same explanation as i'm trying to make here)
$ vi .git/HEAD #it is now pointing directly to a commit
2. Secondly, why working in Hudson with detached HEAD is good? Because the detached HEAD state will guarantee you that NONE of the actions your performing in this state will be recorded in the LOCAL repo unless you will be explicit about it. For example, in detached HEAD state you can commit, but your commits will be lost as soon as you will checkout to an existing local branch, unless you will create a new local branch after you committed in detached HEAD state.
You're saying that the problem is that your Hudson local repo is in broken state after build. Well, it is not, because detached HEAD is not a broken state! Why you shouldn't care about local Hudson repo? Exactly, because git plugin is working with it using detached HEAD state.
here is the example:
you have your gold/master branch pointing to commit aaa
you have your dev branch pointing to commit bbb
build process checks out to gold/master revision aaa
then it resolves the revision to merge bbb and performs the merge. Your HEAD is pointing to the resulting revision ccc (for example there was a recursive merge used which got recorded as new commit) and gets tagged. Now when you take a look at the help message for the git publisher branches you will see that it says that it will merge back the current HEAD! to the specified remote branch!
I.e. that you will get the merge results in your official repository just fine, unless, for example, there is a conflict during the merge.
The point is that you don't have to care about the state of your local Hudson repository, becasue it is not important - your mainline (gold) is important.
OTOH I understand it might be necessary for you to be in some branch because git-buildpackage is requiring it. We are using the default detached HEAD behavior for integration builds, but we use Release plugin in order to prepare production artifact, which has explicit instructions to checkout to master branch, pull latest changes from mainline and then build the code.
I hope that helps.
I suggest to fix the help message for the property "Local branch to use" from current very confusing one to something like that:
"If given, corresponding local branch will be created to store the results of build activities like merges"
I have some questions about the plugin's behavior regarding detached heads, but I think it might be best to approach this discussion by letting you know what I'm trying to do, and let you suggest the best way to do it.
I'd like Jenkins to build and run unit tests for all branches in my repository. I'd like to do this in the build commands for my job: "if $this_branch == 'release_21' then release_this_build_to_beta_servers" The particular branch to be released changes from time to time.
And so it would be convenient for me to be able to see which branch is currently being built. Does this make sense? How would you suggest I accomplish this?
Two related questions:
1. Why doesn't the plugin pass --track to the git checkout command?
2. Would it make sense for there to be a magic string that could be set for "Checkout/merge to local branch (optional)" that means "use remote branch name"?
This issue was marked as resolved, and the resolution marked as "Fixed"... but AFAICT this issue wasn't really fixed and Jenkins still checks out remote branches and winds up in a headless state. Is this going to stay this way? It causes serious headaches for us.
I second what Michael Floering says.
I don't believe this has been fixed.
The detached head state is causing a bunch of problems for us.
UPDATE: After sleeping on the problem I, made a changes which I think resolved the detached head problem:
In the Git plugin Advanced Options, I added: "Checkout to a specific local branch" and provided a branch name.
The detached state breaks build tools that attempt to find the current branch name by calling git branch. When running a project that has multiple branches, the workaround in the previous comment requires n jobs for n branches instead of 1 job.
I have the same problem. Is there any way to avoid the plugin using detached state? I will suggest this to be reopen.
I have this workaround, this depends on the plugin setting the GIT_BRANCH environment variable with the remote ref (including the leading "origin/") that it checked out. So have an Execute Shell build step before your commands:
#!bash git checkout ${GIT_BRANCH#origin/}
The above will check out the branch properly, before running your command. Also, have the following commands in another Execute Shell build step after your commands to do the necessary cleanup:
#!bash git checkout $GIT_BRANCH git branch -D ${GIT_BRANCH#origin/}
I agree, this doesn't seem to have been fixed, and it would help me if it was. It seems like an easy change too. I wonder if there is a complication that we aren't aware of?
Can't you add the "Additional Behaviour" of "Checkout to a specific branch"? That will give you a named branch.
Changing the plugin from using a detached head to using a branch is non-trivial if the goal is to not break a significant portion of the 70 000+ installations of the git plugin. There are too many use models and too many cases where silently switching to use a branch (instead of a detached head) would cause compatibility problems.
If its difficult then fair enough. I am running git commands in a batch script to get round this issue, which is fine, although I do end up wondering what I am getting out of the plug in in this case.
The checkout to specific branch does work, but has complications when building multiple branches (which is a great feature of the plug in).
Maybe adding another environment variable for the branch name would be useful (eg without the "origin/" bit at the start).
I do think that this shouldn't be marked as "Fixed", when it definitely hasn't been. It's misleading and means people will spend time trying to work out why it isn't working.
I think the bug is fixed. I just ran a series of tests which confirmed that I can checkout to the branch
${GIT_BRANCH}
. It expands that variable and performs a checkout of the correct branch.
Steps I took
- Create a new job
JENKINS-6856-checkout-to-GIT_BRANCH - Use git as the SCM
- Use git://github.com/MarkEWaite/git-client-plugin.git as the repository to checkout
- Add "Additional Behavior" to checkout to a specific branch, with the value
$GIT_BRANCH
- Check the "Poll SCM" check box (no polling schedule needed)
- Save the job
- Click the "Poll Now" link on the left side of the job (assuming you have the "Poll Now" plugin installed
That series of steps resulted in immediately running 19 jobs, one for each branch in that repository. Each of those 19 jobs used a branch named precisely for the branch in the origin repository.
What it does not provide is a way to checkout a named branch which is a substring of
GIT_BRANCH
. I think that is what you need, and what is requested in pull request 347
There is some facility to allow substrings of GIT_BRANCH, but I was unable to make it work in the cases I was testing. The GIT_BRANCH variable is implemented inside the git plugin as a "token macro" which takes two optional arguments, fullName and all. If the fullName parameter is false, then the GIT_BRANCH value is to be returned with everything to the right of the leftmost slash character. Unfortunately, I was unable to see the token macro expanded when used in the context of "Branch to build". If I wrote it as
${GIT_BRANCH,fullName=false}
, then the GIT_BRANCH variable was not expanded.
The token macro facility needs more attention inside the git plugin (as far as I can tell), before I'd be confident saying that it works as intended.
Earlier comments in the bug report allude to other ways to checkout the exact desired branch name, so long as you have a bash compatible interpreter available (most Unix variants).
I used this (combined with the earlier checkout to a specific branch name) as a shell script step to checkout a tracking branch
HEAD=$(git rev-parse --abbrev-ref HEAD) CURRENT_BRANCH=remotes/origin/${HEAD##*origin/} WORKING_BRANCH=${CURRENT_BRANCH##*origin/} git checkout $WORKING_BRANCH || git checkout -b $WORKING_BRANCH -t $CURRENT_BRANCH
Code changed in jenkins
User: Mark Waite
Path:
src/test/java/hudson/plugins/git/TestBranchSpec.java
http://jenkins-ci.org/commit/git-plugin/91a1ffc3a6030e8d74fe463edff13d7f1f08fd41
Log:
Add tests exploring JENKINS-6856 - token macro expansion
BranchSpec does not seem to honor token macros. For example,
$GIT_BRANCH matches as expected
${GIT_BRANCH} matches as expected
${GIT_BRANCH,fullName=False} does not match
${GIT_BRANCH,fullName=True} does not match
I expected either all of them to match as expected (token macro expansion
was being applied), or none of them to match (no variable expansion and
no token macro expansion). As far as I can tell, variable expansion is
being applied, but token macro expansion is not being applied.
This confused me too, my scripts rely on finding the name of the current branch which was not possible. It did work however using $GIT_BRANCH as mentioned above, but I did not find that out before finding this issue. Couldn't that be documented for the "Check out to specific local branch" field ?
zitrax you could also use the "Local Branch" extension that was added to git plugin 2.4.4. Refer to the online help for the local branch extension.
In the Local Branch extension, you set the branch name to "**" or the empty string, and that then causes the plugin to checkout to a branch name derived from the branch that was the origin of the checkout. That allows a branch specifier to select multiple branches, then the branch which is checked out is based on the specific branch selected for that run of the job.
I'm writing a pipeline which clones a git repository and supposed to checkout to a specific branch, then merge master to that branch and run a MSBuild.
In reality, git checks out to the sha of the last commit in the branch instead of the branch name itself which is a detached head and the ${GIT_BRANCH} variable is evaluated to 'null'.
// Started by user itai ganot [Pipeline] node Running on master in C:\Program Files (x86)\Jenkins\workspace\bbb [Pipeline] { [Pipeline] stage [Pipeline] { (Setup) [Pipeline] deleteDir [Pipeline] } [Pipeline] // stage [Pipeline] stage [Pipeline] { (Checkout SCM & Merge master to feature branch) [Pipeline] checkout Cloning the remote Git repository Cloning repository http://pctfs1:8080/tfs/DefaultCollection/PC_International/_git/Ensure-pcs-intl > git.exe init C:\Program Files (x86)\Jenkins\workspace\bbb # timeout=10 Fetching upstream changes from http://TFS_SERVER:8080/tfs/DefaultCollection/PC_International/_git/Ensure-pcs-intl > git.exe --version # timeout=10 using GIT_SSH to set credentials javab SSH file > git.exe fetch --tags --progress http://TFS_SERVER:8080/tfs/DefaultCollection/PC_International/_git/REPO_NAME +refs/heads/*:refs/remotes/origin/* > git.exe config remote.origin.url http://TFS_SERVER:8080/tfs/DefaultCollection/PC_International/_git/REPO_NAME # timeout=10 > git.exe config --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* # timeout=10 > git.exe config remote.origin.url http://TFS_SERVER:8080/tfs/DefaultCollection/PC_International/_git/REPO_NAME # timeout=10 Fetching upstream changes from http://TFS_SERVER:8080/tfs/DefaultCollection/PC_International/_git/REPO_NAME using GIT_SSH to set credentials javab SSH file > git.exe fetch --tags --progress http://TFS_SERVER:8080/tfs/DefaultCollection/PC_International/_git/REPO_NAME +refs/heads/*:refs/remotes/origin/* Seen branch in repository origin/feature/merge_tfs Seen branch in repository origin/master Seen branch in repository origin/origin Seen 3 remote branches > git.exe tag -l # timeout=10 Checking out Revision 97b3493db4f726e11e334e5ba34fa808b63edec5 (origin/feature/merge_tfs) > git.exe config core.sparsecheckout # timeout=10 > git.exe checkout -f 97b3493db4f726e11e334e5ba34fa808b63edec5 First time build. Skipping changelog. [Pipeline] bat [bbb] Running batch script C:\Program Files (x86)\Jenkins\workspace\bbb>cd C:\Program Files (x86)\Jenkins\workspace\bbb C:\Program Files (x86)\Jenkins\workspace\bbb>git branch * (HEAD detached at 97b3493) C:\Program Files (x86)\Jenkins\workspace\bbb>echo "git branch: null" "git branch: null" C:\Program Files (x86)\Jenkins\workspace\bbb>echo "git branch: null" "git branch: null" [Pipeline] } [Pipeline] // stage
How can I make sure that I checkout to the relevant branch_name?
itaiganot please refer to the comment prior to your question.
The "pipeline syntax" link on the left of most pipeline job pages will open a page where you can prototype the code you need to perform a checkout to a specific branch. Use the "checkout" selection from that list (not the "git" selection), then select "Git" and add the "Additional Behaviours" for "Check out to specific local branch". You can then set a specific branch name, or you can use "**" to indicate that it should use the branch name from the repository where the clone was performed.
Thanks, it did solve my first issue.
But now I have another issue which is also related, I'd like to set:
// currentBuild.displayName = "#${BUILD_NUMBER}|${BRANCH_NAME}"
And it cannot be done in pipeline because of the same reason... what can be done to achieve that?
itaiganot please don't use closed bug reports as a forum for questions. You're asking for time from the very few people who read git plugin bug reports, when there are much larger groups (like the Jenkins users mailing list) that can address your questions.
Isn't it enough to do the following to get a proper branch head at some point after the checkout? It seems to work for me.
git checkout -b ${GIT_BRANCH} origin/${GIT_BRANCH}
Yes, the git checkout command you used is a very good choice, especially if you're not using authenticated submodules or authenticated access to large file storage (git LFS).
You're mistaken. Checking out to gold/master is actually ABSOLUTELY the same action as checking out to revision it points to. It is a "remote" branch so checking out to it will lead to detached HEAD no matter what.
Git plugin working with revisions in detached HEAD mode is a good thing, IMHO.
It would be more interesting to see the log when it tries to push back your changes to understand why you're not happy about it.