All tf.exe commands return one of these:

public enum ExitCode
{
    Unknown = -1,
    Success = 0,
    PartialSuccess = 1,
    UnrecognizedCommand = 2,
    Failure = 100,
}

You should never see -1.  Code 2 is only for the very specific case where you mistype tf someboguscommand <...>.  The important exit codes are 0, 1, and 100

Unfortunately, the definition of PartialSuccess is kind of ambiguous.  Like the design decisions around tf.exe's path parameters, different commands ended up with slightly different behavior in v1.  For example, if you try to Checkout several files, "partial success" means "at least one edit was successfully pended."  Meanwhile, as we'll see, Checkin treats success as all-or-nothing, reserving the PartialSuccess flag for something else.  I'm not going to catalog all of these differences, especially since they might be harmonized in the future.*  Instead I'm focusing just on tf checkin because:

  • It's not intuitive.  Yet...
  • it's the command whose success or failure is most critical to build scripts & other common automation tasks.
  • I already looked up the answers for another customer today :)

As you probably know, Checkin is an all-or-nothing operation.  Conflicts, policy failures, etc. on any of involved files will halt the process.  This design is part of what allows us to guarantee so-called atomic checkins.  As such, we wanted exit code = 0 to unambiguously indicate that a checkin has occurred, with all that implies: new changeset metadata, a new systemwide version number, and so on.

So what in the world does exit code = 1 mean?  There are two places in the code where it's set:

  1. there were no pending changes in your workspace, and you didn't pass any filespec arguments
  2. all of the pending changes you tried to checkin were silently undone.  This in turn means:
    • they were all edits
    • none of the files had been modified

Situation #1 is pretty straightforward: you used syntax that means "checkin everything", then it turned out there was nothing to do.  Situation #2 arises because the server will not let you checkin unmodified files as edits.  As a courtesy, TFS removes the edit bit and continues.  [This is mildly interesting in the light of the guarantees discussed above.  Put simply, we don't consider this a failure.  We return 0 so long as at least one file is successfully checked in, no matter how many other files might have been reverted.]

As you can see, both of these situations are closer to "meaningless failure" than "partial success".  Was it worth separating them out from exit code = 100 cases?  Hopefully :)  In any case, you should now have all the info you need to write scripts that incorporate tf checkin commands intelligently.

*Disclaimer: this article merely describes behavior you might find helpful in v1; it does not imply a design contract.  Details like this are subject to change in future versions of TFS...though if they did the test team might riot ;-)