{"id":4063,"date":"2006-03-20T22:32:00","date_gmt":"2006-03-20T22:32:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/buckh\/2006\/03\/20\/how-to-check-in-changes-on-behalf-of-other-users\/"},"modified":"2006-03-20T22:32:00","modified_gmt":"2006-03-20T22:32:00","slug":"how-to-check-in-changes-on-behalf-of-other-users","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/buckh\/how-to-check-in-changes-on-behalf-of-other-users\/","title":{"rendered":"How to check in changes on behalf of other users"},"content":{"rendered":"<p>Recently someone asked how to check in changes for another user.&nbsp; There are at least two good scenarios where this is needed.&nbsp; One is for check-in systems such as the Gauntlet system we used internally during the development of TFS.&nbsp; Rather than check in directly, developers would shelve their changes and put them in the Gauntlet queue.&nbsp; Gauntlet would unshelve one shelveset&#8217;s worth of changes, build the code with those changes, run a small set of tests, and then check in the changes on behalf of the user who created the shelveset.<\/p>\n<p>Another important scenario is for converting an existing system over to Team Foundation Server.&nbsp; For version control, you would like the history in TFS to reflect who actually made the changes, rather than the account used for the conversion.<\/p>\n<p>We provide the capability to support these scenarios through a permission and parameters to the <font face=\"Courier New\">CheckIn()<\/font> method, which supports the <font face=\"Courier New\">\/author<\/font> option on the checkin command in tf.exe.&nbsp; In order to be able to check in changes on behalf of another user, the user performing the check in must either be an administrator or must have the CheckinOther permission.<\/p>\n<p>The MSDN documentation describes the <a href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/ms252587(VS.80).aspx\">CheckinOther permission<\/a>&nbsp;and how to set it from within VS as well as from the command line.&nbsp; From the command line, you would execute something like the following.&nbsp; This example sets the permission for $\/Project and all directories and files that inherit permission settings from $\/Project.<\/p>\n<blockquote>\n<p><font face=\"Courier New\">tf perm $\/Project \/allow:CheckinOther \/user:domainSomeOne<\/font><\/p>\n<\/blockquote>\n<p>From the command line, you can check in changes for someone else by using the <font face=\"Courier New\">\/author<\/font> option to the the checkin command (<a href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/c327ca1z.aspx\">documentation<\/a>).&nbsp; For example, the following command checks in all changes in your current workspace on behalf&nbsp;of OtherUser (<font face=\"Courier New\">\/author:domainOtherUser<\/font>) without prompting (<font face=\"Courier New\">\/i<\/font>).&nbsp; You will need to specify domain if it is different than the domain of your user name (there&#8217;s no harm in always specifying it).<\/p>\n<blockquote>\n<p><font face=\"Courier New\">tf checkin \/i \/author:domainOtherUser<\/font><\/p>\n<\/blockquote>\n<p>One important thing to note here is that the changes are pending in your workspace and are being checked in from your workspace.&nbsp; You are simply specifying what user name you want to see in the brief history format.&nbsp; Both your user name and OtherUser are recorded in the changeset data, so that you can always determine who checked in the changes.<\/p>\n<p>All of the above discussion also applies to the <font face=\"Courier New\">CheckIn()<\/font> method on the <font face=\"Courier New\">Workspace<\/font> class in the version control API.&nbsp; I have copied the method signature and its documentation below.&nbsp; The overload below is the one that takes all of the parameters.&nbsp; The simplest CheckIn() overload requires only two parameters, an array of <font face=\"Courier New\">PendingChange<\/font> objects and a comment, and it is used in the <a href=\"\/buckh\/archive\/2006\/03\/15\/552288.aspx\">basic version control API example<\/a>.<\/p>\n<div>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/********************************************************************************************<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/\/&nbsp;&lt;summary&gt;<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/\/&nbsp;Check&nbsp;in&nbsp;a&nbsp;set&nbsp;of&nbsp;pending&nbsp;changes.&nbsp;&nbsp;Checkins&nbsp;are&nbsp;atomic&nbsp;&#8211;&nbsp;either&nbsp;they&nbsp;all&nbsp;succeed&nbsp;or<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/\/&nbsp;they&nbsp;all&nbsp;fail.&nbsp;&nbsp;If&nbsp;there&nbsp;are&nbsp;any&nbsp;conflicts that&nbsp;need&nbsp;to&nbsp;be resolved&nbsp;before&nbsp;the&nbsp;check&nbsp;in,&nbsp;the&nbsp;check<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/\/&nbsp;in&nbsp;operation&nbsp;will&nbsp;throw&nbsp;an&nbsp;exception.<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/\/&nbsp;If&nbsp;any&nbsp;part&nbsp;of&nbsp;the&nbsp;operations&nbsp;leading&nbsp;up&nbsp;to&nbsp;the&nbsp;final&nbsp;check&nbsp;in&nbsp;commit&nbsp;fail&nbsp;(uploading<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/\/&nbsp;files,&nbsp;etc)&nbsp;then&nbsp;the&nbsp;operation&nbsp;is&nbsp;aborted&nbsp;and&nbsp;an&nbsp;exception&nbsp;is&nbsp;thrown.&nbsp;&nbsp;If&nbsp;updating&nbsp;client<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/\/&nbsp;or work item state&nbsp;fails&nbsp;after&nbsp;the&nbsp;commit&nbsp;operation,&nbsp;a&nbsp;non-fatal&nbsp;error&nbsp;is&nbsp;reported&nbsp;with the<\/span>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/\/&nbsp;actual checkin having been successfully committed.<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/\/&nbsp;&lt;\/summary&gt;<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/\/&nbsp;&lt;param&nbsp;name=&#8221;changes&#8221;&gt;List&nbsp;of&nbsp;changes&nbsp;to&nbsp;check&nbsp;in.&lt;\/param&gt;<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/\/&nbsp;&lt;param&nbsp;name=&#8221;author&#8221;&gt;if&nbsp;non-null,&nbsp;this&nbsp;identity&nbsp;will&nbsp;be&nbsp;listed&nbsp;in&nbsp;history&nbsp;for&nbsp;the&nbsp;committed<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/\/&nbsp;&nbsp;&nbsp;changeset&nbsp;(note&nbsp;that&nbsp;the&nbsp;user&nbsp;running&nbsp;this&nbsp;operation&nbsp;must&nbsp;have&nbsp;the&nbsp;CheckinOther<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/\/&nbsp;&nbsp;&nbsp;permission)&lt;\/param&gt;<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/\/&nbsp;&lt;param&nbsp;name=&#8221;comment&#8221;&gt;Comment&nbsp;to&nbsp;go&nbsp;along&nbsp;with&nbsp;the&nbsp;checkin.&lt;\/param&gt;<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/\/&nbsp;&lt;param&nbsp;name=&#8221;checkinNote&#8221;&gt;Any&nbsp;applicable&nbsp;checkin&nbsp;notes&nbsp;data.&lt;\/param&gt;<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/\/&nbsp;&lt;param&nbsp;name=&#8221;workItemChanges&#8221;&gt;List&nbsp;of&nbsp;work&nbsp;item&nbsp;changes&nbsp;to&nbsp;occur&nbsp;with&nbsp;this&nbsp;checkin&lt;\/param&gt;<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/\/&nbsp;&lt;param&nbsp;name=&#8221;policyOverride&#8221;&gt;if&nbsp;non-null,&nbsp;policy&nbsp;failures&nbsp;are&nbsp;being&nbsp;overridden&lt;\/param&gt;<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/\/&nbsp;&lt;param&nbsp;name=&#8221;checkinOptions&#8221;&gt;Per-checkin&nbsp;options&nbsp;that&nbsp;affect&nbsp;event&nbsp;generation&nbsp;and<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/\/&nbsp;checkin&nbsp;author&nbsp;validation&lt;\/param&gt;<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/\/&nbsp;&lt;returns&gt;changeset&nbsp;number&nbsp;created&nbsp;by&nbsp;checking&nbsp;in&lt;\/returns&gt;<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>\/\/********************************************************************************************<\/span> <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>public<\/span>&nbsp;<span>int<\/span>&nbsp;CheckIn(PendingChange[]&nbsp;changes,&nbsp;String&nbsp;author,&nbsp;String&nbsp;comment,&nbsp;CheckinNote&nbsp;checkinNote, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WorkItemCheckinInfo[]&nbsp;workItemChanges,&nbsp;PolicyOverrideInfo&nbsp;policyOverride, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CheckinOptions&nbsp;checkinOptions) <\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;[System.FlagsAttribute()] <br>&nbsp;&nbsp;&nbsp;&nbsp;<span>public<\/span>&nbsp;<span>enum<\/span>&nbsp;CheckinOptions <br>&nbsp;&nbsp;&nbsp;&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;None&nbsp;=&nbsp;<span>1<\/span>, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ValidateCheckinOwner&nbsp;=&nbsp;<span>2<\/span>, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SuppressEvent&nbsp;=&nbsp;<span>4<\/span>, <br>&nbsp;&nbsp;&nbsp;&nbsp;}<\/div>\n<p>The <font face=\"Courier New\">author<\/font>, <font face=\"Courier New\">checkinNote<\/font>, <font face=\"Courier New\">workItemChanges<\/font>, and <font face=\"Courier New\">policyOverride<\/font> parameters can all be <font face=\"Courier New\">null<\/font> if you don&#8217;t have values to specify (okay, the <font face=\"Courier New\">comment<\/font> can be <font face=\"Courier New\">null<\/font> too, but you wouldn&#8217;t do that, right?).<\/p>\n<p>The CheckinOptions values allow you to control what happens with the <font face=\"Courier New\">author<\/font> parameter (<font face=\"Courier New\">ValidateCheckinOwner<\/font>) and server-side event generation (<font face=\"Courier New\">SuppressEvent<\/font>).&nbsp; For overloads of <font face=\"Courier New\">CheckIn()<\/font> that don&#8217;t specify the <font face=\"Courier New\">checkinOptions<\/font> parameter explicitly, the value <font face=\"Courier New\">CheckinOptions.ValidateCheckinOwner<\/font> is used.<\/p>\n<p>For a Gauntlet-type scenario, calling the <font face=\"Courier New\">Checkin()<\/font> method with the <font face=\"Courier New\">author<\/font> being the owner of the shelveset is exactly what you need.&nbsp; You can call an overload that doesn&#8217;t explicitly specify the checkin options and use the default value.<\/p>\n<p>The real purpose of the <font face=\"Courier New\">checkinOptions<\/font> parameter is to support version control converters.&nbsp; For that scenario, you may need to check in changes on behalf of users that don&#8217;t exist as Windows users, either because they have been deleted or because the old version control system had its own user security system (e.g., Visual SourceSafe).&nbsp; So, most converters will not want to have the server validate the checkin owner (author).<\/p>\n<p>Also for the conversion scenario, you will likely want to suppress checkin events on the server.&nbsp; The reason is that you are likely creating hundreds or thousands of changesets, and checkin event generation will simply add overhead to a process that you&#8217;d like to have run as quickly as possible.&nbsp; To do this, you will want to specify <font face=\"Courier New\">CheckinOptions.SuppressEvent<\/font> for the <font face=\"Courier New\">checkinOptions<\/font> parameter.<\/p>\n<p>Putting this all together, the call to <font face=\"Courier New\">CheckIn()<\/font> in a version control converter might look like the following.&nbsp; You may also want to specify the old system&#8217;s checkin date and other metadata in the checkin comment.<\/p>\n<blockquote>\n<p><font face=\"Courier New\">PendingChange[] pendingChanges = workspace.GetPendingChanges();<\/p>\n<p>String oldSystemUser = \/* get user name from other VC system *\/;<br><\/font><font face=\"Courier New\"><br>workspace.CheckIn(pendingChanges, oldSystemUser, &#8220;converted changeset&#8221;, null, null, null, CheckinOptions.SuppressEvent);<\/font><\/p>\n<\/blockquote>\n<p>For those of you wondering why <font face=\"Courier New\">CheckinOptions.None<\/font> and other None enum values have the value of 1 rather than zero, it was a side effect of wsdl.exe.&nbsp; In SOAP, the enumeration values are marshalled as names, such as None, rather than integers.&nbsp; As a result, the values of the enumerations in the client may not match the values of the enumerations used by the server, since they are specified in the web service&#8217;s WSDL.<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Recently someone asked how to check in changes for another user.&nbsp; There are at least two good scenarios where this is needed.&nbsp; One is for check-in systems such as the Gauntlet system we used internally during the development of TFS.&nbsp; Rather than check in directly, developers would shelve their changes and put them in the [&hellip;]<\/p>\n","protected":false},"author":94,"featured_media":10268,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[6,8],"class_list":["post-4063","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-source-control","tag-team-foundation"],"acf":[],"blog_post_summary":"<p>Recently someone asked how to check in changes for another user.&nbsp; There are at least two good scenarios where this is needed.&nbsp; One is for check-in systems such as the Gauntlet system we used internally during the development of TFS.&nbsp; Rather than check in directly, developers would shelve their changes and put them in the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/posts\/4063","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/users\/94"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/comments?post=4063"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/posts\/4063\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/media\/10268"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/media?parent=4063"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/categories?post=4063"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/buckh\/wp-json\/wp\/v2\/tags?post=4063"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}