Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-60267

Document that Pipeline git step doesn't handle commit hashes

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: Minor Minor
    • git-plugin
    • OS: Linux 64-bit
      Jenkins: 2.190.3
      Git plugin: 4.0.0
    • git plugin 4.1.0

      Despite git step description states that "this step is shorthand for the generic SCM step", it behaves differently when specifying commit hash as a branch to checkout. Consider the following pipeline:

       

      repo = 'https://github.com/jmacloue/mypwgen-pl.git'
      branch = 'ad0f6e4'
      
      pipeline {
          agent any
          stages {
              stage("GitSCM") {
                  steps {
                      checkout([$class: 'GitSCM',
                                userRemoteConfigs: [[url: repo]],
                                branches: [[name: branch]],
                               ])
                  }
              }
              
              stage("shorthand") {
                  steps {
                      git url: repo, branch: branch
                  }
              }
          }
      }
      

      Though the stages should be identical according to docs, the second stage fails:

      ...
       > git fetch --tags --force --progress -- https://github.com/jmacloue/mypwgen-pl.git +refs/heads/*:refs/remotes/origin/* # timeout=10
       > git rev-parse ad0f6e4^{commit} # timeout=10
      Checking out Revision ad0f6e453986b1a068d1d6cab4aef37f254ab86e (detached)
      ...
       > git rev-parse refs/remotes/origin/ad0f6e4^{commit} # timeout=10
       > git rev-parse refs/remotes/origin/origin/ad0f6e4^{commit} # timeout=10
       > git rev-parse origin/ad0f6e4^{commit} # timeout=10
      ...
      ERROR: Couldn't find any revision to build. Verify the repository and branch configuration for this job.
      Finished: FAILURE
      

      However if branch is set to "master" - it works just fine.

       

      ...
       > git rev-parse origin/master^{commit} # timeout=10
      Checking out Revision ad0f6e453986b1a068d1d6cab4aef37f254ab86e (origin/master)
      ...
       > git rev-parse refs/remotes/origin/master^{commit} # timeout=10
       > git rev-parse refs/remotes/origin/origin/master^{commit} # timeout=10
      Checking out Revision ad0f6e453986b1a068d1d6cab4aef37f254ab86e (refs/remotes/origin/master)
      ...
      

      So, it looks like git step follows a completely different path from what the checkout step does. Either git step's description or, preferably, its behaviour needs to be changed.

       

      PS I vaguely recall that at some point the stages worked identical indeed but now it's definitely not so.

       

       

          [JENKINS-60267] Document that Pipeline git step doesn't handle commit hashes

          Mark Waite added a comment -

          I'll update the documentation to further reinforce that the git step does not have all the functionality of the checkout step and that it does not have the same behaviors as the checkout step in all cases.

          I won't modify the behavior of the git step.

          Mark Waite added a comment - I'll update the documentation to further reinforce that the git step does not have all the functionality of the checkout step and that it does not have the same behaviors as the checkout step in all cases. I won't modify the behavior of the git step.

          Jeff MacLoue added a comment -

          Any reason not to fix this the other way around? Besides the effort needed, of course.

           

          The thing is - "detached HEAD" builds by commit hash is just too popular. It's much too often you see tasks like "Our latest commit broke the production, deploy revision ad3ad12 immediately!" (and, of course, there is no tag or branch head pointing to this revision, it's just HEAD^ from master or something like it), and to be able to perform such tasks efficiently you have to stick with the "long" Git checkout syntax in your pipelines.

           

          Regardless of the syntax, checking out by commit hash by putting it in "branches" parameter is confusing enough already, so different behaviour of a shortcut adds yet another quirk to keep in mind. Also checkout([$class: "GitSCM", ...]) looks too similar to how you used to wrap pre-pipeline era plugins in generic build steps, so it's  counter-intuitive that you should use this syntax to get the things done: you don't do step([$class: "ArtifactArchiverStep", ...]) instead of clearer archiveArtifact ..., why do checkout([$class: "GitSCM", ...]) instead of git ... ?

          Jeff MacLoue added a comment - Any reason not to fix this the other way around? Besides the effort needed, of course.   The thing is - "detached HEAD" builds by commit hash is just too popular. It's much too often you see tasks like "Our latest commit broke the production, deploy revision ad3ad12 immediately!" (and, of course, there is no tag or branch head pointing to this revision, it's just HEAD^ from master or something like it), and to be able to perform such tasks efficiently you have to stick with the "long" Git checkout syntax in your pipelines.   Regardless of the syntax, checking out by commit hash by putting it in "branches" parameter is confusing enough already, so different behaviour of a shortcut adds yet another quirk to keep in mind. Also checkout( [$class: "GitSCM", ...] ) looks too similar to how you used to wrap pre-pipeline era plugins in generic build steps, so it's  counter-intuitive that you should use this syntax to get the things done: you don't do step( [$class: "ArtifactArchiverStep", ...] ) instead of clearer archiveArtifact ..., why do checkout( [$class: "GitSCM", ...] ) instead of git ... ?

          Mark Waite added a comment - - edited

          The git shorthand is considered a dead end by jglick. He recommends no further additions be made to it.

          The preferred path forward is to define symbols for the various classes and extensions which are now declared more verbosely when using the checkout step. That will allow simpler syntax in the checkout step and allow the full capabilities of the checkout step, rather than attempting to add all the capabilities of the checkout step to the git step.

          I assume the same behavior is visible when you use a full SHA-1 rather than the abbreviated SHA-1 hash that is used in the examples you listed. Can you confirm that?

          Mark Waite added a comment - - edited The git shorthand is considered a dead end by jglick . He recommends no further additions be made to it. The preferred path forward is to define symbols for the various classes and extensions which are now declared more verbosely when using the checkout step. That will allow simpler syntax in the checkout step and allow the full capabilities of the checkout step, rather than attempting to add all the capabilities of the checkout step to the git step. I assume the same behavior is visible when you use a full SHA-1 rather than the abbreviated SHA-1 hash that is used in the examples you listed. Can you confirm that?

          Jeff MacLoue added a comment -

          Okay, valid point from jglick, but in this case the syntax is not "shorthand" but instead "broken and deprecated". Docs should say so right away - without adding more confusion about "limited functionality" or "different behaviour".

          Though it would definitely be nice to have it as advertised, a short syntax for 90% cases you face. Git is standard, and you rarely need to specify more than repo URL, credentials, and revision you want.

          PS Yes, full SHA commit hashes work the same - checkout() works with them and git() doesn't. As the logs I quoted show, git() uses different way to look revisions up, one that relies on them to be a HEAD of a branch or a tag in the remote repo (note "refs/remotes/origin/XXX" in rev-parse).

          Jeff MacLoue added a comment - Okay, valid point from jglick , but in this case the syntax is not "shorthand" but instead "broken and deprecated". Docs should say so right away - without adding more confusion about "limited functionality" or "different behaviour". Though it would definitely be nice to have it as advertised, a short syntax for 90% cases you face. Git is standard, and you rarely need to specify more than repo URL, credentials, and revision you want. PS Yes, full SHA commit hashes work the same - checkout() works with them and git() doesn't. As the logs I quoted show, git() uses different way to look revisions up, one that relies on them to be a HEAD of a branch or a tag in the remote repo (note "refs/remotes/origin/XXX" in rev-parse).

          Mark Waite added a comment - - edited

          Commited to git plugin 4.0.1 pre-release Nov 27, 2019

          Mark Waite added a comment - - edited Commited to git plugin 4.0.1 pre-release Nov 27, 2019

          Mark Waite added a comment -

          Fixed in git plugin 4.1.0, released Jan 18, 2020.

          Mark Waite added a comment - Fixed in git plugin 4.1.0, released Jan 18, 2020.

            Unassigned Unassigned
            jmacloue Jeff MacLoue
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: