<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>Atlassian Blogs</title><link>http://blogs.atlassian.com</link><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/AtlassianDeveloperBlog" /><description>Software development and collaboration tools</description><language>en-US</language><lastBuildDate>Wed, 22 May 2013 09:22:17 PDT</lastBuildDate><generator>http://wordpress.org/?v=3.5.1</generator><sy:updatePeriod xmlns:sy="http://purl.org/rss/1.0/modules/syndication/">hourly</sy:updatePeriod><sy:updateFrequency xmlns:sy="http://purl.org/rss/1.0/modules/syndication/">1</sy:updateFrequency><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/AtlassianDeveloperBlog" /><feedburner:info uri="atlassiandeveloperblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>AtlassianDeveloperBlog</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><feedburner:browserFriendly>This is an XML content feed. It is intended to be viewed in a newsreader or syndicated to another site, subject to copyright and fair use.</feedburner:browserFriendly><item><title>Maven Git Flow Plugin for Better Releases</title><link>http://feedproxy.google.com/~r/AtlassianDeveloperBlog/~3/iXUf5dwm0xM/</link><category>Uncategorized</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Jonathan Doklovic</dc:creator><pubDate>Tue, 21 May 2013 04:28:09 PDT</pubDate><guid isPermaLink="false">http://blogs.atlassian.com/?p=25405</guid><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h2 id="DraftJGitFlowMavenPluginBlogPost-WhatisJGitFlowandWhyDoINeedaMavenPlugin?">What is JGit Flow and Why Do I Need a Maven Plugin?</h2>
<p>If you missed <a href="http://blogs.atlassian.com/2013/04/git-flow-comes-to-java/">my other blog post</a>, I recently release a Java library named jgit-flow that implements the git-flow branching and merging model introduced by Vincent Driessen in Java.</p>
<p>My hope is that developers will use this library to integrate git-flow workflows inside of their Java apps, and to get the ball rolling, I thought I&#8217;d be the first integrator.</p>
<p>If you read <a href="http://blogs.atlassian.com/2013/04/git-flow-comes-to-java/">my other blog post</a>, you&#8217;ll remember that although git-flow is really useful, trying to make it play nice with the <a href="http://maven.apache.org/maven-release/maven-release-plugin/">maven-release-plugin</a> (MRP) leaves a lot to be desired.</p>
<p>In particular, some of the pitfalls of the maven-release-plugin in the context of git-flow are:</p>
<ul>
<li>MRP writes .backup and release.properties files to your working tree which are easily committed when they shouldn&#8217;t be</li>
<li>MRP does a build in the prepare goal and a build in the perform goal causing tests to run 2 times</li>
<li>MRP and git-flow both create tags leaving you with two tags if you forget to delete one of them</li>
<li>If something goes wrong, MRP usually leaves you in a bad state and rollback doesn&#8217;t work most of the time</li>
</ul>
<p>So I figured the best plan of action was to write a specific plugin to enable git-flow style release workflows, and after a bit of twiddling, I&#8217;m pleased to bring you the JGit Flow Maven Plugin.</p>
<h2>Features</h2>
<p>While the plugin is primarily used to perform releases, it also provides full git-flow functionality including:</p>
<ul>
<li><strong>starting a release</strong> &#8211; creates a release branch and updates pom(s) with release versions</li>
<li><strong>finishing a release</strong> &#8211; runs a maven build (deploy or install), merges the release branch, updates pom(s) with development versions</li>
<li><strong>starting a hotfix</strong> &#8211; creates a hotfix branch and updates pom(s) with hotfix versions</li>
<li><strong>finishing a hotfix</strong> &#8211; runs a maven build (deploy or install), merges the hotfix branch, updates pom(s) with previous versions</li>
<li><strong>starting a feature</strong> &#8211; creates a feature branch</li>
<li><strong>finishing a feature</strong> &#8211; merges the feature branch</li>
</ul>
<h3>Differences with the Maven Release Plugin</h3>
<p>Although the maven-jgitflow-plugin is based on the maven-release-plugin, it does things a bit differently to provide a cleaner workflow&#8230;</p>
<ul>
<li>doesn&#8217;t create any .backup or release.properties files (or any other files in your working tree)</li>
<li>makes all changes on branches. This means to &#8220;roll-back&#8221; you can simply delete the branch</li>
<li>automatically copies any profiles (-P) and user-properties (-D) passed on the command line to the forked maven process when building</li>
<li>doesn&#8217;t run site-deploy</li>
<li>provides the ability to completely turn off maven deployment</li>
<li>provides the ability to completely turn off remote pushes/tagging</li>
<li>Only builds your project once in the finish goal. e.g. if you do release-start and release-finish together, your tests only run once</li>
<li>Never clones your project to a temp folder</li>
<li>auto tracks origin based on maven scm values if origin tracking is not already setup (I&#8217;m looking at you Bamboo!)</li>
<li>master branch is always kept at the latest release version (not a SNAPSHOT)</li>
</ul>
<p>I&#8217;m hoping this plugin will help ease the pain of releasing maven projects with git-flow and help reduce the number of groans when someone says &#8220;can you do a maven release of&#8230;&#8221;</p>
<p>To get started, check out the <a href="https://bitbucket.org/atlassian/maven-jgitflow-plugin/wiki/Home">plugin&#8217;s wiki</a>. And when things don&#8217;t work, let me know in the <a href="https://bitbucket.org/atlassian/maven-jgitflow-plugin/issues">plugin&#8217;s issue tracker.</a></p>
<p>If you&#8217;re interested in contributing, please fork the <a href="https://bitbucket.org/atlassian/maven-jgitflow-plugin">Maven JGitFlow Plugin on Bitbucket</a>. When your super cool new feature is ready, just issue a pull request to the develop branch of the main project.</p>
<p>Enjoy!</p>
<h3>resources</h3>
<p>Wiki: <a href="https://bitbucket.org/atlassian/maven-jgitflow-plugin/wiki/Home">https://bitbucket.org/atlassian/maven-jgitflow-plugin/wiki/Home</a><br />
Issue Tracker: <a href="https://bitbucket.org/atlassian/maven-jgitflow-plugin/issues">https://bitbucket.org/atlassian/maven-jgitflow-plugin/issues</a><br />
Google Group: <a href="https://groups.google.com/forum/#!forum/maven-jgitflow-users">https://groups.google.com/forum/#!forum/maven-jgitflow-users</a><br />
Source Code: <a href="https://bitbucket.org/atlassian/maven-jgitflow-plugin">https://bitbucket.org/atlassian/maven-jgitflow-plugin</a></p>
 <img src="http://blogs.atlassian.com/?feed-stats-post-id=25405" width="1" height="1" style="display: none;" /><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?a=iXUf5dwm0xM:OYTGWfQ0Hzk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?a=iXUf5dwm0xM:OYTGWfQ0Hzk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?i=iXUf5dwm0xM:OYTGWfQ0Hzk:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/AtlassianDeveloperBlog/~4/iXUf5dwm0xM" height="1" width="1"/>]]></content:encoded><description>What is JGit Flow and Why Do I Need a Maven Plugin? If you missed my other blog post, I recently release a Java library named jgit-flow that implements the git-flow branching and merging model introduced by Vincent Driessen in Java. My hope is that developers will use this library to integrate git-flow workflows inside of their Java apps, and to get the ball rolling, I thought I&amp;#8217;d be the first integrator. If you read my other blog post, you&amp;#8217;ll remember that although git-flow is really useful, trying to make it play nice with the maven-release-plugin (MRP) leaves a lot to be desired. In particular, some of the pitfalls of the maven-release-plugin in the context of git-flow are: MRP writes .backup and release.properties files to your working tree which are easily committed when they shouldn&amp;#8217;t be MRP does a build in the prepare goal and a build in the perform goal causing tests to run 2 times MRP and git-flow both create tags leaving you with two tags if you forget to delete one of them If something goes wrong, MRP usually leaves you in a bad state and rollback doesn&amp;#8217;t work most of the time So I figured the best plan of action was to write a specific plugin to enable git-flow style release workflows, and after a bit of twiddling, I&amp;#8217;m pleased to bring you the JGit Flow Maven Plugin. Features While the plugin is primarily used to perform releases, it also provides full git-flow functionality including: starting a release &amp;#8211; creates a release branch and updates pom(s) with release versions finishing a release &amp;#8211; runs a maven build (deploy or install), merges the release branch, updates pom(s) with development versions starting a hotfix &amp;#8211; creates a hotfix branch and updates pom(s) with hotfix versions finishing a hotfix &amp;#8211; runs a maven build (deploy or install), merges the hotfix branch, updates pom(s) with previous versions starting a feature &amp;#8211; creates a feature branch finishing a feature &amp;#8211; merges the feature branch Differences with the Maven Release Plugin Although the maven-jgitflow-plugin is based on the maven-release-plugin, it does things a bit differently to provide a cleaner workflow&amp;#8230; doesn&amp;#8217;t create any .backup or release.properties files (or any other files in your working tree) makes all changes on branches. This means to &amp;#8220;roll-back&amp;#8221; you can simply delete the branch automatically copies any profiles (-P) and user-properties (-D) passed on the command line to the forked maven process when building doesn&amp;#8217;t run site-deploy provides the ability to completely turn off maven deployment provides the ability to completely turn off remote pushes/tagging Only builds your project once in the finish goal. e.g. if you do release-start and release-finish together, your tests only run once Never clones your project to a temp folder auto tracks origin based on maven scm values if origin tracking is not already setup (I&amp;#8217;m looking at you Bamboo!) master branch is always kept at the latest release version (not a SNAPSHOT) I&amp;#8217;m hoping this plugin will help ease the [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.atlassian.com/2013/05/maven-git-flow-plugin-for-better-releases/feed/</wfw:commentRss><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">0</slash:comments><feedburner:origLink>http://blogs.atlassian.com/2013/05/maven-git-flow-plugin-for-better-releases/</feedburner:origLink></item><item><title>A Solution to SSO Authentication and Identity Management: Lessons Learned</title><link>http://feedproxy.google.com/~r/AtlassianDeveloperBlog/~3/NK0hLUxp6i0/</link><category>Developer</category><category>Atlassian ID</category><category>Crowd</category><category>HA Crowd</category><category>identity management</category><category>integration</category><category>SSO</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Brendan Haire</dc:creator><pubDate>Thu, 16 May 2013 18:52:00 PDT</pubDate><guid isPermaLink="false">http://blogs.atlassian.com/?p=25342</guid><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Here at Atlassian, we recently went through an exercise to consolidate the <a href="http://blogs.atlassian.com/2013/01/atlassian-id-coming-to-a-service-near-you/" rel="nofollow">authentication and identity management</a> of our key support systems.  As we have grown, we have seen a number of account silos materialize across our system landscape. This required customers to have separate logins for support, forums, account management, etc., resulting in a frustrating experience for our customers, and a tough situation for Atlassian staff.</p>
<p>The problem of multiple account silos is common across the technology domain, yet is a surprisingly difficult one to resolve. It starts with a simple requirement: &#8220;We want to use the same login for multiple systems.&#8221;</p>
<p>But what sounds easy on the surface can quickly evolve into a complex blend of concerns across technology, data migration and separate functional teams.</p>
<p>So I am pleased to be able to outline the process and technology solution we used as part of this project, in the hopes that it will mitigate some of the headaches in delivering similar initiatives.</p>
<p>Welcome to a Behind the Scenes look at the creation of <a href="https://id.atlassian.com/about" rel="nofollow">Atlassian ID</a>.</p>
<h2><strong>Challenges and Learnings</strong></h2>
<p>Before diving into the solution and design process, I will comment on some of the key challenges (both technical and non-) and learnings. Our biggest challenges were:</p>
<ul>
<li><strong>Multiple teams.</strong> By its nature the project required engagement across a number of functional groups within Atlassian. This was made somewhat easier than in most organisations due to Atlassian&#8217;s fast moving pace and can-do-it culture, but it was also a double-edged sword. Once we had agreement with the teams, it was necessary to keep up with them as they powered ahead providing new services and capabilities on their system.</li>
<li><strong>Availability</strong>. Having one user base for all your applications can be effectively like putting all your eggs in one basket. You don&#8217;t want that basket to break. Availability was a significant challenge to tackle throughout the solution.</li>
<li><strong>Customer migration</strong>. This was a big one. We had seven systems and a large user base that had been diverging for over 10 years. You name the scenario&#8230; we had it.</li>
</ul>
<p>What did we learn from the process? What stood out was:</p>
<ul>
<li><strong>Data migration is hard</strong>. I have learnt this a couple of times previously in my experience but I was once again reminded. Data migration is hard and always takes more effort than you think. Plan it out&#8230;then double.</li>
<li><strong>SSO is important</strong>. From a technical perspective there is an urge to dismiss this as unimportant. The reality is that SSO is hard. It raises a number of security and distributed &#8216;state&#8217; concerns that need to be dealt with. The alternate argument is that all browsers remember usernames and passwords, meaning only one additional click for users. Surely a single username and password rather than SSO is &#8216;good enough?&#8217; More often than not the answer is &#8216;no.&#8217; By giving away SSO you are sacrificing the ability to really provide a seamless customer experience. In addition, you are losing additional technical capabilities that can be extremely useful. The primary one I would cite is the ability to produce finer grained application or services that can act together to form a larger site (micro-sites/services). The ability to divide your applications into a number of smaller modules has significant benefits for maintenance and development speed.</li>
<li><strong>Authentication is complex</strong>. It is quite amazing how complicated a simple concept such as authentication can become, this domain is littered with many different (and often competing) standards and options for implementation. We dealt with a handful of these methods including your standard web based login pages, OpenID, BASIC-AUTH and some other custom authentication mechanisms including of course the Seraph connector (used by Confluence and JIRA).  There are many others and it is an area to tread with caution.</li>
<li><strong>Design patterns are good</strong>. Implementing without a reference architecture is equivalent to exploring uncharted territory, you never know what is going to happen. Having a good design pattern is like having a map with all the pit-falls and dangerous areas to avoid highlighted. If possible always find a relevant design pattern.</li>
</ul>
<h2>Our Solution</h2>
<p>We had seven systems that were immediately in scope for the project, each owned by a different business unit here at Atlassian. So the first step was to understand the immediate and potential future requirements of each of these systems and units. They boiled down to the following key capabilities:</p>
<ul>
<li><strong>Single sign-on </strong><strong>(SSO)</strong>. The ability to sign-on once and access multiple applications without the need to re-authenticate.</li>
<li><strong>User aliasing</strong>. The ability to &#8216;harmonize&#8217; non-uniform local user identifiers by the means of aliasing or mapping, i.e., username <em>brendan</em> on system A is the same user as <em>bhaire</em> on system B. This was an important capability in relation to legacy users and migration as it meant we could onboard systems to the solution without imposing the need to rename user accounts on the target system.</li>
<li><strong>Central identity management</strong>. The ability to capture, store and manage user identity information centrally.</li>
<li><strong>Provisioning</strong>. The ability to push user identity events across multiple applications e.g. New User, Updated Profile.</li>
<li><strong>Federated authentication</strong> - The ability to provide authentication services to a 3rd party system external to Atlassian, e.g., OpenID, SAML based auth styles.</li>
</ul>
<p>We used <a href="http://www.atlassian.com/software/crowd" rel="nofollow">Crowd</a> to form the backbone of the solution, and extended it using the Interceptor or Gateway architecture pattern. We also settled on <a href="http://www.simplecloud.info/" rel="nofollow">SCIM</a> as a standard for the identity management space. The final solution is one that can be used to provide the access and identity management services both to JIRA and Confluence applications as well as commercial off the shelf (COTS), open source and home grown applications.</p>
<div>
<p>The overal solution covers identity and access management (IAM) but is best split for discusssion across identity management (IDM &#8211; left of diagram) and access management (AM &#8211; right of diagram).</p>
<p><img class="alignnone size-large wp-image-25343" alt="Atlassian ID - Architecture" src="http://atlassian.wpengine.netdna-cdn.com/wp-content/uploads/Atlassian-ID-Architecture-600x510.png" width="600" height="510" /></p>
<h3 id="AtlassianID-BehindtheScenes-AccessManagement(AM)">Access Management (AM)</h3>
<p>This section of the architecture is concerned with providing authentication and access services and capabilities. It follows an architectural design pattern that is often referred to as an <em>interceptor</em> or<em> gateway pattern</em>. As a means to understanding how this functions the two key information or message flows for this solution and component breakdown are detailed below.</p>
<p>Authentication flow:</p>
<ol>
<li><em>User</em> (1) requests a particular resource from a <em>protected application</em> (3).</li>
<li>An <em>Interceptor</em> (2) intercepts this request and authenticates the user (if they are logged in) via their token against <em>Crowd</em> (4) and forwards the request to the p<em>rotected application</em> (3).</li>
<li>The <em>protected application</em> (3) trusts the forwarded request and connection from the <em>interceptor</em> (2) and logs the user into the application under the supplied credentials.</li>
</ol>
<p>Login flow:</p>
<ol>
<li>The <em>user</em> (1) is directed (or re-directed potentially from the <em>protected application</em> (3)) to the <em>login</em> (4).</li>
<li>The <em>user</em> (1) supplies their authentication credentials to the <em>login</em> (4) component.</li>
<li>The l<em>ogin</em> (4) component validated these credentials against C<em>rowd - Access</em> (5).</li>
<li><em>Crowd - access</em> (5) creates a session and returns a unique token to the <em>login</em> (4) component.</li>
<li>The<em> login</em> (4) component returns the token to the u<em>ser</em> (1).</li>
</ol>
<p><strong>(1) User</strong></p>
<p>Most traditionally a person at a web browser but can also be another system operating over HTTP/S.</p>
<p><strong>(2) Interceptor</strong></p>
<p>The interceptor&#8217;s role is to perform all required authentication and to remove these concerns from the <em>protected application</em> (3) i.e., it is a delegated auth provider. It intercepts all requests that are made to the p<em>rotected application</em> (3) and then forwards these requests through with appropriate authentication details.</p>
<p>It is implemented as an Apache Mod and interfaces with the Crowd&#8217;s API to validate tokens and exchange identity information such as aliasing of user accounts. As well as cookie based authentication it provides BASIC-AUTH authentication and elevated auth capabilities (a &#8216;sudo&#8217; equivalent for the web). After authenticating a user it passes the users credentials through to the <em>protected application</em> (3) by encoding the details in the HTTP header.</p>
<p>This component is deployed as a load balanced cluster for availability.</p>
<p><strong>(3) Protected Application</strong></p>
<p>This is the application that is being protected. In most cases this is a web application but can also take the form of a REST service end-point or other services operating over HTTP/S.</p>
<p>The protected application is required to extract the encoded user credential information from the forwarded HTTP request and to log the user into the application.  It is also required to listen to and process identity events (such as profile updates etc.) from the <em>provisioning queue</em> (11) and process these accordingly.</p>
<p><strong>(4) Login</strong></p>
<p>This is a web application that provides authentication services to the <em>user</em> (1) the most notable one being the ability to login to the system. It removes the need for the <em>protected application </em>(3) to handle user authentication credentials i.e. password, therefore minimizing the impact of any security vulnerability or compromise in the <em>protected application </em>(3).</p>
<p>This component is deployed as a load balanced cluster for availability.</p>
<p><strong>(5) Crowd &#8211; Access</strong></p>
<p>This is a <a href="http://www.atlassian.com/software/crowd">Crowd</a> installation that points to a local read-only copy of the LDAP user directory. It provides the underlying access management and directory management services that drive the solution. Most notable for this section of the architecture is the creation and management of the access tokens.</p>
<p>This component is deployed as a load balanced cluster for availability.</p>
<h3 id="AtlassianID-BehindtheScenes-IdentityManagement(IDM)">Identity Management (IDM)</h3>
<p>This section of the architecture is concerned with providing Identity management services and capabilities e.g. profile updates. It is largely a set of CRUD based services with a provisioning queue to provide a push based communication capability to keep downstream systems in sync.</p>
<p>The component breakdown of this section is detailed below.</p>
<p><strong>(6) Identity Management</strong></p>
<p>This is a web application that provides the user interface to create and maintain the users personal identity information as well as account migration and merging services for legacy users.  It interfaces with the i<em>dentity services</em> (7) component to enact these services.</p>
<p><strong>(7) Identity Services</strong></p>
<p>This is a REST based service layer that implements identity management services for the user facing i<em>dentity management</em> (6) component. It adheres to the <a href="http://www.simplecloud.info/" rel="nofollow">SCIM</a> standard for message formats.</p>
<p><strong>(8) Crowd &#8211; Provisioning</strong></p>
<p>This is a Crowd installation that points to <em>LDAP source</em> (10) the writable LDAP user directory which acts as the source of truth for user credentials.  In this section of the architecture Crowd also provides aliasing capabilities that enables the migration and merging of existing accounts without the need to change downstream account setup i.e. it is not invasive.</p>
<p><strong>(9) Crowd Database</strong></p>
<p>The single Crowd database that both <em>Crowd &#8211; access</em> (5) and <em>Crowd &#8211; provisioning</em> (8) components use. This is the persistent data source for identity information including aliasing and central configuration elements.</p>
<p><strong>(10) LDAP Source</strong></p>
<p>Central source for managing authentication details of the user base.</p>
<p><strong>(11) Provisioning Queue</strong></p>
<p>Provides push mechanism capability for identity updates. Messages are written to this queue by the i<em>dentity services</em> (7) component.</p>
<h2>Final Stats</h2>
<p>The rollout was huge success! We were able to resolve a longstanding problem in our system landscape. Tens of thousands of people affected by the change, yet we only had a handful of  complaints and issues, many from unrelated issues such as not receiving authentication emails (due to over-aggressive spam filter on their companies&#8217; server-side). The migration stats at the time of writing were 20,494 accounts migrated with a 99.3% first-time success rate. For those with complex data scenarios that were not immediately successful we have worked hard to resolve their problems as quickly as possible through our support channels.</p>
</div>
 <img src="http://blogs.atlassian.com/?feed-stats-post-id=25342" width="1" height="1" style="display: none;" /><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?a=NK0hLUxp6i0:6x9eiKqP64Q:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?a=NK0hLUxp6i0:6x9eiKqP64Q:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?i=NK0hLUxp6i0:6x9eiKqP64Q:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/AtlassianDeveloperBlog/~4/NK0hLUxp6i0" height="1" width="1"/>]]></content:encoded><description>Here at Atlassian, we recently went through an exercise to consolidate the authentication and identity management of our key support systems.  As we have grown, we have seen a number of account silos materialize across our system landscape. This required customers to have separate logins for support, forums, account management, etc., resulting in a frustrating experience for our customers, and a tough situation for Atlassian staff. The problem of multiple account silos is common across the technology domain, yet is a surprisingly difficult one to resolve. It starts with a simple requirement: &amp;#8220;We want to use the same login for multiple systems.&amp;#8221; But what sounds easy on the surface can quickly evolve into a complex blend of concerns across technology, data migration and separate functional teams. So I am pleased to be able to outline the process and technology solution we used as part of this project, in the hopes that it will mitigate some of the headaches in delivering similar initiatives. Welcome to a Behind the Scenes look at the creation of Atlassian ID. Challenges and Learnings Before diving into the solution and design process, I will comment on some of the key challenges (both technical and non-) and learnings. Our biggest challenges were: Multiple teams. By its nature the project required engagement across a number of functional groups within Atlassian. This was made somewhat easier than in most organisations due to Atlassian&amp;#8217;s fast moving pace and can-do-it culture, but it was also a double-edged sword. Once we had agreement with the teams, it was necessary to keep up with them as they powered ahead providing new services and capabilities on their system. Availability. Having one user base for all your applications can be effectively like putting all your eggs in one basket. You don&amp;#8217;t want that basket to break. Availability was a significant challenge to tackle throughout the solution. Customer migration. This was a big one. We had seven systems and a large user base that had been diverging for over 10 years. You name the scenario&amp;#8230; we had it. What did we learn from the process? What stood out was: Data migration is hard. I have learnt this a couple of times previously in my experience but I was once again reminded. Data migration is hard and always takes more effort than you think. Plan it out&amp;#8230;then double. SSO is important. From a technical perspective there is an urge to dismiss this as unimportant. The reality is that SSO is hard. It raises a number of security and distributed &amp;#8216;state&amp;#8217; concerns that need to be dealt with. The alternate argument is that all browsers remember usernames and passwords, meaning only one additional click for users. Surely a single username and password rather than SSO is &amp;#8216;good enough?&amp;#8217; More often than not the answer is &amp;#8216;no.&amp;#8217; By giving away SSO you are sacrificing the ability to really provide a seamless customer experience. In addition, you are losing additional technical capabilities that can be extremely useful. The primary one I would cite is the ability to produce finer grained application or services that [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.atlassian.com/2013/05/a-solution-to-sso-authentication-and-identity-management-lessons-learned/feed/</wfw:commentRss><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">3</slash:comments><feedburner:origLink>http://blogs.atlassian.com/2013/05/a-solution-to-sso-authentication-and-identity-management-lessons-learned/</feedburner:origLink></item><item><title>Alternatives To Git Submodule: Git Subtree</title><link>http://feedproxy.google.com/~r/AtlassianDeveloperBlog/~3/skMdUWJXtZc/</link><category>Developer</category><category>dvcs</category><category>git</category><category>submodules</category><category>subtree</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Nicola Paolucci</dc:creator><pubDate>Thu, 16 May 2013 05:25:57 PDT</pubDate><guid isPermaLink="false">http://blogs.atlassian.com/?p=25292</guid><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>The Internet is full of articles on why you <a href="http://codingkilledthecat.wordpress.com/2012/04/28/why-your-company-shouldnt-use-git-submodules/">should</a> <a href="http://ayende.com/blog/4746/the-problem-with-git-submodules">not</a> <a href="http://somethingsinistral.net/blog/git-submodules-are-probably-not-the-answer/">use</a> Git submodules. I mostly agree, although I am not so harsh in my evaluation. As I explained in a <a href="http://blogs.atlassian.com/2013/03/git-submodules-workflows-tips/">previous post</a>, <span class="text codecolorer">submodules</span> are useful for a few use cases but have several drawbacks.</p>
<p>Are there alternatives? The answer is: yes! There are (at least) two tools that can help track the history of software dependencies in your project while allowing you to keep using git:</p>
<ul>
<li><a href="https://github.com/git/git/blob/master/contrib/subtree/git-subtree.txt">git subtree</a></li>
<li><a href="https://code.google.com/p/git-repo/">google repo</a></li>
</ul>
<p>In this post I will be looking at <span class="text codecolorer">git subtree</span> and show why it is an improvement &#8211; albeit not perfect &#8211; over <span class="text codecolorer">git submodule</span>.</p>
<p>As a working example I run to my usual use case. How do I easily store and keep up to date the vim plugins used in <a href="https://bitbucket.org/durdn/cfg">my dotfiles</a>?</p>
<h2>Why use subtree instead of submodule?</h2>
<p>There are several reasons why you might find <span class="text codecolorer">subtree</span> better to use:</p>
<ul>
<li>Management of a simple workflow is easy.</li>
<li>Older version of <span class="text codecolorer">git</span> are supported (even before <span class="text codecolorer">v1.5.2</span>).</li>
<li>The sub-project&#8217;s code is available right after the <span class="text codecolorer">clone</span> of the super project is done.</li>
<li><span class="text codecolorer">subtree</span> does not require users of your repository to learn anything new, they can ignore the fact that you are using <span class="text codecolorer">subtree</span> to manage dependencies.</li>
<li><span class="text codecolorer">subtree</span> does not add new metadata files like <span class="text codecolorer">submodules</span> doe (i.e. <span class="text codecolorer">.gitmodule</span>).</li>
<li>Contents of the module can be modified without having a separate repository copy of the dependency somewhere else.</li>
</ul>
<p>In my opinion the drawbacks are acceptable:</p>
<ul>
<li>You must learn about a new merge strategy (i.e. <span class="text codecolorer">subtree</span>).</li>
<li>Contributing code back <span class="text codecolorer">upstream</span> for the sub-projects is slightly more complicated.</li>
<li>The responsibility of not mixing super and sub-project code in commits lies with you.</li>
</ul>
<h2>How to use git subtree?</h2>
<p><span class="text codecolorer">git subtree</span> is available in stock version of <span class="text codecolorer">git</span> available since May 2012 – <span class="text codecolorer">1.7.11</span>+. The version installed by <a href="http://mxcl.github.io/homebrew/">homebrew</a> on OSX already has subtree properly wired but on some platforms you might need to follow the <a href="https://github.com/git/git/blob/master/contrib/subtree/INSTALL">installation instructions</a>.</p>
<p>Let me show you the canonical example of tracking a vim plug-in using <span class="text codecolorer">git subtree</span>.</p>
<h3>The quick and dirty way without remote tracking</h3>
<p>If you just want a couple of one liners to cut and paste just read this paragraph.</p>
<p>First add the <span class="text codecolorer">subtree</span> at a specified <span class="text codecolorer">prefix</span> folder:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">git subtree add --prefix .vim/bundle/tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git master --squash</div></td></tr></tbody></table></div>

</pre>
<p><em>(The common practice is to not store the entire history of the sub-project in your main repository, but If you want to preserve it just omit the <span class="text codecolorer">&#8211;squash</span> flag.)</em></p>
<p>The above command produces this output:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">git fetch https://bitbucket.org/vim-plugins-mirror/vim-surround.git master<br />
warning: no common commits<br />
remote: Counting objects: 338, done.<br />
remote: Compressing objects: 100% (145/145), done.<br />
remote: Total 338 (delta 101), reused 323 (delta 89)<br />
Receiving objects: 100% (338/338), 71.46 KiB, done.<br />
Resolving deltas: 100% (101/101), done.<br />
From https://bitbucket.org/vim-plugins-mirror/vim-surround.git<br />
* branch &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;master &nbsp; &nbsp; -} FETCH_HEAD<br />
Added dir '.vim/bundle/tpope-vim-surround'</div></td></tr></tbody></table></div>

</pre>
<p>As you can see this records a <span class="text codecolorer">merge commit</span> by squashing the whole history of the <span class="text codecolorer">vim-surround</span> repository into a single one:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">1bda0bd [3 minutes ago] (HEAD, stree) Merge commit 'ca1f4da9f0b93346bba9a430c889a95f75dc0a83' as '.vim/bundle/tpope-vim-surround' [Nicola Paolucci]<br />
ca1f4da [3 minutes ago] Squashed '.vim/bundle/tpope-vim-surround/' content from commit 02199ea [Nicola Paolucci]</div></td></tr></tbody></table></div>

</pre>
<p>If after a while you want to update the code of the plugin from the <span class="text codecolorer">upstream</span> repository you can just <span class="text codecolorer">subtree pull</span>:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">git subtree pull --prefix .vim/bundle/tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git master --squash</div></td></tr></tbody></table></div>

</pre>
<p>This is very quick and painless but the commands are slightly lengthy and hard to remember. We can make the commands shorter by adding the sub-project as a remote.</p>
<h3>Adding the sub-project as a remote</h3>
<p>Adding the subtree as a remote allows us to refer to it in shorter form:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">git remote add -f tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git</div></td></tr></tbody></table></div>

</pre>
<p>Now we can add the subtree (as before), but now we can refer to the remote in short form:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">git subtree add --prefix .vim/bundle/tpope-vim-surround tpope-vim-surround master --squash</div></td></tr></tbody></table></div>

</pre>
<p>The command to update the sub-project at a later date becomes:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">git fetch tpope-vim-surround master<br />
git subtree pull --prefix .vim/bundle/tpope-vim-surround tpope-vim-surround master --squash</div></td></tr></tbody></table></div>

</pre>
<h3>Contributing back to upstream</h3>
<p>We can freely commit our fixes to the sub-project in our local working directory now.</p>
<p>When it&#8217;s time to contribute back to the <span class="text codecolorer">upstream</span> project we need to fork the project and add it as another remote:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">git remote add durdn-vim-surround ssh://git@bitbucket.org/durdn/vim-surround.git</div></td></tr></tbody></table></div>

</pre>
<p>Now we can use the <span class="text codecolorer">subtree push</span> command like the following:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">git subtree push --prefix=.vim/bundle/tpope-vim-surround/ durdn-vim-surround master<br />
<br />
git push using: &nbsp;durdn-vim-surround master<br />
Counting objects: 5, done.<br />
Delta compression using up to 4 threads.<br />
Compressing objects: 100% (3/3), done.<br />
Writing objects: 100% (3/3), 308 bytes, done.<br />
Total 3 (delta 2), reused 0 (delta 0)<br />
To ssh://git@bitbucket.org/durdn/vim-surround.git<br />
&nbsp; 02199ea..dcacd4b &nbsp;dcacd4b21fe51c9b5824370b3b224c440b3470cb -} master</div></td></tr></tbody></table></div>

</pre>
<p>After this we&#8217;re ready and we can open a <span class="text codecolorer">pull-request</span> to the maintainer of the package.</p>
<h3>Without using the subtree command</h3>
<p><span class="text codecolorer">git subtree</span> is different from the <a href="https://www.kernel.org/pub/software/scm/git/docs/howto/using-merge-subtree.html">subtree merge strategy</a>. You can still use the merge strategy even if for some reason <span class="text codecolorer">git subtree</span> is not available. Here is how you would go about it:</p>
<p>Add the dependency as a simple <a href="https://github.com/git/git/blob/master/contrib/subtree/INSTALL">git remote</a>:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">git remote add -f tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git</div></td></tr></tbody></table></div>

</pre>
<p>Before reading the contents of the dependency into the repository it&#8217;s important to record a merge so that we can track the entire tree history of the plug-in up to this point:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">git merge -s ours --no-commit tpope-vim-surround/master</div></td></tr></tbody></table></div>

</pre>
<p>Which outputs:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Automatic merge went well; stopped before committing as requested</div></td></tr></tbody></table></div>

</pre>
<p>We then read the content of the latest tree-object in the plugin repository into our working directory ready to be committed:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">git read-tree --prefix=.vim/bundle/tpope-vim-surround/ -u tpope-vim-surround/master</div></td></tr></tbody></table></div>

</pre>
<p>Now we can commit (and it will be a merge commit that will preserve the history of the tree we read):</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">git ci -m&quot;[subtree] adding tpope-vim-surround&quot;<br />
<br />
[stree 779b094] [subtree] adding tpope-vim-surround</div></td></tr></tbody></table></div>

</pre>
<p>When we want to update the project we can now <span class="text codecolorer">pull</span> using the <span class="text codecolorer">subtree</span> merge strategy:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">git pull -s subtree tpope-vim-surround master</div></td></tr></tbody></table></div>

</pre>
<h2>Conclusions</h2>
<p>After having used <span class="text codecolorer">submodule</span> for a while I appreciate <span class="text codecolorer">git subtree</span> much more, lots of <span class="text codecolorer">submodule</span> problems are superseded and solved by <span class="text codecolorer">subtree</span>. As usual, with all things <span class="text codecolorer">git</span>, there is a learning curve to make the most of the feature.</p>
<p>Follow me <a href="http://twitter.com/durdn">@durdn</a> and the awesome <a href="http://twitter.com/AtlDevTools">@AtlDevtools</a> team for more Git rocking.</p>
 <img src="http://blogs.atlassian.com/?feed-stats-post-id=25292" width="1" height="1" style="display: none;" /><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?a=skMdUWJXtZc:BDLMtVyjeDY:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?a=skMdUWJXtZc:BDLMtVyjeDY:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?i=skMdUWJXtZc:BDLMtVyjeDY:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/AtlassianDeveloperBlog/~4/skMdUWJXtZc" height="1" width="1"/>]]></content:encoded><description>The Internet is full of articles on why you should not use Git submodules. I mostly agree, although I am not so harsh in my evaluation. As I explained in a previous post, submodules are useful for a few use cases but have several drawbacks. Are there alternatives? The answer is: yes! There are (at least) two tools that can help track the history of software dependencies in your project while allowing you to keep using git: git subtree google repo In this post I will be looking at git subtree and show why it is an improvement &amp;#8211; albeit not perfect &amp;#8211; over git submodule. As a working example I run to my usual use case. How do I easily store and keep up to date the vim plugins used in my dotfiles? Why use subtree instead of submodule? There are several reasons why you might find subtree better to use: Management of a simple workflow is easy. Older version of git are supported (even before v1.5.2). The sub-project&amp;#8217;s code is available right after the clone of the super project is done. subtree does not require users of your repository to learn anything new, they can ignore the fact that you are using subtree to manage dependencies. subtree does not add new metadata files like submodules doe (i.e. .gitmodule). Contents of the module can be modified without having a separate repository copy of the dependency somewhere else. In my opinion the drawbacks are acceptable: You must learn about a new merge strategy (i.e. subtree). Contributing code back upstream for the sub-projects is slightly more complicated. The responsibility of not mixing super and sub-project code in commits lies with you. How to use git subtree? git subtree is available in stock version of git available since May 2012 – 1.7.11+. The version installed by homebrew on OSX already has subtree properly wired but on some platforms you might need to follow the installation instructions. Let me show you the canonical example of tracking a vim plug-in using git subtree. The quick and dirty way without remote tracking If you just want a couple of one liners to cut and paste just read this paragraph. First add the subtree at a specified prefix folder: 1git subtree add --prefix .vim/bundle/tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git master --squash (The common practice is to not store the entire history of the sub-project in your main repository, but If you want to preserve it just omit the &amp;#8211;squash flag.) The above command produces this output: 12345678910git fetch https://bitbucket.org/vim-plugins-mirror/vim-surround.git master warning: no common commits remote: Counting objects: 338, done. remote: Compressing objects: 100% (145/145), done. remote: Total 338 (delta 101), reused 323 (delta 89) Receiving objects: 100% (338/338), 71.46 KiB, done. Resolving deltas: 100% (101/101), done. From https://bitbucket.org/vim-plugins-mirror/vim-surround.git * branch &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160; &amp;#160;master &amp;#160; &amp;#160; -} FETCH_HEAD Added dir '.vim/bundle/tpope-vim-surround' As you can see this records a merge commit by squashing the whole history of the vim-surround repository into a single one: 121bda0bd [3 minutes ago] (HEAD, [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.atlassian.com/2013/05/alternatives-to-git-submodule-git-subtree/feed/</wfw:commentRss><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">6</slash:comments><feedburner:origLink>http://blogs.atlassian.com/2013/05/alternatives-to-git-submodule-git-subtree/</feedburner:origLink></item><item><title>git? tig!</title><link>http://feedproxy.google.com/~r/AtlassianDeveloperBlog/~3/kpbUPhceBK4/</link><category>Developer</category><category>DVCS</category><category>git</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Antoine Büsch</dc:creator><pubDate>Tue, 07 May 2013 04:30:35 PDT</pubDate><guid isPermaLink="false">http://blogs.atlassian.com/?p=24355</guid><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>I&#8217;m a big fan of Git, but I&#8217;m not such a big fan of most UIs for it, especially the ones integrated into IDEs. I find them convoluted and confusing. They try to map some generic &#8220;VCS&#8221; language onto the commands, or try to hide too much, making it hard to understand what&#8217;s going on. Or worse: they&#8217;re written in Tcl/Tk&#8230;</p>
<p>In short, I don&#8217;t trust &#8216;em.</p>
<p>So command line it is for me, which is fine because I love my command line. Except once in a while, it&#8217;s nice to be able to see a &#8220;graphical&#8221; view of your history, or to have a bit of help when preparing your commits.</p>
<p>Enter tig. tig is a text-mode, ncurses-based UI for git written by <a href="https://profiles.google.com/jonas.fonseca">Jonas Fonseca</a>. In short, it is the mutt to your Outlook, the Vim to your Emacs, the w3m to your Firefox. I use it all the time, but I haven&#8217;t seen many people using it so I thought I&#8217;d publicize it a bit. So, why is it awesome?</p>
<h3 id="git?tig!-It'sinsanelyfast">It&#8217;s insanely fast</h3>
<p>Seriously. Three letters to type, and it instantly shows up. No fussing around with your mouse, or alt-tabbing to another window, or waiting for a JVM to start. It&#8217;s there at your fingertips whenever you need it. It literally loads the 50,000 commits of the JIRA codebase in a fraction of a second.</p>
<h3 id="git?tig!-Historyview">History view</h3>
<p>The default view when launching tig is the history view. It&#8217;s basically a <tt>git log</tt>, with a bit of ASCII-art to represent the history (you can hide the graph with <tt>g</tt>). Without any argument, it displays the current branch. You can also pass it the name of a branch, or <tt>--all</tt> for all branches. You can also pass it a range of commits as git log would expect (e.g. <tt>tig master..branch</tt>). You can navigate through the commits with arrow keys or j/k. Use the <tt>/</tt> key to search (match is done on summary or author).</p>
<p>Pressing <tt>Enter</tt> on a commit opens that commit in a split diff view.</p>
<p style="text-align: center;"><a href="http://atlassian.wpengine.netdna-cdn.com/wp-content/uploads/tig-2.png" rel="lightbox[24355]" title="git? tig!"><img class="size-medium wp-image-24802 aligncenter" alt="tig-2" src="http://atlassian.wpengine.netdna-cdn.com/wp-content/uploads/tig-2-300x187.png" width="300" height="187" /></a></p>
<p>You can then navigate in the diff view using the <tt>j/k</tt> keys. At the beginning of the diff is the list of files that the commit touched. If you select one of them and press <tt>Enter</tt>, you will directly jump to the beginning of that file in the diff. Press <tt>q</tt> to close the diff view (and press <tt>q</tt> a second time to quit tig).</p>
<p>If you press <tt>t</tt> on a commit in the history view, you will open the tree view. In this view, you browse the content of your repository in exactly the state it was at that point in time (just use the arrow keys and <tt>Enter</tt>), without having to do a <tt>git checkout</tt>.</p>
<h3 id="git?tig!-Statusview">Status view</h3>
<p>The is the killer feature in my opinion, and the one I use the most. If you start it with <tt>tig status</tt>, or if you press <tt>shift-S</tt> in the main view, you will go to the status view. This is like <tt>git status</tt>, but interactive. You can see the files that you&#8217;ve modified and staged, the files you&#8217;ve modified but haven&#8217;t staged yet, and the files that are no yet tracked by git. If you select a file that is not staged or untracked and press <tt>u</tt>, it will stage it. If you select a staged file and press <tt>u</tt>, it will unstage it. No need to remember that pesky <tt>git reset HEAD &lt;file&gt;</tt> command. You can also press <tt>!</tt> on a file to revert all uncommitted changes to that file.</p>
<p>If you press <tt>Enter</tt> on a file, you will see a diff view of the changes you&#8217;ve made to that file (press <tt>q</tt> to close that view), making it easy to review what you want to commit or not. Even better: you can navigate in the diff with the <tt>j/k</tt> keys (line by line), or the <tt>@</tt> key (chunk by chunk). If you then press <tt>u</tt> it will only stage the current diff chunk (a section in the diff that starts with <tt>@@</tt>). You can also stage a single line with <tt>1</tt>. It&#8217;s all the power of <tt>git add -i</tt>, except easy to use.</p>
<p>When you are ready to commit,  press <tt>shift-C</tt>. and it will open your favourite editor to enter the commit message (make sure you close any open diff view first).</p>
<p style="text-align: center;"><a href="http://atlassian.wpengine.netdna-cdn.com/wp-content/uploads/tig-4.png" rel="lightbox[24355]" title="git? tig!"><img class="size-medium wp-image-24803 aligncenter" alt="tig-4" src="http://atlassian.wpengine.netdna-cdn.com/wp-content/uploads/tig-4-300x187.png" width="300" height="187" /></a></p>
<h3 id="git?tig!-Blameview">Blame view</h3>
<p>Want to know who messed up your beautiful code or introduced that nasty bug? Just do <tt>tig blame &lt;file&gt;</tt>. It is similar to <tt>git blame</tt> or <tt>Git -&gt; Annotate</tt> in IDEA. Just select a line and press <tt>Enter</tt>, and it will show you the last commit that touched that line.</p>
<p style="text-align: center;"><a href="http://atlassian.wpengine.netdna-cdn.com/wp-content/uploads/tig-6.png" rel="lightbox[24355]" title="git? tig!"><img class="size-medium wp-image-24804 aligncenter" alt="tig-6" src="http://atlassian.wpengine.netdna-cdn.com/wp-content/uploads/tig-6-300x187.png" width="300" height="187" /></a></p>
<h3 id="git?tig!-Pagermode">Pager mode</h3>
<p>Got a fancy <tt>git log</tt> command that you&#8217;ve tweaked to display just the information you want? Just pipe its output into tig to have it nicely colorised, and easy to scroll back and forth. Also, if you&#8217;re on a line that contains a commit hash, you can just press enter to view that commit. This should work for most Git commands.</p>
<h3 id="git?tig!-HowdoIgetit?">How do I get it?</h3>
<p>If you use OS X, you can easily install it via homebrew, and most Linux distributions should have a package for it. If not, you can always get the source from <a href="http://jonas.nitro.dk/tig/" rel="nofollow">http://jonas.nitro.dk/tig/</a> and compile it yourself. I think it is even available for Cygwin, so there&#8217;s no reason not to try it!</p>
<p>Don&#8217;t hesitate to look at the man page, or press <tt>h</tt> inside tig: There&#8217;s a lot more you can do with it.</p>
 <img src="http://blogs.atlassian.com/?feed-stats-post-id=24355" width="1" height="1" style="display: none;" /><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?a=kpbUPhceBK4:KUV1o2SfAb4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?a=kpbUPhceBK4:KUV1o2SfAb4:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?i=kpbUPhceBK4:KUV1o2SfAb4:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/AtlassianDeveloperBlog/~4/kpbUPhceBK4" height="1" width="1"/>]]></content:encoded><description>I&amp;#8217;m a big fan of Git, but I&amp;#8217;m not such a big fan of most UIs for it, especially the ones integrated into IDEs. I find them convoluted and confusing. They try to map some generic &amp;#8220;VCS&amp;#8221; language onto the commands, or try to hide too much, making it hard to understand what&amp;#8217;s going on. Or worse: they&amp;#8217;re written in Tcl/Tk&amp;#8230; In short, I don&amp;#8217;t trust &amp;#8216;em. So command line it is for me, which is fine because I love my command line. Except once in a while, it&amp;#8217;s nice to be able to see a &amp;#8220;graphical&amp;#8221; view of your history, or to have a bit of help when preparing your commits. Enter tig. tig is a text-mode, ncurses-based UI for git written by Jonas Fonseca. In short, it is the mutt to your Outlook, the Vim to your Emacs, the w3m to your Firefox. I use it all the time, but I haven&amp;#8217;t seen many people using it so I thought I&amp;#8217;d publicize it a bit. So, why is it awesome? It&amp;#8217;s insanely fast Seriously. Three letters to type, and it instantly shows up. No fussing around with your mouse, or alt-tabbing to another window, or waiting for a JVM to start. It&amp;#8217;s there at your fingertips whenever you need it. It literally loads the 50,000 commits of the JIRA codebase in a fraction of a second. History view The default view when launching tig is the history view. It&amp;#8217;s basically a git log, with a bit of ASCII-art to represent the history (you can hide the graph with g). Without any argument, it displays the current branch. You can also pass it the name of a branch, or --all for all branches. You can also pass it a range of commits as git log would expect (e.g. tig master..branch). You can navigate through the commits with arrow keys or j/k. Use the / key to search (match is done on summary or author). Pressing Enter on a commit opens that commit in a split diff view. You can then navigate in the diff view using the j/k keys. At the beginning of the diff is the list of files that the commit touched. If you select one of them and press Enter, you will directly jump to the beginning of that file in the diff. Press q to close the diff view (and press q a second time to quit tig). If you press t on a commit in the history view, you will open the tree view. In this view, you browse the content of your repository in exactly the state it was at that point in time (just use the arrow keys and Enter), without having to do a git checkout. Status view The is the killer feature in my opinion, and the one I use the most. If you start it with tig status, or if you press shift-S in the main view, you will go to the status view. This is like git status, but interactive. You can see the files that you&amp;#8217;ve modified and staged, the files you&amp;#8217;ve modified but haven&amp;#8217;t staged [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.atlassian.com/2013/05/git-tig/feed/</wfw:commentRss><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">42</slash:comments><feedburner:origLink>http://blogs.atlassian.com/2013/05/git-tig/</feedburner:origLink></item><item><title>Git Branching and Forking in the Enterprise: Why Fork?</title><link>http://feedproxy.google.com/~r/AtlassianDeveloperBlog/~3/TYoNJtJqla0/</link><category>DVCS</category><category>dvcs</category><category>fork</category><category>git</category><category>Workflow</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Nicola Paolucci</dc:creator><pubDate>Mon, 06 May 2013 05:09:32 PDT</pubDate><guid isPermaLink="false">http://blogs.atlassian.com/?p=25173</guid><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>Enterprise DVCS Workflows are settling and patterns are consolidating. The flexibility <a href="http://git-scm.com/">git</a> gives teams is so broad that even within a single company different teams might use different approaches to code sharing and collaboration.</p>
<p>I speak from hard evidence as this is exactly what happens at Atlassian. The <a href="http://www.atlassian.com/software/stash/overview">Stash</a> team works differently than the <a href="http://www.atlassian.com/software/confluence/overview/team-collaboration-software">Confluence</a> team which works differently from the <a href="http://www.atlassian.com/software/jira/overview">JIRA</a> team. They all share a similar Agile process but have different approaches to branching, Continuous Integration and team organization.</p>
<p>Differences not withstanding, common patterns are emerging. A recurring paradigm in the industry is the use of a centralized repository with a <em>master</em> branch, several stable lines of development and follow a feature branch workflow where new features and bug fixes can be developed independently. This provides quick integration and allows teams to leverage the efficiency boost that comes with DVCS.</p>
<p><img src="http://atlassian.wpengine.netdna-cdn.com/wp-content/uploads/full-branching-model.png" alt="stash team image" /></p>
<p>If you read this and ponder a bit you might ask: if a company is following the centralized repository workflow listed above, why would they still need forks?</p>
<p>There are several reasons why forking is useful and vital even within the enterprise. Before I present them let me first backtrack a bit and provide some context and definitions.</p>
<h2>Table of Contents</h2>
<ol>
<li><a href="#what">What is a Fork?</a></li>
<li><a href="#award">Forks have won the Open Source workflow choice award</a></li>
<li><a href="#need">Do you need Forks in the Enterprise?</a></li>
<li><a href="#guard">Guard core components but encourage innovation and adoption</a></li>
<li><a href="#cross">Organize cross department collaboration</a></li>
<li><a href="#noise">Reduce noise</a></li>
<li><a href="#contractors">Streamline interaction with contractors</a></li>
<li><a href="#dev-to-dev">Developer to developer interactions behind the firewall</a></li>
<li><a href="#conclusions">Conclusions</a></li>
</ol>
<h2 id="what">What is a Fork?</h2>
<p>In recent DVCS terminology a fork is a remote, server-side copy of a repository, distinct from the original. A clone is not a fork; a clone is a local copy of some remote repository. This differs slightly form the <a href="http://en.wikipedia.org/wiki/Fork_%28software_development%29">general definition of forks in software development</a> but is the meaning that I will refer to in the course of this piece.</p>
<h2 id="award">Forks have won the Open Source workflow choice award</h2>
<p>If you have been living under a rock for the past several years let me reveal to you an indisputable fact: <em>forks</em> have won the Open Source process choice award. They foster participation by drastically lowering the barrier of entry and the friction of code collaboration.</p>
<p>Anybody can fork an open project and the original author does not incur in penalties or burdens because of it, the operation is transparent. He will <em>potentially</em> receive feedback or improvements in the form of <a href="https://confluence.atlassian.com/display/BITBUCKET/Working+with+pull+requests">pull requests</a> but that&#8217;s it.</p>
<h2 id="need">Do you need Forks in the Enterprise?</h2>
<p>A fully distributed de-centralized approach is effective for loosely connected open source teams but what about enterprise teams all working in the same office with a central repository? Are forks useful in this setting?</p>
<p>Forks are surprisingly useful also behind the firewalls of the enterprise.</p>
<p>In abstract terms <em>forks</em> can be used within an organization to <strong>manage trust, track the maturity of codebases and facilitate cross team collaboration</strong>.</p>
<p>Concrete examples include:</p>
<ul>
<li>Guard core components but encourage innovation and adoption.</li>
<li>Organize Cross department collaboration.</li>
<li>Reduce noise.</li>
<li>Streamline interaction with contractors.</li>
<li>Developer to Developer interactions behind the firewall.</li>
</ul>
<p>Let&#8217;s see in more details each one.</p>
<h2 id="guard">Guard core components but encourage innovation and adoption</h2>
<p>Many enterprises have core components that are reused across the company. Often these pieces have stricter policies regarding who can make changes, stability guarantees and heavier review process.</p>
<p>Forks allow to keep the sanctioned code closely guarded but at the same time encourage adoption and innovation.</p>
<p>A non-sanctioned team or a lone developer with interest in the matter can fork the project and start contributing, without requiring supervision and without disrupting the core team&#8217;s work. Collaboration still happens as usual with <a href="https://developer.atlassian.com/display/AUI/Atlassian+User+Interface+%28AUI%29+Developer+Documentation">pull requests</a> and feature branches.</p>
<p>By keeping experiments out of the main repositories one can effectively manage and track the maturity of contributions. Crazy unstable hacks remain sealed in their own forks; Solid pieces can be merged into the core components after they are reviewed. Why forks allow this and regular clones do not? Because forks allow the tracking bit: anybody can clone locally and work on their own experiments but pushing this code to a server-side fork allows it to be traceable.</p>
<p>Atlassian has several core libraries shared between the various groups, like for example the <a href="https://developer.atlassian.com/display/AUI/Atlassian+User+Interface+%28AUI%29+Developer+Documentation">Atlassian User Interface</a>. Forks relieve the burden on the Core teams maintaining them. No spurious feature branches and a messy tree appear in their main repository anymore.</p>
<h2 id="cross">Organize cross department collaboration</h2>
<p>An alternative but similar scenario is also common: when there is no &#8220;core&#8221; or ruling team over a certain software component but several departments maintain their own modified versions of the same piece of infrastructure. <em>Forks</em> allow teams to have control and guarantees on their own variations. Collaboration between departments is still easy and transparent with <a href="https://developer.atlassian.com/display/AUI/Atlassian+User+Interface+%28AUI%29+Developer+Documentation">pull requests</a> and the awesome integration features of <a href="http://git-scm.com/">git</a>.</p>
<h2 id="noise">Reduce noise</h2>
<p>When teams grow very large the noise of feature and bug fix branches can effectively become too much for UIs to properly display. Project history becomes so messy that is hard to understand what is going on and what is being merged where. The tools can become less effective in this situation.</p>
<p>Again forks allow sub-teams to collaborate in the open but keep the central repositories where integrations happen as clean as possible.</p>
<h2 id="contractors">Streamline interaction with contractors</h2>
<p>Another area where <em>forks</em> are valuable is in the interaction with third parties, contractors and freelances. By providing forks as the only access point for contractors to your repositories one can gain several benefits:</p>
<ul>
<li>Keep your main repository clean and restricted.</li>
<li>Integrate third party work work after review at scheduled times.</li>
<li>Retain the common git collaboration process.</li>
</ul>
<h2 id="dev-to-dev">Developer to developer interactions behind the firewall</h2>
<p>Let&#8217;s not leave out one final and very important piece of the puzzle.</p>
<p><strong>Developer&#8217;s personal forks!</strong> A developer might be happy to hack, improve and enhance some piece of core infrastructure but he might not want to share his early work with the rest yet. Would you want him to push some mission critical proprietary code out in the open?</p>
<p>In other cases he might want to maintain a slightly different approach to a problem and keep the contribution locked up until he can prove that a certain design decision will reap benefits for his team. For this scenario personal forks are great.</p>
<p>Personal forks allow also for the kind of distributed, uncoordinated kind of interactions that have made DVCS extremely successful in Open Source communities.</p>
<h2 id="conclusions">Conclusions</h2>
<p>Forks are not the answer to all code collaboration woes but offer an effective solution to several concerns. In this piece I presented some ideas that support the statement that <em>forks</em> inside the enterprise help manage trust, the maturity of code bases and facilitate cross team collaboration.</p>
<p>Let me conclude by shouting that Stash&#8217;s new release includes first class <a href="http://blogs.atlassian.com/2013/05/stash-git-forking-development-workflow/">support for forks</a> in addition to a whole lot of other features.</p>
<p>As usual ping me <a href="http://twitter.com/durdn">@durdn</a> or the awesome team <a href="http://twitter.com/AtlDevTools">@AtlDevtools</a> for more DVCS trend spotting and git content.</p>
<p><em>(Credits: Branching model image was originally forked from nvie&#8217;s <a href="http://github.com/downloads/nvie/gitflow/Git-branching-model-src.key.zip">git-flow</a> Keynote source)</em></p>
 <img src="http://blogs.atlassian.com/?feed-stats-post-id=25173" width="1" height="1" style="display: none;" /><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?a=TYoNJtJqla0:yG4mnfedcY0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?a=TYoNJtJqla0:yG4mnfedcY0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?i=TYoNJtJqla0:yG4mnfedcY0:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/AtlassianDeveloperBlog/~4/TYoNJtJqla0" height="1" width="1"/>]]></content:encoded><description>Enterprise DVCS Workflows are settling and patterns are consolidating. The flexibility git gives teams is so broad that even within a single company different teams might use different approaches to code sharing and collaboration. I speak from hard evidence as this is exactly what happens at Atlassian. The Stash team works differently than the Confluence team which works differently from the JIRA team. They all share a similar Agile process but have different approaches to branching, Continuous Integration and team organization. Differences not withstanding, common patterns are emerging. A recurring paradigm in the industry is the use of a centralized repository with a master branch, several stable lines of development and follow a feature branch workflow where new features and bug fixes can be developed independently. This provides quick integration and allows teams to leverage the efficiency boost that comes with DVCS. If you read this and ponder a bit you might ask: if a company is following the centralized repository workflow listed above, why would they still need forks? There are several reasons why forking is useful and vital even within the enterprise. Before I present them let me first backtrack a bit and provide some context and definitions. Table of Contents What is a Fork? Forks have won the Open Source workflow choice award Do you need Forks in the Enterprise? Guard core components but encourage innovation and adoption Organize cross department collaboration Reduce noise Streamline interaction with contractors Developer to developer interactions behind the firewall Conclusions What is a Fork? In recent DVCS terminology a fork is a remote, server-side copy of a repository, distinct from the original. A clone is not a fork; a clone is a local copy of some remote repository. This differs slightly form the general definition of forks in software development but is the meaning that I will refer to in the course of this piece. Forks have won the Open Source workflow choice award If you have been living under a rock for the past several years let me reveal to you an indisputable fact: forks have won the Open Source process choice award. They foster participation by drastically lowering the barrier of entry and the friction of code collaboration. Anybody can fork an open project and the original author does not incur in penalties or burdens because of it, the operation is transparent. He will potentially receive feedback or improvements in the form of pull requests but that&amp;#8217;s it. Do you need Forks in the Enterprise? A fully distributed de-centralized approach is effective for loosely connected open source teams but what about enterprise teams all working in the same office with a central repository? Are forks useful in this setting? Forks are surprisingly useful also behind the firewalls of the enterprise. In abstract terms forks can be used within an organization to manage trust, track the maturity of codebases and facilitate cross team collaboration. Concrete examples include: Guard core components but encourage innovation and adoption. Organize Cross department collaboration. Reduce [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.atlassian.com/2013/05/git-branching-and-forking-in-the-enterprise-why-fork/feed/</wfw:commentRss><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">4</slash:comments><feedburner:origLink>http://blogs.atlassian.com/2013/05/git-branching-and-forking-in-the-enterprise-why-fork/</feedburner:origLink></item><item><title>Git: Automatic Merges With Server Side Hooks (For The Win!)</title><link>http://feedproxy.google.com/~r/AtlassianDeveloperBlog/~3/h_QM1NeCwtA/</link><category>Developer</category><category>DVCS</category><category>git</category><category>hooks</category><category>merge</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Nicola Paolucci</dc:creator><pubDate>Thu, 02 May 2013 04:46:46 PDT</pubDate><guid isPermaLink="false">http://blogs.atlassian.com/?p=24967</guid><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>This will be standard and easily understandable to anyone who has already been working with <a href="http://git-scm.com/">git</a> for a while. If you come from a centralized, old school version control background and you are thinking of switching to Git &#8211; which I heartily <a href="http://git-scm.com/about">recommend</a> &#8211; you will find the topic of this post awesome, almost magical. Not as magical as <a href="http://en.wikipedia.org/wiki/My_Little_Pony:_Friendship_Is_Magic_fandom">mini ponies</a> but &#8230; you get the picture.</p>
<p>It is still awesome to me even though I&#8217;ve been working with <span class="text codecolorer">git</span> for a while already.</p>
<p>I am talking about <strong>automated</strong> merges from stable/maintenance branches to master.</p>
<h2>Real World Scenario</h2>
<p>Let me give you an example taken from the way the <a href="http://www.atlassian.com/software/stash/overview">Stash</a> development team works. The Stash team maintains, at any given point in time, several stable code lines that are out in the market (let&#8217;s limit the example to <span class="text codecolorer">2.1</span>, <span class="text codecolorer">2.2</span> and <span class="text codecolorer">2.3</span> releases) while at the same time they merge feature branches into <em>master</em> in preparation for an upcoming release branch <span class="text codecolorer">2.4</span>.</p>
<p><a href="http://atlassian.wpengine.netdna-cdn.com/wp-content/uploads/auto-merge-1.png" rel="lightbox[24967]" title="Git: Automatic Merges With Server Side Hooks (For The Win!)"><img class="alignnone size-large wp-image-24968" alt="auto-merge-1" src="http://atlassian.wpengine.netdna-cdn.com/wp-content/uploads/auto-merge-1-362x600.png" width="362" height="600" /></a></p>
<p>Now check out the magical bit. Whenever a maintenance fix is applied to any of the stable branches it is <strong>automatically merged</strong>(!!) in cascade to the master branch. No user interaction is required (except in the rare occasion when a conflict arises). (<em>It is understood that a fix is committed to a stable branch only after the change has been peer reviewed, all tests pass, the builds are green and the performance metrics have not been affected</em>).</p>
<p><a href="http://atlassian.wpengine.netdna-cdn.com/wp-content/uploads/auto-merge-2.png" rel="lightbox[24967]" title="Git: Automatic Merges With Server Side Hooks (For The Win!)"><img class="alignnone size-large wp-image-24969" alt="auto-merge-2" src="http://atlassian.wpengine.netdna-cdn.com/wp-content/uploads/auto-merge-2-346x600.png" width="346" height="600" /></a></p>
<p>As you can see a fix applied to the <span class="text codecolorer">2.2</span> code line will <strong>automatically</strong> be first applied to the <span class="text codecolorer">2.3</span> branch and then from the <span class="text codecolorer">2.3</span> branch to <span class="text codecolorer">master</span>. All without user interaction. How cool is that?</p>
<p>How is that even possible you ask? Can I have that too please? Well of course.</p>
<h2>Automatic Merges are the rule, not the exception</h2>
<p>One of the areas where <span class="text codecolorer">git</span> excels at is merging code lines. <span class="text codecolorer">git</span> is so good at this that most of the times the merges just work. Except when they <a href="http://git-blame.blogspot.com.au/2013/04/where-do-evil-merges-come-from.html">don&#8217;t</a>. In the case of stable code lines, merge conflicts are even more rare given that the amount of code involved in those fixes is <em>generally</em> small.</p>
<h2>How to setup Automated merges, the manual way with hooks</h2>
<p>Let me show you how you can implement a similar workflow. First let&#8217;s write something that will accomplish it on a local machine.</p>
<p>The first part of the puzzle is to write a script that you can run after you&#8217;ve committed a fix on a stable branch:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#!/bin/sh<br />
# Automatically merge the last commit through the following branches:<br />
# 2.1 -} 2.2 -} 2.3 -} master<br />
<br />
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)<br />
LAST_COMMIT=$(git rev-list -1 HEAD)<br />
<br />
echo Automatically merging commit $LAST_COMMIT from $CURRENT_BRANCH rippling to master<br />
<br />
case $CURRENT_BRANCH in<br />
2.1)<br />
&nbsp; git checkout 2.2 ＆＆ git merge $CURRENT_BRANCH<br />
&nbsp; git checkout 2.3 ＆＆ git merge 2.2<br />
&nbsp; git checkout master ＆＆ git merge 2.3<br />
&nbsp; git checkout $CURRENT_BRANCH<br />
&nbsp; ;;<br />
2.2)<br />
&nbsp; git checkout 2.3 ＆＆ git merge 2.2<br />
&nbsp; git checkout master ＆＆ git merge 2.3<br />
&nbsp; git checkout $CURRENT_BRANCH<br />
&nbsp; ;;<br />
2.3)<br />
&nbsp; git checkout master ＆＆ git merge 2.3<br />
&nbsp; git checkout $CURRENT_BRANCH<br />
&nbsp; ;;<br />
esac</div></td></tr></tbody></table></div>

