TFS 2008: How to check in without triggering a build when using continuous integration

If part of your build process is to check in a file, such as an updated version file, you wouldn't want that checkin to kick off another build.  You'd be stuck in an infinite loop.

To prevent that problem, simply put the string ***NO_CI*** in the checkin comment.  The code that examines a changeset to determine whether to kick off a new build will skip any changeset with that string in the comment.

[Update 07/02/2008]  If you are making a checkin as part of the build process, you can use $(NoCICheckinComment).  That property is set at run time when the build agent starts msbuild.  I had forgotten about it until a reader pointed this out.

Comments (29)

  1. Ohad Oron says:

    I’m Sorry, but the method you mentioned for not triggering a build seems to be very un practicle. i think a better way to address the issue is to handle a configuration file with desired file types for triggering a build, for example .cs, .csproj, or a diffirent approach such as "listening to a specific branch – say an integration branch, and trigger a build only when something new goes in that branch. what do you think?

  2. buckh says:

    Ohad, I didn’t describe how CI actually works in this post.  It works based on looking at the workspace mappings for build definitions that have CI turned on.  In other words, checkins into version control will not trigger CI builds unless they affect a build definition that has CI turned on.

    In the case where you have CI enabled for a particular part of your source tree via a build definition with that part of the tree mapped and you want to check in without triggering a build, you would put the ***NO_CI*** string in your comment.


  3. Jeff Beehler on Watch out Tech Ed 2007 sessions. Rob Caron on Visual Studio Team System 2008 Team Foundation…

  4. StevenIBSI says:

    The ***NO_CI*** trick worked well thanks.

    I am using the BuildNumberOverrideTarget target with a custom build task to checkout assemblyinfo increment the build number and check it back in.  That seems to work, but my resulting dll files all have a version number that is 1 less then it should be.  

    At the start of the build I see the AssemblyInfo in the working folder has the correct number and that ver gets checked into source control, but then when the Getting Sources occurs I now have the previous version of the file with a build number 1 less then what it shoould be.

    Any ideas why that would be?



  5. buckh says:

    Steven, I had to think about this one for a minute, but I believe I know what’s happened.  When a CI build is triggered, the system records the changeset that triggered it.  That changeset number is passed to the build as the version to use in the get.

    Your process to update the assemblyinfo and check it in occurs prior to the Get.  When the get runs, it’s getting the version specified by the changeset that triggered the build, which is prior to your checkin that changed the assemblyinfo, and thus the files gotten by get do not include your new change to assemblyinfo.  Likewise, the label created by the build includes what was gotten and not your newly updated assemblyinfo.

    What you can do to fix this is to override the AfterGet target and simply get the latest version of the assemblyinfo file.  Then it will be included in the label and the build, giving your dlls the version number you expect.


  6. StevenIBSI says:

    The AfterGet suggestion worked. I added the following to my build definition and now my build number and dll version numbers match.

     <Target Name="AfterGet">    

       <Get Condition=" ‘$(SkipGet)’!=’true’ " Workspace="$(WorkspaceName)" Filespec="$(AssemblyVersionInfoFile)"  Recursive="$(RecursiveGet)" Force="$(ForceGet)" />


    I have another question/comment concerning the CI build triggers. It seemed that when I did a check-in it took about 1 minute before I saw a build in the Queued list.  And if I did multiple check-ins within that 1 minute they were all in the same build.  However if I did another check-in just a few minutes later it queued up another build.

    I would like to be able to specify the number of minutes (say 10) that the CI engine would wait after the first check-in until it queued up that first build.  This way instead of only having 1 minute to get in a few check-ins I would be able to have x minutes to make multiple check-ins for that first build.  So kind of like a count down clock that starts with the first check-in after a period of inactivity.

    Thanks for your help


  7. buckh says:

    Steven, I’m glad to hear that did the trick.

    The one minute delta you are seeing there is because the system checks once per minute to see if there are any new builds to queue based on checkins that have been recorded in the last minute.

    The fact that all of the checkins from that minute were in the same build indicates that you had the option turned on to accumulate checkins (otherwise, you would have gotten one build queued per checkin).

    I saw your other comment on the desire to have a delay before the first build.  When we designed the feature, we looked at it from the perspective that checkins tend to be more spread out through the day, so the first person checking in wouldn’t want to wait some amount of time to find out how the build turned out.  Thus the first checkin kicks off a build immediately, and then the next build is kicked off no sooner than the delay time.  Having said that, I see what you are saying, and we’ll consider adding it in a future release.


  8. StevenIBSI says:

    So with “Accumulate check-ins” being used I as a single developer doing say three check-ins within a few minutes period would expect all three check-ins to be in the same build. But what I would get is a build for the first check-in and then the other two check-ins as part of a second build.  And configured as “Build each check-in” I would get three separate builds, even worse.

    In discussions I have heard of other CI solutions they mentioned the ability to wait for a specified number of minutes of inactivity before a build would be queued.

    Is there any way to configure the one minute delta to be say five minutes? At least then I would have a few minutes to do the multiple check-ins before the build would start.

    — Steven

  9. buckh says:

    No, there’s no way to configure a delay before the build starts in TFS 2008.  We’ll add it to the feature backlog for Rosario, though.


  10. PaulM says:

    Does CI in TFS 2005 look at the workspace mappings for build definitions that have CI turned on. I tried checking something into a non-mapped (and even cloaked) area of Source Control, and it always kicks off a new build.



  11. buckh says:

    Paul, TFS 2005 didn’t support CI in the box.  What CI solution have you chosen to use with TFS 2005?  Chances are whatever it is looks for the TFS CheckinEvent for a team project or something fairly high-level like that.


  12. PaulM says:

    I followed the steps outlined here:

    It sounds like I need to remove the alert I created and set one up as you described in this blog:



  13. buckh says:

    Paul, that’s correct.  Looking at that article, the subscription it shows would register for all checkin events on the entire server.  The checkin event filter blog post you reference is the right way to go about scoping it down to the paths you care about.


  14. Did you know you could disable a Continuous Integration build process from firing as result of a check-in

  15. Altre modifiche per passare da Team Build 2005 a Team Build 2008

  16. randy kibbe says:


       On a related subject is there anyway to setup TFS CI to build the same TFSBuild.proj multiple fixed times a day ? It seems you can only schedule it once a day. Which seems very impractical. The build takes too long for setting it up for checkin triggers.

  17. buckh says:

    Randy, there’s no way to set it to trigger at multiple fixed times per day, but you can set it to accumulate checkins for CI.  That way the build won’t get behind (i.e., you won’t end up with multiple queued builds).


  18. Found this out just this past week. What a great tip. Thanks Colin Bowern by way of Buck Hodges Have

  19. Lars Kemmann says:

    This post is exactly what I needed!  Thank you!

  20. Vermin says:

    Does anyone know if any text can be appended to the ***NO_CI*** string?? I have a lot of ***NO_CI*** comments when looking at project history in TFS 2010 and would like to add some text to the end of the ***NO_CI*** text is possible (eg a build/version number "***NO_CI*** 154")

  21. buckh says:

    Vermin, the account that commits the checkin or an account with ReviseOther permission for the path can alter the comment for a changeset.  You could have a process that updates the changeset comment after a build completes.


  22. Vermin says:

    That's great thanks, I'll be looking into doing that

  23. David says:

    I have TFS 2010 setup at home and this trick works great. At work we also use TFS 2010. For some reason this does not work. What process is evaluating the comment to see if this is in there? Is there something with our build process template that could cause this behaviour?


  24. buckh says:

    David, my guess is that there's a checkin happening that doesn't have that comment and is mapped by the build definition.  Whatever is covered by the workspace mappings for the build definition will be used to determine whether a build should be triggered.


  25. David says:

    Thanks for the reply Buck. You were correct. I had a second check-in in AfterBuild that was checking into a directory that was mapped in the build definition's workspace causing the CI build to kick off.

  26. Joe says:

    we use cloaking and decloaking to prevent the endless loop, however with TFS 2010 build activities there does not seem to be way to decloak the folder via the API to comment the update.  Any ideas on how to decloak a folder during the build in a Work flow activity?

  27. buckh says:

    Joe, would you provide me more details on what you are trying to accomplish?  Why using cloaking for this?


  28. Joe says:

    For lower level projects that other projects depend on we need to check in the build output(Dll and Lib files), but we don't want to start the endless loop so we are cloaking the libraries folder in the current project, but not the others so the update will trigger those builds to use the new libraries, that is why we cannot use the No CI comment, because the other builds will not be triggered.

    Thanks for the quick reply

  29. Jason Prickett says:

    Hi Joe,

    There are a lot of ways to accomplish your goal, but since you already have the cloaking and uncloaking working, I will start there. The easiest thing to do would be to use the Invoke activity to invoke tf.exe with the command line options to change the working folder mappings. If you already have the code to use the OM in a custom task, you could either invoke MSBuild and call the custom task (this may be harder than it sounds) or create a custom activity that calls the same code. Jim Lamb, Patrick Carnahan and I all have blog posts on creating custom activities for TFS 2010. If you have any trouble, feel free to post a comment on one of our blogs – mine is at…/jpricket.



Skip to main content