</pre>
<p><em>(Please bear with me as I leave the error conditions and the conflicts scenarios out of this example as I just want to highlight the potential for workflow automation. In fact I will show you a more robust, visual and less error prone way to accomplish the same thing if you read on.)</em></p>
<p>Save it as <span class="text codecolorer">auto-merge.sh</span> and make it executable with:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">chmod 755 auto-merge.sh</div></td></tr></tbody></table></div>

</pre>
<p>So after you <span class="text codecolorer">check out</span> a stable branch and commit a fix &#8211; that passes all tests and has been reviewed &#8211; run the script and you will get an output like the following:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ git commit -am&quot;PRJ-1 bugfix on 2.1&quot;<br />
Automatically merging commit e42cefd7597b04a619e7f3f1b8a0bdfd3514c296 from 2.1 rippling to master<br />
Switched to branch '2.2'<br />
Updating 032c6a6..e42cefd<br />
Fast-forward<br />
a.txt | 1 +<br />
1 file changed, 1 insertion(+)<br />
Switched to branch '2.3'<br />
Updating 032c6a6..e42cefd<br />
Fast-forward<br />
a.txt | 1 +<br />
1 file changed, 1 insertion(+)<br />
Switched to branch 'master'<br />
Updating 032c6a6..e42cefd<br />
Fast-forward<br />
a.txt | 1 +<br />
1 file changed, 1 insertion(+)<br />
Switched to branch '2.1'<br />
[2.1 e42cefd] PRJ-1 bugfix on 2.1<br />
1 file changed, 1 insertion(+)</div></td></tr></tbody></table></div>

</pre>
<p>Good starting point. Now we want to automate this process for the whole team. If you review all the available <a href="http://git-scm.com/book/ch7-3.html">local</a> and <a href="http://git-scm.com/book/ch7-3.html#Server-Side-Hooks">remote hooks</a> you will quickly realize that the one we need is the <span class="text codecolorer">update</span> one, which kicks in anytime a single <span class="text codecolorer">HEAD</span>(i.e. branch) is pushed on to the server.</p>
<p>Catering for error conditions makes writing this in <span class="text codecolorer">bash</span> less than optimal so I spent some time cooking the <span class="text codecolorer">update</span> hook in Python. It grew a bit too much for me to show you the source in its entirety here. Check it out on bitbucket at <a href="https://bitbucket.org/durdn/automatic-merge-hook">automatic-merge-hook</a>. How to use it? Edit the <span class="text codecolorer">branches_flow</span> variable (line 71), upload into the hooks folder of your bare repository on your server and you can have automatic merges too:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">branches_flow = ['2.1','2.2','2.3', 'master']</div></td></tr></tbody></table></div>

</pre>
<p>Done! Now when you create a new commit on say the <span class="text codecolorer">2.1</span> branch you will get a nice <em>ripple</em> merge to <span class="text codecolorer">master</span>.</p>
<p>Here is the core Python logic that will automatically merge the branch with the next in the list:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">def automatic_merge(head_before_start, latest, branches_flow):<br />
&nbsp; &nbsp; log.debug('Auto-merging through: %s' % branches_flow)<br />
&nbsp; &nbsp; reset = False<br />
&nbsp; &nbsp; for branch in branches_flow:<br />
&nbsp; &nbsp; &nbsp; &nbsp; onto = next(branch, branches_flow)<br />
&nbsp; &nbsp; &nbsp; &nbsp; if onto:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; exitcode = call('git checkout %s ＆＆ git merge refs/heads/%s' % (onto, branch))<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if exitcode:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.debug('Merge of %s onto %s failed, must reset to original state' % (branch, onto))<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; call('git reset --hard %s' % (latest[onto]))<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; reset = True<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break<br />
<br />
&nbsp; &nbsp; if reset:<br />
&nbsp; &nbsp; &nbsp; &nbsp; for to_reset in branches_flow:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; call('git checkout %s ＆＆ git reset --hard %s ＆＆ git checkout %s' % (<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; to_reset, latest[to_reset], head_before_start))<br />
&nbsp; &nbsp; &nbsp; &nbsp; sys.exit('Automated merges failed, reset to original state')</div></td></tr></tbody></table></div>

</pre>
<h2>Visual Way Using A Stash Plugin</h2>
<p>What if you&#8217;re not a fan of fiddling with hooks on the command line or on your remote server via <span class="text codecolorer">ssh</span>? There is an easier shrink-wrapped almost one-click way to accomplish the same thing using <a href="http://www.atlassian.com/software/stash/overview">Stash</a>.</p>
<p>It is the <a href="https://bitbucket.org/atlassianlabs/stash-auto-merge-plugin">Stash Auto Merge Plugin</a>. The way it works is very simple, you <a href="https://confluence.atlassian.com/display/UPM/Installing+a+Plugin">install the plugin</a>, you go to the <em>Auto merge</em> menu in the <em>Settings</em> tab and you fill in your <strong>automated branching flow</strong> using arrows (<span class="text codecolorer">-&gt;</span>):</p>
<p><a href="http://atlassian.wpengine.netdna-cdn.com/wp-content/uploads/auto-merge-plugin-1.jpg" rel="lightbox[24967]" title="Git: Automatic Merges With Server Side Hooks (For The Win!)"><img class="alignnone size-large wp-image-24970" alt="auto-merge-plugin-1" src="http://atlassian.wpengine.netdna-cdn.com/wp-content/uploads/auto-merge-plugin-1-600x247.jpg" width="600" height="247" /></a></p>
<p>And then the magic happens automagically. The plugin also handles the edge cases as follows:</p>
<ul>
<li>There are no changes to merge &#8211; Skip to the next branches</li>
<li>There is an open pull request for the source and destination branches &#8211; break, the changes will be incorporated into the pull request</li>
<li>There are conflicts &#8211; open a pull request</li>
</ul>
<p>If that is not awesome, I don&#8217;t know what is!</p>
<h2>Bonus: Sample Branching Model Of The Stash Development Team</h2>
<p>I&#8217;ve only skimmed over it earlier because it&#8217;s not the topic of this post but If you&#8217;re very familiar with <a href="http://www.atlassian.com/git/workflows">git development workflows</a> and promise not to be overwhelmed you might be interested to see the full branching model used by Atlassian&#8217;s <a href="http://www.atlassian.com/software/stash/overview">Stash</a> Development team.</p>
<p><a href="http://blogs.atlassian.com/2013/05/git-automatic-merges-with-server-side-hooks-for-the-win/full-branching-model/" rel="attachment wp-att-24979"><img class="alignnone size-large wp-image-24979" alt="full-branching-model" src="http://atlassian.wpengine.netdna-cdn.com/wp-content/uploads/full-branching-model-470x600.png" width="470" height="600" /></a></p>
<p>If the picture is unclear fear not. The way the Stash team works will be explained in detail soon on this channel. Follow <a href="http://twitter.com/AtlDevTools">@AtlDevTools</a> or me <a href="http://twitter.com/durdn">@durdn</a> on twitter to get it fresh out of the presses.</p>
<p>(<em>In the snippets above I had to use the unicode symbol ＆ in place for the regular ampersand as WordPress is rather zealous with regards of escaping them, they would appear as &#8220;<span class="text codecolorer">&amp;</span>amp;&#8221;. Please replace the ＆ with a regular ampersand. The source code on bitbucket is already fine, of course.</em>).</p>
 <img src="http://blogs.atlassian.com/?feed-stats-post-id=24967" width="1" height="1" style="display: none;" /><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?a=h_QM1NeCwtA:UOzN4gqyn9E:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?a=h_QM1NeCwtA:UOzN4gqyn9E:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?i=h_QM1NeCwtA:UOzN4gqyn9E:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/AtlassianDeveloperBlog/~4/h_QM1NeCwtA" height="1" width="1"/>]]></content:encoded><description>This will be standard and easily understandable to anyone who has already been working with git for a while. If you come from a centralized, old school version control background and you are thinking of switching to Git &amp;#8211; which I heartily recommend &amp;#8211; you will find the topic of this post awesome, almost magical. Not as magical as mini ponies but &amp;#8230; you get the picture. It is still awesome to me even though I&amp;#8217;ve been working with git for a while already. I am talking about automated merges from stable/maintenance branches to master. Real World Scenario Let me give you an example taken from the way the Stash development team works. The Stash team maintains, at any given point in time, several stable code lines that are out in the market (let&amp;#8217;s limit the example to 2.1, 2.2 and 2.3 releases) while at the same time they merge feature branches into master in preparation for an upcoming release branch 2.4. Now check out the magical bit. Whenever a maintenance fix is applied to any of the stable branches it is automatically merged(!!) in cascade to the master branch. No user interaction is required (except in the rare occasion when a conflict arises). (It is understood that a fix is committed to a stable branch only after the change has been peer reviewed, all tests pass, the builds are green and the performance metrics have not been affected). As you can see a fix applied to the 2.2 code line will automatically be first applied to the 2.3 branch and then from the 2.3 branch to master. All without user interaction. How cool is that? How is that even possible you ask? Can I have that too please? Well of course. Automatic Merges are the rule, not the exception One of the areas where git excels at is merging code lines. git is so good at this that most of the times the merges just work. Except when they don&amp;#8217;t. In the case of stable code lines, merge conflicts are even more rare given that the amount of code involved in those fixes is generally small. How to setup Automated merges, the manual way with hooks Let me show you how you can implement a similar workflow. First let&amp;#8217;s write something that will accomplish it on a local machine. The first part of the puzzle is to write a script that you can run after you&amp;#8217;ve committed a fix on a stable branch: 1234567891011121314151617181920212223242526#!/bin/sh # Automatically merge the last commit through the following branches: # 2.1 -} 2.2 -} 2.3 -} master CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) LAST_COMMIT=$(git rev-list -1 HEAD) echo Automatically merging commit $LAST_COMMIT from $CURRENT_BRANCH rippling to master case $CURRENT_BRANCH in 2.1) &amp;#160; git checkout 2.2 ＆＆ git merge $CURRENT_BRANCH &amp;#160; git checkout 2.3 ＆＆ git merge 2.2 &amp;#160; git checkout master ＆＆ git merge 2.3 &amp;#160; git checkout $CURRENT_BRANCH &amp;#160; ;; 2.2) &amp;#160; git checkout 2.3 ＆＆ git merge 2.2 &amp;#160; git checkout master ＆＆ git [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.atlassian.com/2013/05/git-automatic-merges-with-server-side-hooks-for-the-win/feed/</wfw:commentRss><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">5</slash:comments><feedburner:origLink>http://blogs.atlassian.com/2013/05/git-automatic-merges-with-server-side-hooks-for-the-win/</feedburner:origLink></item><item><title>How Stash Developers Avoid Branching from a Bad Commit</title><link>http://feedproxy.google.com/~r/AtlassianDeveloperBlog/~3/FkDFoB5ulmw/</link><category>Bamboo</category><category>Developer</category><category>Stash</category><category>git</category><category>hooks</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Tim Pettersen</dc:creator><pubDate>Wed, 01 May 2013 17:09:18 PDT</pubDate><guid isPermaLink="false">http://blogs.atlassian.com/?p=25203</guid><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>One of my colleagues <a href="http://blogs.atlassian.com/2013/04/avoid-branching-from-bad-commit/" title="How Confluence Developers Avoid Branching from a Bad Commit">recently blogged</a> about how the Confluence team avoids creating feature branches from bad commits. This blog post describes how to take the same idea one step further.</p>
<h2>The Problem</h2>
<p>I hate it when I make a trivial change, something like:</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ git checkout master<br />
Switch to branch 'master'<br />
&nbsp;<br />
$ git checkout -b STASHDEV-1234-fix-capitalisation-of-Stash<br />
Switched to a new branch 'STASHDEV-1234-fix-capitalisation-of-Stash'<br />
&nbsp;<br />
.. change capitalization of one word in a template ..<br />
&nbsp;<br />
$ git commit -m &quot;STASHDEV-1234: Totally trivial change&quot; &amp;&amp; git push --set-upstream origin STASHDEV-1234-fix-capitalisation-of-Stash</div></td></tr></tbody></table></div>
<p>Then a few minutes later.. <strong>*BOOM*</strong></p>
<p><a href="http://atlassian.wpengine.netdna-cdn.com/wp-content/uploads/boom-0.png" rel="lightbox[25203]" title="ka-boom!"><img src="http://atlassian.wpengine.netdna-cdn.com/wp-content/uploads/boom-0-600x52.png" alt="broken builds" width="600" height="52" class="alignnone size-large wp-image-25204" title="ka-boom!" /></a></p>
<p>What the heck? How did changing the capitalization of a letter break the database migration tests?</p>
<p>Hmm.. maybe they&#8217;re flakey. Let&#8217;s re-run the build. <strong>*BOOM*</strong></p>
<p><a href="http://atlassian.wpengine.netdna-cdn.com/wp-content/uploads/boom-1.png" rel="lightbox[25203]" title="How Stash Developers Avoid Branching from a Bad Commit"><img src="http://atlassian.wpengine.netdna-cdn.com/wp-content/uploads/boom-1-600x54.png" alt="more broken builds" width="600" height="54" class="alignnone size-large wp-image-25205" /></a></p>
<p>Arggh!</p>
<p>Oh wait. Of course. I know what heinous crime I&#8217;ve committed!</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ git checkout master<br />
$ git checkout -b STASHDEV-1234-fix-capitalisation-of-Stash</div></td></tr></tbody></table></div>
<p>Little did I know, one of my co-workers had broken master at some point in the past. My crime: branching from their broken commit. A simple merge from master at this point (providing it&#8217;s green) will remedy the situation, even if it does make the history a bit uglier.</p>
<p>Wouldn&#8217;t it be nice if we could avoid this whole situation altogether?</p>
<h2>The Solution</h2>
<p>What if git warned you when you switched to a dodgy ref? Something like:</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ git checkout master<br />
master is lookin' good! c4f3b4b has 4 green builds.<br />
&nbsp;<br />
$ git checkout stable-2.3 <br />
DANGER! stable-2.3 is busted. e1324fa has 2 red builds.</div></td></tr></tbody></table></div>
<p>Then you could easily switch back to a better ref for your branch point, or slap the build breaker until they fix it.</p>
<p>I&#8217;ve built a little client-side git hook that does exactly that. It will work work for any git repository built by Bamboo or hosted by Stash, and is super easy to install.</p>
<p>Just run this command from the root of your local clone:</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">sh &lt;(curl -s https://bitbucket.org/tpettersen/post-checkout-build-status/raw/master/install.sh)</div></td></tr></tbody></table></div>
<p>You&#8217;ll be prompted for the url and credentials of either: </p>
<ul>
<li>the Bamboo server that builds your repository; or</li>
<li>the Stash server that hosts your repository (if you&#8217;ve set up your CI server to <a href="https://developer.atlassian.com/stash/docs/latest/how-tos/updating-build-status-for-commits.html">notify Stash of build results</a>).</li>
</ul>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ sh &lt;(curl -s https://bitbucket.org/tpettersen/post-checkout-build-status/raw/master/install.sh)<br />
Retrieve build status from (S)tash or (B)amboo? B<br />
Bamboo URL: bamboo.atlassian.com<br />
Username: tpettersen<br />
Password: <br />
Installing hook...<br />
post-update hook installed. Config written to .git/hooks/bamboo-config.yml</div></td></tr></tbody></table></div>
<p>It works by registering a <a href="http://git-scm.com/book/ch7-3.html">post-checkout hook</a> that hits a <a href="https://bamboo.phpbb.com/rest/api/latest/result/byChangeset/954edb3eb4f79d48c3fdf2e204791ea454145085" title="changeset end-point">little known REST end-point</a> in Bamboo that provides all build results for a particular SHA.</p>
<p>The project is <a href="https://bitbucket.org/tpettersen/post-checkout-build-status" title="post-checkout-build-status">up on Bitbucket</a> and I&#8217;m very open to pull requests.</p>
 <img src="http://blogs.atlassian.com/?feed-stats-post-id=25203" width="1" height="1" style="display: none;" /><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?a=FkDFoB5ulmw:Egp3iWTAaFQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?a=FkDFoB5ulmw:Egp3iWTAaFQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?i=FkDFoB5ulmw:Egp3iWTAaFQ:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/AtlassianDeveloperBlog/~4/FkDFoB5ulmw" height="1" width="1"/>]]></content:encoded><description>One of my colleagues recently blogged about how the Confluence team avoids creating feature branches from bad commits. This blog post describes how to take the same idea one step further. The Problem I hate it when I make a trivial change, something like: 123456789$ git checkout master Switch to branch 'master' &amp;#160; $ git checkout -b STASHDEV-1234-fix-capitalisation-of-Stash Switched to a new branch 'STASHDEV-1234-fix-capitalisation-of-Stash' &amp;#160; .. change capitalization of one word in a template .. &amp;#160; $ git commit -m &amp;#34;STASHDEV-1234: Totally trivial change&amp;#34; &amp;#38;&amp;#38; git push --set-upstream origin STASHDEV-1234-fix-capitalisation-of-Stash Then a few minutes later.. *BOOM* What the heck? How did changing the capitalization of a letter break the database migration tests? Hmm.. maybe they&amp;#8217;re flakey. Let&amp;#8217;s re-run the build. *BOOM* Arggh! Oh wait. Of course. I know what heinous crime I&amp;#8217;ve committed! 12$ git checkout master $ git checkout -b STASHDEV-1234-fix-capitalisation-of-Stash Little did I know, one of my co-workers had broken master at some point in the past. My crime: branching from their broken commit. A simple merge from master at this point (providing it&amp;#8217;s green) will remedy the situation, even if it does make the history a bit uglier. Wouldn&amp;#8217;t it be nice if we could avoid this whole situation altogether? The Solution What if git warned you when you switched to a dodgy ref? Something like: 12345$ git checkout master master is lookin' good! c4f3b4b has 4 green builds. &amp;#160; $ git checkout stable-2.3 DANGER! stable-2.3 is busted. e1324fa has 2 red builds. Then you could easily switch back to a better ref for your branch point, or slap the build breaker until they fix it. I&amp;#8217;ve built a little client-side git hook that does exactly that. It will work work for any git repository built by Bamboo or hosted by Stash, and is super easy to install. Just run this command from the root of your local clone: 1sh &amp;#60;(curl -s https://bitbucket.org/tpettersen/post-checkout-build-status/raw/master/install.sh) You&amp;#8217;ll be prompted for the url and credentials of either: the Bamboo server that builds your repository; or the Stash server that hosts your repository (if you&amp;#8217;ve set up your CI server to notify Stash of build results). 1234567$ sh &amp;#60;(curl -s https://bitbucket.org/tpettersen/post-checkout-build-status/raw/master/install.sh) Retrieve build status from (S)tash or (B)amboo? B Bamboo URL: bamboo.atlassian.com Username: tpettersen Password: Installing hook... post-update hook installed. Config written to .git/hooks/bamboo-config.yml It works by registering a post-checkout hook that hits a little known REST end-point in Bamboo that provides all build results for a particular SHA. The project is up on Bitbucket and I&amp;#8217;m very open to pull requests.</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.atlassian.com/2013/05/how-stash-developers-avoid-branching-from-a-bad-commit/feed/</wfw:commentRss><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">4</slash:comments><feedburner:origLink>http://blogs.atlassian.com/2013/05/how-stash-developers-avoid-branching-from-a-bad-commit/</feedburner:origLink></item><item><title>Git Flow Comes to Java</title><link>http://feedproxy.google.com/~r/AtlassianDeveloperBlog/~3/qusJ5WhwUYA/</link><category>Developer</category><category>DVCS</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Jonathan Doklovic</dc:creator><pubDate>Tue, 23 Apr 2013 09:51:32 PDT</pubDate><guid isPermaLink="false">http://blogs.atlassian.com/?p=25109</guid><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p>As a Java developer, I&#8217;m always trying to find ways to streamline all the mundane tasks that come along with development but aren&#8217;t necessarily part of the actual code I&#8217;m trying to write. Managing source control and performing releases are definitely on that list.</p>
<p>I use Git as my DVCS of choice, and while it certainly makes managing source changes a bit more, well, manageable, it can also feel like the &#8220;wild wild west&#8221; at times with random branches and commits flying around.</p>
<p>Enter Git Flow. Git Flow makes managing features, releases, and bug fixes really simple and provides structure to the dev cycle. But there&#8217;s one problem: There&#8217;s no Java implementation, but let&#8217;s not get ahead of ourselves&#8230;</p>
<p>&nbsp;</p>
<h2>What Is Git Flow?</h2>
<p><img alt="" src="http://www.atlassian.com/git/workflows/pageSections/00/contentFullWidth/0/tabs/02/pageSections/06/contentFullWidth/0/content_files/file/git-workflow-release-cycle-2feature.png" /></p>
<p>Git Flow is a <a href="http://nvie.com/posts/a-successful-git-branching-model/">branching and merging model introduced by Vincent Driessen</a> that provides a little bit of structure to your development workflow.</p>
<p>At its core you have two &#8220;long running&#8221; branches:</p>
<ul>
<li>develop &#8211; this is where all changes are made (or eventually end up) while in active development.</li>
<li>master &#8211; no development work is done on master, but instead all changes are merged in from the develop branch.</li>
</ul>
<p>Along with the long running branches, you may have some other short-lived branches as well:</p>
<ul>
<li>feature/&lt;some feature&gt; &#8211; used to develop new features to be released at some point in the future.</li>
<li>release/&lt;some version&gt; &#8211; used to prepare for a new planned production release.</li>
<li>hotfix/&lt;some version&gt; &#8211; used to prepare for a new <em>un</em>planned production release specifically to fix up high priority issues.</li>
</ul>
<p>For more in-depth information about git flow and how git flow can help your business, <a href="http://www.atlassian.com/git/workflows#!workflow-gitflow">check out our git flow guide</a>.</p>
<h2>JGit Flow Java Library</h2>
<p>The JGit Flow Java Library is a general purpose library that implements git flow on top of <a href="http://eclipse.org/jgit/">JGit</a> and is licensed under <a href="http://www.apache.org/licenses/LICENSE-2.0.html">the Apache 2 License</a>.</p>
<p>Now some people may not like the command pattern that JGit uses for most of its functionality, but I don&#8217;t mind it and to keep things familiar and cohesive, JGit Flow uses the same pattern. That being said, we&#8217;ve added some abstractions to make it easy to interact with both JGit and JGit Flow instances.</p>
<p>So let&#8217;s get into some code already! Say you have a project that you want to git flow enable. It doesn&#8217;t even need to be a git project, just a regular project directory will do (or even an empty directory for that matter).</p>
<div class="codecolorer-container java mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">JGitFlow flow <span style="color: #339933;">=</span> JGitFlow.<span style="color: #006633;">getOrInit</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">File</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;/home/my-projects/example-gitflow-project&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #666666; font-style: italic;">//your local working copy is now on the develop branch</span></div></td></tr></tbody></table></div>
<p>That&#8217;s it. One line and you&#8217;ve set up git flow for your directory.</p>
<p>The <code class="codecolorer java mac-classic"><span class="java">getORInit</span></code> method essentially checks to see if the folder is already a git project, and if not, runs <em>git init</em>. After that, it checks to see if the directory is already a git flow project and if not, runs <code class="codecolorer java mac-classic"><span class="java">git flow init</span></code> with the default branch names/prefixes and finally returns a git flow instance.</p>
<p>To maintain compatibility with the command line git-flow, JGit Flow uses the same git config keys/values that the CLI uses. This means that you can switch between using JGit Flow and the git-flow CLI with no side effects.</p>
<p>If you need a more customizable approach, here are some other examples:</p>
<div class="codecolorer-container java mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">//create a flow instance with a few custom prefixes</span><br />
InitContext ctx <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> InitContext<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
ctx.<span style="color: #006633;">setMaster</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;GA&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">setHotfix</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;bugfix/&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">setVersiontag</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;rtags/&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
JGitFlow flow <span style="color: #339933;">=</span> JGitFlow.<span style="color: #006633;">getOrInit</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">File</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;/home/my-projects/example-gitflow-project&quot;</span><span style="color: #009900;">&#41;</span>, ctx<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">//initialize git flow or throw an error if it's already been initialized</span><br />
JGitFlow flow <span style="color: #339933;">=</span> JGitFlow.<span style="color: #006633;">init</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">File</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;/home/my-projects/example-gitflow-project&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">//initialize git flow with custom values that override the current values</span><br />
<span style="color: #666666; font-style: italic;">// in the case it's already been initialized</span><br />
InitContext ctx <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> InitContext<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
ctx.<span style="color: #006633;">setMaster</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;GA&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">setHotfix</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;bugfix/&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">setVersiontag</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;rtags/&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
JGitFlow flow <span style="color: #339933;">=</span> JGitFlow.<span style="color: #006633;">forceInit</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">File</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;/home/my-projects/example-gitflow-project&quot;</span><span style="color: #009900;">&#41;</span>, ctx<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
<p>Once you have a <code class="codecolorer java mac-classic"><span class="java">JGitFlow</span></code> instance, you can use the familiar JGit style command pattern on the instance to carry out git flow operations.</p>
<p>For instance, to start a release, you can do:</p>
<div class="codecolorer-container java mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">flow.<span style="color: #006633;">releaseStart</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;1.0&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">call</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">// Or if you need a reference to the newly created branch, you can get that too</span><br />
<span style="color: #003399;">Ref</span> newBranchRef <span style="color: #339933;">=</span> flow.<span style="color: #006633;">releaseStart</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;1.0&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">call</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">//Note: your local working copy is now on release/1.0</span></div></td></tr></tbody></table></div>
<p>All of this is well and good, but you&#8217;re probably going to need to mix JGitFlow commands with other JGit commands on the same repository. JGitFlow makes this easy by providing a reference to the Git instance created by JGit.</p>
<p>For instance, if you want to start a release, update a file with the release version and commit it and then finish the release, you could do:</p>
<div class="codecolorer-container java mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">//get a JGitFlow instance</span><br />
JGitFlow flow <span style="color: #339933;">=</span> JGitFlow.<span style="color: #006633;">getOrInit</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">File</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;/home/my-projects/example-gitflow-project&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">//start our release</span><br />
flow.<span style="color: #006633;">releaseStart</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;1.0&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">call</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #666666; font-style: italic;">//Note: your local working copy is now on release/1.0</span><br />
<span style="color: #666666; font-style: italic;">//update the version.txt file in the working tree</span><br />
<span style="color: #003399;">File</span> versionFile <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">File</span><span style="color: #009900;">&#40;</span>flow.<span style="color: #006633;">git</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getRepository</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">getWorkTree</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>, <span style="color: #0000ff;">&quot;version.txt&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
FileHelper.<span style="color: #006633;">writeStringToFile</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;1.0&quot;</span>, versionFile<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">//commit the change</span><br />
flow.<span style="color: #006633;">git</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">setUpdate</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">addFilepattern</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;version.txt&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">call</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
flow.<span style="color: #006633;">git</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">commit</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">setMessage</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;updating version file&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">call</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">//finish the release and push to origin</span><br />
flow.<span style="color: #006633;">releaseFinish</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;1.0&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">setPush</span><span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">call</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">//Note: your local working copy is now on develop</span></div></td></tr></tbody></table></div>
<h2>Why A Java Library?</h2>
<p>After using git flow for a while and becoming a convert, I found one big wrench in the process. That wrench is called the Maven release plugin.</p>
<p>With its checkouts, tagging, pom rewrites and extraneous release.properties and *.backup files mostly taking place within your working tree, the Maven release plugin doesn&#8217;t play well with git flow.</p>
<p>Now that doesn&#8217;t mean integrating Maven releases with git flow can&#8217;t be done, but it requires some special configuration, and you never quite get it to do exactly what you want.</p>
<p>The best you can do is to configure your pom.xml like this:</p>
<div class="codecolorer-container xml mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;build<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;plugins<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>org.apache.maven.plugins<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/groupId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>maven-release-plugin<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/artifactId<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #808080; font-style: italic;">&lt;!-- v 2.4 has a bug with localCheckout. will be fixed in 2.4.1 --&gt;</span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>2.3.2<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/version<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;configuration<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;autoVersionSubmodules<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>true<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/autoVersionSubmodules<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;goals<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>deploy<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/goals<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;pushChanges<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>false<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/pushChanges<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;localCheckout<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>true<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/localCheckout<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;tagNameFormat<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>mvn-@{project.version}<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/tagNameFormat<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/configuration<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/plugin<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/plugins<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/build<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
<p>Notice lines 11 through 13:</p>
<p><strong>11.</strong> tell Maven not to push rewritten POMs to the remote repo, git flow will do that</p>
<p><strong>12</strong>. tell Maven not to check out the project from the remote repo as we want to use our local changes</p>
<p><strong>13.</strong> give Maven some junk tag name so it doesn&#8217;t conflict with the git flow tagging</p>
<p>With this in place, doing a release is as &#8220;simple&#8221; as:</p>
<div class="codecolorer-container bash mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #c20cb9; font-weight: bold;">git</span> flow release start <span style="color: #000000;">1.0</span><br />
mvn release:prepare release:perform <span style="color: #660033;">-DreleaseVersion</span>=<span style="color: #000000;">1.0</span><br />
<span style="color: #c20cb9; font-weight: bold;">git tag</span> <span style="color: #660033;">-d</span> mvn-<span style="color: #000000;">1.0</span> <span style="color: #666666; font-style: italic;">#if you forget this, you'll get 2 tags in the remote repo</span><br />
<br />
<span style="color: #c20cb9; font-weight: bold;">git</span> flow release finish <span style="color: #660033;">-p</span> <span style="color: #000000;">1.0</span></div></td></tr></tbody></table></div>
<p>So after all is said and done, you&#8217;ll have created a new release branch, Maven will have:</p>
<ul>
<li>messed with your POMs</li>
<li>maybe committed a release.properties</li>
<li>run your build and your tests 2 times</li>
<li>created Java docs</li>
<li>created a Maven site (that you didn&#8217;t ask for)</li>
<li>and pushed your artifacts the the Maven repo</li>
</ul>
<p>then git flow merged your release into develop and master, created a tag, and then pushed master, develop and the tag to the remote repo, which now has 1.1-SNAPSHOT as the version in both master and develop.</p>
<p>While this works, there are some obvious flaws here. So I decided that using git flow in a Maven release process probably warrants a specific Maven gitflow-release plugin.</p>
<p>&#8220;Shouldn&#8217;t be too hard&#8221;, I thought. &#8220;I&#8217;ll just grab whatever java git flow library is out there and wrap a Maven plugin around it&#8221;.</p>
<p>To my surprise there was only <a href="https://github.com/lukepfarrar/jgitflow">one git flow java library that was started but never completed.</a></p>
<p>Clearly there are lots of developers using Maven that could probably take advantage of a git flow plugin, and surely lots of Java projects to benefit from adding git flow support, right?</p>
<p>And so was born the JGit Flow Java Library.</p>
<p><a href="https://bitbucket.org/atlassian/maven-jgitflow-plugin">curious about the maven plugin?</a></p>
<h2>When things go wrong</h2>
<p>The JGit Flow examples above seem pretty simple from an end user API perspective. However, JGit Flow has to do some complex things under the covers to ensure the proper state exists before carrying out the requested operation—things like making sure branches exist/don&#8217;t exist, ensuring that your local tree is not behind the remote repo, ensuring that remote branches exist, etc.</p>
<p>To enable you, as the integrator, to do something meaningful when good things go bad, JGit Flow provides a fine-grained set of exceptions that all inherit from a base exception. This allows you to catch very specific exceptions or just catch a single exception depending on what your code needs to do.</p>
<p>Taking the start release example from above, it could be re-written to catch specific exceptions</p>
<div class="codecolorer-container java mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br /></div></td><td><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">//Note: we catch what we want and throw any other JGitFlowException</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">boolean</span> doReleaseStart<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> JGitFlowException<br />
<span style="color: #009900;">&#123;</span><br />
<span style="color: #666666; font-style: italic;">//Initialize our project if needed</span><br />
JGitFlow flow <span style="color: #339933;">=</span> JGitFlow.<span style="color: #006633;">getOrInit</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">File</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;/home/my-projects/example-gitflow-project&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #666666; font-style: italic;">//try to start our release</span><br />
<span style="color: #000000; font-weight: bold;">try</span><br />
<span style="color: #009900;">&#123;</span><br />
flow.<span style="color: #006633;">releaseStart</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;1.0&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">call</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
wasReleased <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">true</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span>BranchExistsException e<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
<span style="color: #666666; font-style: italic;">//the release branch already exists, just check it out</span><br />
<span style="color: #000000; font-weight: bold;">try</span><br />
<span style="color: #009900;">&#123;</span><br />
flow.<span style="color: #006633;">git</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">checkout</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">setName</span><span style="color: #009900;">&#40;</span>flow.<span style="color: #006633;">getReleaseBranchPrefix</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot;1.0&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">call</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span>GitAPIException e1<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
log.<span style="color: #006633;">error</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Something went wrong checking out the release branch&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">return</span> wasReleased<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span>DirtyWorkingTreeException e<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
log.<span style="color: #006633;">error</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;you have un-committed changes!&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">return</span> wasReleased<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span>BranchOutOfDateException e<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
log.<span style="color: #006633;">error</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;your local develop branch is behind the remote, please do a git pull&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">return</span> wasReleased<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #666666; font-style: italic;">//all is good!</span><br />
<span style="color: #000000; font-weight: bold;">return</span> wasReleased<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<h2>Let the flow begin!</h2>
<p>Armed with this new library, hopes are that more and more Java projects will use it to integrate git flow into their apps. But don&#8217;t stop there! I believe this is just the tip of the iceberg and as JGit Flow gets adopted by more and more projects, I hope to see it evolve beyond the base git flow workflow.</p>
<p>Anything is possible and everything is up for grabs. If you find a bug or have a feature request, by all means add it to the <a href="https://bitbucket.org/atlassian/jgit-flow/issues">JGitFlow issue tracker. </a></p>
<p>If you&#8217;d like to contribute, please fork the <a href="https://bitbucket.org/atlassian/jgit-flow">JGit Flow project on Bitbucket</a>. When your super cool new feature is ready, just issue a pull request to the develop branch of the main project.</p>
<p>For more information and usage instructions, see the <a href="https://bitbucket.org/atlassian/jgit-flow/wiki">JGit Flow Wiki on Bitbucket</a>.</p>
<p>Enjoy!</p>
<p><a href="http://blogs.atlassian.com/2013/05/maven-git-flow-plugin-for-better-releases/">See my follow up blog post about the maven-jgitflow-plugin.</a></p>
 <img src="http://blogs.atlassian.com/?feed-stats-post-id=25109" width="1" height="1" style="display: none;" /><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?a=qusJ5WhwUYA:nYpeFX3iNn4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?a=qusJ5WhwUYA:nYpeFX3iNn4:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?i=qusJ5WhwUYA:nYpeFX3iNn4:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/AtlassianDeveloperBlog/~4/qusJ5WhwUYA" height="1" width="1"/>]]></content:encoded><description>As a Java developer, I&amp;#8217;m always trying to find ways to streamline all the mundane tasks that come along with development but aren&amp;#8217;t necessarily part of the actual code I&amp;#8217;m trying to write. Managing source control and performing releases are definitely on that list. I use Git as my DVCS of choice, and while it certainly makes managing source changes a bit more, well, manageable, it can also feel like the &amp;#8220;wild wild west&amp;#8221; at times with random branches and commits flying around. Enter Git Flow. Git Flow makes managing features, releases, and bug fixes really simple and provides structure to the dev cycle. But there&amp;#8217;s one problem: There&amp;#8217;s no Java implementation, but let&amp;#8217;s not get ahead of ourselves&amp;#8230; &amp;#160; What Is Git Flow? Git Flow is a branching and merging model introduced by Vincent Driessen that provides a little bit of structure to your development workflow. At its core you have two &amp;#8220;long running&amp;#8221; branches: develop &amp;#8211; this is where all changes are made (or eventually end up) while in active development. master &amp;#8211; no development work is done on master, but instead all changes are merged in from the develop branch. Along with the long running branches, you may have some other short-lived branches as well: feature/&amp;#60;some feature&amp;#62; &amp;#8211; used to develop new features to be released at some point in the future. release/&amp;#60;some version&amp;#62; &amp;#8211; used to prepare for a new planned production release. hotfix/&amp;#60;some version&amp;#62; &amp;#8211; used to prepare for a new unplanned production release specifically to fix up high priority issues. For more in-depth information about git flow and how git flow can help your business, check out our git flow guide. JGit Flow Java Library The JGit Flow Java Library is a general purpose library that implements git flow on top of JGit and is licensed under the Apache 2 License. Now some people may not like the command pattern that JGit uses for most of its functionality, but I don&amp;#8217;t mind it and to keep things familiar and cohesive, JGit Flow uses the same pattern. That being said, we&amp;#8217;ve added some abstractions to make it easy to interact with both JGit and JGit Flow instances. So let&amp;#8217;s get into some code already! Say you have a project that you want to git flow enable. It doesn&amp;#8217;t even need to be a git project, just a regular project directory will do (or even an empty directory for that matter). 12JGitFlow flow = JGitFlow.getOrInit&amp;#40;new File&amp;#40;&amp;#34;/home/my-projects/example-gitflow-project&amp;#34;&amp;#41;&amp;#41;; //your local working copy is now on the develop branch That&amp;#8217;s it. One line and you&amp;#8217;ve set up git flow for your directory. The getORInit method essentially checks to see if the folder is already a git project, and if not, runs git init. After that, it checks to see if the directory is already a git flow project and if not, runs git flow init with the default branch names/prefixes and finally returns a git flow instance. To maintain compatibility with the command line git-flow, JGit Flow uses the [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.atlassian.com/2013/04/git-flow-comes-to-java/feed/</wfw:commentRss><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">11</slash:comments><feedburner:origLink>http://blogs.atlassian.com/2013/04/git-flow-comes-to-java/</feedburner:origLink></item><item><title>The difference between bundledArtifacts and pluginArtifacts</title><link>http://feedproxy.google.com/~r/AtlassianDeveloperBlog/~3/yBDJO5IJaRY/</link><category>Developer</category><category>Plugins</category><category>JIRA plugin</category><category>maven</category><category>plugin development</category><category>sdk</category><category>testing</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Michael Tokar</dc:creator><pubDate>Wed, 17 Apr 2013 00:23:42 PDT</pubDate><guid isPermaLink="false">http://blogs.atlassian.com/?p=24283</guid><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<div id="main-content">
<div>
<p>Or &#8220;<em>I don&#8217;t have <strong>TIME</strong> to understand Maven; I&#8217;ve got work to do!</em>&#8221;</p>
<p>A big part of developing a plugin is seeing it work inside the base product. For JIRA plugins, this is accomplished using the <tt>maven-jira-plugin</tt>. There are two options for getting your plugin to run inside the host application: adding it as a <a href="https://developer.atlassian.com/display/DOCS/AMPS+Plugin+for+Maven#AMPSPluginforMaven-bundledArtifacts" rel="nofollow"><tt>bundledArtifact</tt></a>, or as a <a href="https://developer.atlassian.com/display/DOCS/AMPS+Plugin+for+Maven#AMPSPluginforMaven-pluginArtifacts" rel="nofollow"><tt>pluginArtifact</tt></a>. If you examine the configuration of an established plugin, like GreenHopper or any of JIRA&#8217;s bundled plugins, you might see multiple plugins configured, using either method. For example, making use of the <tt>jira-func-test-plugin</tt> or the <tt>jira-testkit-plugin</tt> to assist with writing integration tests, or the <tt>atlassian-qunit-plugin</tt> to run QUnit tests.</p>
<p>Why are there two ways? I always get confused by this, so I looked up the documentation. It quite clearly states:</p>
<blockquote>
<h4>pluginArtifacts</h4>
<p>Specifies other Atlassian plugins that your plugin depends on to work properly. These plugin artifacts will be installed into the product along with your plugin.</p>
<h4>bundledArtifacts</h4>
<p>Specifies other Atlassian plugins that your plugin depends on to work properly. These plugin artifacts will be treated as bundled by the product, meaning they can be disabled but not removed. The product will always make a bundled plugin available at startup, even if it was removed previously. By contrast, plugin artifacts can be removed after installation at any time, and they will stay gone until they are manually reinstalled.</p></blockquote>
<p>Ask yourself this question &#8212; is the plugin you are developing always going to be a bundled plugin i.e. not removable by administrators? If so, add it as a <tt>bundledArtifact</tt>. Simple.</p>
<p>But does it really make a difference? This configuration is purely for development purposes. What does it matter if your plugin is treated as bundled? As I found out today, it matters if you plan on doing any sort of integration testing around your plugin&#8217;s interactions with Atlassian&#8217;s Universal Plugin Manager (UPM).</p>
<p>I wrote a WebDriver test that re-used UPM&#8217;s PageObject library to drive licensing changes. In my development environment, everything was working just fine. But when the test ran in Bamboo, it failed. Initially, I thought the failure was due to a &#8220;flaky&#8221; PageObject. We call PageObjects &#8220;flaky&#8221; if they bind correctly to the DOM in a low-latency environment, like your workstation, but fail to bind due to timeouts or <tt>StaleElementException</tt>s in an environment where there is more latency, such as a <a href="http://quickstart.atlassian.com/download/bamboo/get-started/agents/" target="_blank">Remote Agent</a>. However, I realised that UPM&#8217;s PageObjects weren&#8217;t flaky. When I re-ran my test locally in the IDE, with the Slo-mo Filter enabled (which you can get by using the <tt>jira-func-test-plugin</tt>, by the way), it still passed.</p>
<p>The golden rule of test failure debugging is &#8220;try it from the command line&#8221;. We introduced a profile in our integration test POM that allows us to run a single test via <tt>mvn verify</tt>. So I ran the command and eagerly awaited the failure to appear before me. And sure enough, it did. The problem arose when my test attempted to &#8220;expand&#8221; the plugin&#8217;s details on the UPM page, to extract some license information. The PageObject couldn&#8217;t perform the task, because there was nothing to expand &#8211; the plugin was hidden away in the &#8220;System Plugins&#8221; section of the page.</p>
<p>Flipping back to the POM file for our integration test module, I quickly realised why this was the case – we had declared that the plugin should be installed as a <em>bundled</em> artifact instead of a <em>plugin</em> artifact. Moving the configuration across to the other XML block fixed the problem instantly. But it&#8217;s easy to see how we got in the predicament in the first place &#8211; both ways of installing a plugin were being used for different artifacts, and we probably just added it to the one that had more blocks in it.</p>
<p>Now, I will never forget the difference between the two. And hopefully, you won&#8217;t either!</p>
</div>
</div>
 <img src="http://blogs.atlassian.com/?feed-stats-post-id=24283" width="1" height="1" style="display: none;" /><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?a=yBDJO5IJaRY:xm-1pOWtn0U:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?a=yBDJO5IJaRY:xm-1pOWtn0U:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?i=yBDJO5IJaRY:xm-1pOWtn0U:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/AtlassianDeveloperBlog/~4/yBDJO5IJaRY" height="1" width="1"/>]]></content:encoded><description>Or &amp;#8220;I don&amp;#8217;t have TIME to understand Maven; I&amp;#8217;ve got work to do!&amp;#8221; A big part of developing a plugin is seeing it work inside the base product. For JIRA plugins, this is accomplished using the maven-jira-plugin. There are two options for getting your plugin to run inside the host application: adding it as a bundledArtifact, or as a pluginArtifact. If you examine the configuration of an established plugin, like GreenHopper or any of JIRA&amp;#8217;s bundled plugins, you might see multiple plugins configured, using either method. For example, making use of the jira-func-test-plugin or the jira-testkit-plugin to assist with writing integration tests, or the atlassian-qunit-plugin to run QUnit tests. Why are there two ways? I always get confused by this, so I looked up the documentation. It quite clearly states: pluginArtifacts Specifies other Atlassian plugins that your plugin depends on to work properly. These plugin artifacts will be installed into the product along with your plugin. bundledArtifacts Specifies other Atlassian plugins that your plugin depends on to work properly. These plugin artifacts will be treated as bundled by the product, meaning they can be disabled but not removed. The product will always make a bundled plugin available at startup, even if it was removed previously. By contrast, plugin artifacts can be removed after installation at any time, and they will stay gone until they are manually reinstalled. Ask yourself this question &amp;#8212; is the plugin you are developing always going to be a bundled plugin i.e. not removable by administrators? If so, add it as a bundledArtifact. Simple. But does it really make a difference? This configuration is purely for development purposes. What does it matter if your plugin is treated as bundled? As I found out today, it matters if you plan on doing any sort of integration testing around your plugin&amp;#8217;s interactions with Atlassian&amp;#8217;s Universal Plugin Manager (UPM). I wrote a WebDriver test that re-used UPM&amp;#8217;s PageObject library to drive licensing changes. In my development environment, everything was working just fine. But when the test ran in Bamboo, it failed. Initially, I thought the failure was due to a &amp;#8220;flaky&amp;#8221; PageObject. We call PageObjects &amp;#8220;flaky&amp;#8221; if they bind correctly to the DOM in a low-latency environment, like your workstation, but fail to bind due to timeouts or StaleElementExceptions in an environment where there is more latency, such as a Remote Agent. However, I realised that UPM&amp;#8217;s PageObjects weren&amp;#8217;t flaky. When I re-ran my test locally in the IDE, with the Slo-mo Filter enabled (which you can get by using the jira-func-test-plugin, by the way), it still passed. The golden rule of test failure debugging is &amp;#8220;try it from the command line&amp;#8221;. We introduced a profile in our integration test POM that allows us to run a single test via mvn verify. So I ran the command and eagerly awaited the failure to appear before me. And sure enough, it did. The problem arose when my test attempted to &amp;#8220;expand&amp;#8221; the plugin&amp;#8217;s details on the UPM page, to extract some license information. The PageObject couldn&amp;#8217;t perform the [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.atlassian.com/2013/04/the-difference-between-bundledartifacts-and-pluginartifacts/feed/</wfw:commentRss><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">0</slash:comments><feedburner:origLink>http://blogs.atlassian.com/2013/04/the-difference-between-bundledartifacts-and-pluginartifacts/</feedburner:origLink></item><item><title>Git Titanium Armor: Recovering From Various Disasters</title><link>http://feedproxy.google.com/~r/AtlassianDeveloperBlog/~3/vkqqRfJz2Ck/</link><category>Developer</category><category>DVCS</category><category>git</category><category>rebase</category><category>reflog</category><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Nicola Paolucci</dc:creator><pubDate>Mon, 15 Apr 2013 09:25:15 PDT</pubDate><guid isPermaLink="false">http://blogs.atlassian.com/?p=25011</guid><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<p><a href="http://git-scm.com">git</a> is an advanced tool. It features a philosophy that is dear to my heart: to treat developers as smart and responsible folks. This means that a lot of power is at your fingertips. The power to also shoot yourself in the foot &#8211; arguably with a titanium vest on &#8211; but shoot yourself nonetheless.</p>
<p>The topic of this post is to confirm what my colleague <a href="https://twitter.com/charlesofarrell">Charles O&#8217;Farrell</a> said very well in the ever popular &#8220;<a href="http://blogs.atlassian.com/2012/03/git-vs-mercurial-why-git/">Why Git?</a>&#8221; article some time ago:</p>
<blockquote><p>[...] Git is actually the safest of all the DVCS options. As we saw above,<br />
Git never actually lets you change anything, it just creates new objects.</p>
<p>[...] Git actually keeps track of every change you make, storing them in<br />
the reflog. Because every commit is unique and immutable, all the reflog has<br />
to do is store a reference to them.</p></blockquote>
<p>This means you&#8217;re safe from harm and your code is always preserved, but there are situations where you might need some conjuring to get it back.</p>
<p>Let me give you a few real world examples of how to recover from trouble, going from simple to advanced:</p>
<h2>Table Of Contents</h2>
<ol>
<li><a href="#tip1">How To Undo A (Soft) Reset And Recover A Deleted File</a></li>
<li><a href="#tip2">If You Lose A Commit During An Interactive Rebase</a></li>
<li><a href="#tip3">How To Undo <span class="text codecolorer">reset &#8211;hard</span> If You Only Staged Your Changes</a></li>
</ol>
<h2 id="tip1">How To Undo A (Soft) Reset And Recover A Deleted File</h2>
<p>If you delete a file with <span class="text codecolorer">git rm </span> and immediately after you <a href="http://www.atlassian.com/git/tutorial/undoing-changes#!reset"><span class="text codecolorer">git reset</span></a> your working directory (which is called a <em>soft</em> reset), you will find yourself with a missing file and a dirty working directory like the following:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"># On branch master<br />
# Changes not staged for commit:<br />
# &nbsp; (use &quot;git add/rm file...&quot; to update what will be committed)<br />
# &nbsp; (use &quot;git checkout -- file...&quot; to discard changes in working directory)<br />
#<br />
# &nbsp; deleted: &nbsp; &nbsp;test.txt<br />
#</div></td></tr></tbody></table></div>

</pre>
<p>There are a couple of simple ways to go about restoring the file. One is to use a <span class="text codecolorer">git reset &#8211;hard</span> which will recreate the missing files but it will <em>delete any local modifications you might have in your working directory</em>.</p>
<p>The second is to just re-check out the file yourself with <span class="text codecolorer">git checkout test.txt</span>.</p>
<p>In a slightly different scenario, if the file was removed in an earlier commit, you can recover it by noting down the exact commit where the file was deleted and use the reference to pick the commit immediately before:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">git checkout commit_id~ -- test.txt</div></td></tr></tbody></table></div>

</pre>
<p>Where the <span class="text codecolorer">~</span> (tilde) sign means <span class="text codecolorer">the one before this one</span>.</p>
<h2 id="tip2">If You Lose A Commit During An Interactive Rebase</h2>
<p><a href="http://git-scm.com/book/en/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages">Interactive rebase</a> is one of the most useful tools in the git arsenal; It allows to edit, squash and delete commits interactively.</p>
<p>Personally, I love to clean and streamline commits before sharing them with others. It&#8217;s nice when each commit is an understandable and logical chunk of work. In the heat of development, or in a local private branch, I might commit furiously for a bit, then when I am satisfied I spend time cleaning up the history.</p>
<p>But what if while in the interactive rebase session you accidentally remove a commit line without realizing it and save?</p>
<p>This situation is slightly annoying cause you have just removed a commit from your history!</p>
<p>If you created a throwaway branch before starting the <span class="text codecolorer">rebase</span> &#8211; which you should always do &#8211; you&#8217;re fine and you can restart the process all over. But what if you didn&#8217;t?</p>
<p>No worries, <span class="text codecolorer">git</span> has got you covered. Nothing is ever lost. This is a good opportunity to use the <a href="http://www.atlassian.com/git/tutorial/rewriting-git-history#!reflog">reflog</a>, which is an automatic mechanism recording where the tip of all branches has been for the past 30 days.</p>
<p>Say at the start of the <span class="text codecolorer">rebase</span> I had 4 commits like the following:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ git log<br />
cfdf880 [2 seconds ago] (HEAD, master) wrote fifth change<br />
ab446e6 [34 seconds ago] changed one line<br />
6e1a130 [25 minutes ago] third change<br />
6566977 [26 minutes ago] second change<br />
5feeb33 [26 minutes ago] initial commit</div></td></tr></tbody></table></div>

</pre>
<p>I <span class="text codecolorer">rebase</span> the last 4 commits and accidentally remove one line:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ git rebase -i HEAD~4</div></td></tr></tbody></table></div>

</pre>
<p>Editor opens on:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">pick 6566977 second change<br />
pick 6e1a130 third change<br />
pick ab446e6 changed one line<br />
pick cfdf880 wrote fifth change<br />
<br />
# Rebase 5feeb33..cfdf880 onto 5feeb33<br />
#<br />
# Commands:<br />
# &nbsp;p, pick = use commit<br />
# &nbsp;r, reword = use commit, but edit the commit message<br />
# &nbsp;e, edit = use commit, but stop for amending<br />
# &nbsp;s, squash = use commit, but meld into previous commit<br />
# &nbsp;f, fixup = like &quot;squash&quot;, but discard this commit's log message<br />
# &nbsp;x, exec = run command (the rest of the line) using shell<br />
#<br />
# These lines can be re-ordered; they are executed from top to bottom.<br />
#<br />
# If you remove a line here THAT COMMIT WILL BE LOST.<br />
#<br />
# However, if you remove everything, the rebase will be aborted.<br />
#<br />
# Note that empty commits are commented out</div></td></tr></tbody></table></div>

</pre>
<p>I removed one commit line (<span class="text codecolorer">pick ab446e6 changed one line</span>), I saved and got this:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Successfully rebased and updated refs/heads/master.</div></td></tr></tbody></table></div>

</pre>
<p>Now, if I check the list of commits I see I lost one:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ git log<br />
3dd6845 [6 minutes ago] (HEAD, master) wrote fifth change<br />
6e1a130 [32 minutes ago] third change<br />
6566977 [32 minutes ago] second change<br />
5feeb33 [32 minutes ago] initial commit</div></td></tr></tbody></table></div>

</pre>
<p>But the <span class="text codecolorer">reflog</span> has our lost commit:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ git reflog<br />
3dd6845 HEAD@{0}: rebase -i (finish): returning to refs/heads/master<br />
3dd6845 HEAD@{1}: rebase -i (pick): wrote fifth change<br />
6e1a130 HEAD@{2}: checkout: moving from master to 6e1a130<br />
cfdf880 HEAD@{3}: commit: wrote fifth change<br />
----}} ab446e6 HEAD@{4}: commit: changed one line<br />
[...]</div></td></tr></tbody></table></div>

</pre>
<p>Here <span class="text codecolorer">ab446e6</span> is the <span class="text codecolorer">sha-1</span> for the commit we lost. Armed with this id we can just <span class="text codecolorer">cherry-pick</span> it back in the code:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ git cherry-pick ab446e6<br />
[master 032c6a6] changed one line<br />
1 file changed, 1 insertion(+), 1 deletion(-)</div></td></tr></tbody></table></div>

</pre>
<p>And as you can see the commit is now back in our history:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">$ git log<br />
032c6a6 [12 minutes ago] (HEAD, master) changed one line<br />
3dd6845 [12 minutes ago] wrote fifth change<br />
6e1a130 [37 minutes ago] third change<br />
6566977 [38 minutes ago] second change<br />
5feeb33 [38 minutes ago] initial commit</div></td></tr></tbody></table></div>

</pre>
<h2 id="tip3">How To Undo <span class="text codecolorer">reset &#8211;hard</span> If You Only Staged Your Changes</h2>
<p>I&#8217;ll save you the speech to commit frequently &#8211; whether in a private short lived branch or a shared one &#8211; to protect you from heaps of problems.</p>
<p>But let&#8217;s say you didn&#8217;t commit this time and you find yourself in the following scenario: you&#8217;ve done some work, haven&#8217;t committed it yet but have <span class="text codecolorer">git add</span>ed it to the staging area.</p>
<p>Then tragedy strikes: you type <span class="text codecolorer">git reset &#8211;hard</span> and immediately realize that <em>you&#8217;ve zeroed your local changes(!!)</em> and brought back (in it&#8217;s entirety) the previous commit.</p>
<p>This is a tough situation to be in. How do you recover your work? Is it even possible? The answer is <em>yes</em>! The solution involves some low level searching and can be approached in a couple of ways.</p>
<p>Since <span class="text codecolorer">git</span> creates new objects in the <span class="text codecolorer">.git/objects</span> folder as soon as something is added to the staging area we can look there for the most recently created objects:</p>
<p>In OSX (and BSD systems) you can do:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">find .git/objects/ -type f | xargs stat -f &quot;%Sm %N&quot; | sort | tail -5</div></td></tr></tbody></table></div>

</pre>
<p>On Linux(with GNU tools) this should work:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">find .git/objects/ -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort | tail -5</div></td></tr></tbody></table></div>

</pre>
<p>With <span class="text codecolorer">tail -n</span> you can cut to the last <span class="text codecolorer">n</span> results if your repository is very big:</p>
<p>The result should be something like:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Apr &nbsp;2 12:26:33 2013 .git/objects//pack/pack-4cf657357973915f6fb6f90a41f69a88c0b08bb7.pack<br />
Apr &nbsp;2 12:29:56 2013 .git/objects//3d/d6845a69cd59dac0851e1ae0bd69dde950c46b<br />
Apr &nbsp;2 12:29:56 2013 .git/objects//68/c983f0cefb4bee2f753516ab6352ee2f2b7d29<br />
Apr &nbsp;2 12:35:23 2013 .git/objects//03/2c6a653cc00c302020293e020d8d68326b112e<br />
Apr &nbsp;2 15:34:55 2013 .git/objects//df/485610889e98ff773b4440a032ea2ede1338b9</div></td></tr></tbody></table></div>

</pre>
<p>In my case my sample file was lost exactly around <span class="text codecolorer">15:34</span> so I can inspect and retrieve it with:</p>
<pre>

<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">git show df485610889e98ff773b4440a032ea2ede1338b9</div></td></tr></tbody></table></div>

</pre>
<p>Remember that the folder is part of the <span class="text codecolorer">sha-1</span> reference, so remove the <span class="text codecolorer">/</span> slash to compute the correct id.</p>
<p>Note that <span class="text codecolorer">git</span> has specific low level command to explore dangling objects and to verify their connectivity: <a href="https://www.kernel.org/pub/software/scm/git/docs/git-fsck.html">git fsck</a>. For an alternative solution to this problem using <span class="text codecolorer">fsck</span>, check out this very cool <a href="http://stackoverflow.com/questions/7374069/undo-git-reset-hard/7376959#7376959">answer on Stack Overflow</a>.</p>
<h2>Conclusions</h2>
<p>There are many more examples and scenarios to cover on this topic so I might come back later with more interesting cases.</p>
<p>One thing to take away from this should be the feeling that it&#8217;s very very hard to screw up and lose your data when using <span class="text codecolorer">git</span>. That&#8217;s all for now!</p>
<p>Follow the awesome <a href="http://twitter.com/AtlDevTools">@AtlDevtools</a> team or me <a href="http://twitter.com/durdn">@durdn</a> for more Git rocking.</p>
 <img src="http://blogs.atlassian.com/?feed-stats-post-id=25011" width="1" height="1" style="display: none;" /><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?a=vkqqRfJz2Ck:ESVYst3HY2Q:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?a=vkqqRfJz2Ck:ESVYst3HY2Q:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/AtlassianDeveloperBlog?i=vkqqRfJz2Ck:ESVYst3HY2Q:V_sGLiPBpWU" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/AtlassianDeveloperBlog/~4/vkqqRfJz2Ck" height="1" width="1"/>]]></content:encoded><description>git is an advanced tool. It features a philosophy that is dear to my heart: to treat developers as smart and responsible folks. This means that a lot of power is at your fingertips. The power to also shoot yourself in the foot &amp;#8211; arguably with a titanium vest on &amp;#8211; but shoot yourself nonetheless. The topic of this post is to confirm what my colleague Charles O&amp;#8217;Farrell said very well in the ever popular &amp;#8220;Why Git?&amp;#8221; article some time ago: [...] Git is actually the safest of all the DVCS options. As we saw above, Git never actually lets you change anything, it just creates new objects. [...] Git actually keeps track of every change you make, storing them in the reflog. Because every commit is unique and immutable, all the reflog has to do is store a reference to them. This means you&amp;#8217;re safe from harm and your code is always preserved, but there are situations where you might need some conjuring to get it back. Let me give you a few real world examples of how to recover from trouble, going from simple to advanced: Table Of Contents How To Undo A (Soft) Reset And Recover A Deleted File If You Lose A Commit During An Interactive Rebase How To Undo reset &amp;#8211;hard If You Only Staged Your Changes How To Undo A (Soft) Reset And Recover A Deleted File If you delete a file with git rm and immediately after you git reset your working directory (which is called a soft reset), you will find yourself with a missing file and a dirty working directory like the following: 1234567# On branch master # Changes not staged for commit: # &amp;#160; (use &amp;#34;git add/rm file...&amp;#34; to update what will be committed) # &amp;#160; (use &amp;#34;git checkout -- file...&amp;#34; to discard changes in working directory) # # &amp;#160; deleted: &amp;#160; &amp;#160;test.txt # There are a couple of simple ways to go about restoring the file. One is to use a git reset &amp;#8211;hard which will recreate the missing files but it will delete any local modifications you might have in your working directory. The second is to just re-check out the file yourself with git checkout test.txt. In a slightly different scenario, if the file was removed in an earlier commit, you can recover it by noting down the exact commit where the file was deleted and use the reference to pick the commit immediately before: 1git checkout commit_id~ -- test.txt Where the ~ (tilde) sign means the one before this one. If You Lose A Commit During An Interactive Rebase Interactive rebase is one of the most useful tools in the git arsenal; It allows to edit, squash and delete commits interactively. Personally, I love to clean and streamline commits before sharing them with others. It&amp;#8217;s nice when each commit is an understandable and logical chunk of work. In the heat of development, or in a local private branch, I might commit furiously for a bit, then [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.atlassian.com/2013/04/git-titanium-armor-recovering-from-various-disasters/feed/</wfw:commentRss><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">5</slash:comments><feedburner:origLink>http://blogs.atlassian.com/2013/04/git-titanium-armor-recovering-from-various-disasters/</feedburner:origLink></item></channel></rss>
