scratch/output/Scratch/fr/blog/2010-03-23-Encapsulate-git/index.html
Yann Esposito (Yogsototh) 219937b6c9 Regen
2012-01-18 14:28:01 +01:00

339 lines
No EOL
23 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="fr" xml:lang="fr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="keywords" content="git, protection, branches">
<link rel="shortcut icon" type="image/x-icon" href="/Scratch/img/favicon.ico" />
<link rel="stylesheet" type="text/css" href="/Scratch/assets/css/main.css" />
<link rel="stylesheet" type="text/css" href="/Scratch/css/twilight.css" />
<link rel="stylesheet" type="text/css" href="/Scratch/css/idc.css" />
<link rel="alternate" type="application/rss+xml" title="RSS" href="http://feeds.feedburner.com/yannespositocomfr"/>
<link rel="alternate" lang="fr" xml:lang="fr" title="Encapsuler git" type="text/html" hreflang="fr" href="/Scratch/fr/blog/2010-03-23-Encapsulate-git/" />
<link rel="alternate" lang="en" xml:lang="en" title="Encapsulate git" type="text/html" hreflang="en" href="/Scratch/en/blog/2010-03-23-Encapsulate-git/" />
<script type="text/javascript" src="/Scratch/js/jquery-1.3.1.min.js"></script>
<script type="text/javascript" src="/Scratch/js/jquery.cookie.js"></script>
<script type="text/javascript" src="/Scratch/js/index.js"></script>
<!--[if lt IE 9]>
<script src="http://ie7-js.googlecode.com/svn/version/2.1(beta4)/IE9.js"></script>
<![endif]-->
<title>Encapsuler git</title>
</head>
<body lang="fr" class="article">
<script type="text/javascript">// <![CDATA[
document.write('<div id="blackpage"><img src="/Scratch/img/loading.gif" alt="Chargement en cours..."/></div>');
// ]]>
</script>
<div id="content">
<div id="choix">
<div class="return"><a href="#entete">&darr; Menu &darr;</a></div>
<div id="choixlang">
<a href="/Scratch/en/blog/2010-03-23-Encapsulate-git/" onclick="setLanguage('en')">in English</a>
</div>
<div class="flush"></div>
</div>
<div id="titre">
<h1>
Encapsuler git
</h1>
</div>
<div class="flush"></div>
<div class="flush"></div>
<div id="afterheader">
<div class="corps">
<p><span class="intro">
Voici une solution pour conserver des branches divergentes avec <code>git</code>.
Parce quil est facile de <em>merger</em> par erreur, je propose un script qui encapsule le comportement de <code>git</code> pour interdire certains <em>merges</em> dangereux. Mais qui permet aussi de faire des merges en cascades de la racines vers les autres branches.
</span></p>
<h2 id="se-prmunir-contre-les-erreurs">Se prémunir contre les erreurs</h2>
<p>Je travaille sur un projet dans lequel certaines de mes branches <code>git</code> doivent rester divergentes. Et les divergences devraient aller en saccentuant.</p>
<p>Jutilise aussi certaines branches qui contiennent la partie commune de ces projets.</p>
<p>Disons que jai les branches&nbsp;:</p>
<ul>
<li>master: commune à toutes les branches</li>
<li>dev: branche instable pour le développement</li>
<li>client: Branche commune à plusieurs clients</li>
<li>clientA: le projet spécialisé pour le client A</li>
<li>clientB: le projet spécialisé pour le client B</li>
</ul>
<p>Voilà comment je souhaiterai que ça fonctionne</p>
<p><img alt="Dynamic branching" src="/Scratch/img/blog/2010-03-23-Encapsulate-git/dynamic_branching.png" /></p>
<p>Et plus précisément la hiérarchie des branches&nbsp;:</p>
<p><img alt="Branch hierarchy" src="/Scratch/img/blog/2010-03-23-Encapsulate-git/branch_hierarchy.png" /></p>
<p>Une flèche de A vers B signifie que lon peut merger A dans B. Sil ny a pas de flèche de A vers B cela signifie quil est <em>interdit</em> de merger A dans B. Voici le code ruby correspondant&nbsp;:</p>
<div><pre class="twilight">
<span class="Variable"><span class="Variable">$</span>architecture</span><span class="Keyword">=</span>{
<span class="Constant"><span class="Constant">:</span>master</span> =&gt; [ <span class="Constant"><span class="Constant">:</span>dev</span>, <span class="Constant"><span class="Constant">:</span>client</span> ],
<span class="Constant"><span class="Constant">:</span>dev</span> =&gt; [ <span class="Constant"><span class="Constant">:</span>master</span> ],
<span class="Constant"><span class="Constant">:</span>client</span> =&gt; [ <span class="Constant"><span class="Constant">:</span>clientA</span>, <span class="Constant"><span class="Constant">:</span>clientB</span> ] }
</pre></div>
<p><code>:master =&gt; [ :dev, :client ]</code> signifie que lon peut merger la branche <code>master</code> dans la branche <code>dev</code> et la branche <code>client</code>.</p>
<p>Je fait une erreur si je tape <code>git checkout master &amp;&amp; git merge clientA</code>.
Cest pour éviter ça que jai fait un script pour encapsuler le comportement de <code>git</code>.</p>
<p>Mais ce script fait bien plus que ça. Il fait des merges en cascade de la racine vers les feuilles avec lacion <code>allmerges</code>.</p>
<div><pre class="twilight">
git co dev <span class="Keyword">&amp;&amp;</span> git merge master
git co client <span class="Keyword">&amp;&amp;</span> git merge master
git co clientA <span class="Keyword">&amp;&amp;</span> git merge client
git co clientB <span class="Keyword">&amp;&amp;</span> git merge client
</pre></div>
<p>Je peux ainsi mettre à jour toutes les branches. Lalgorithme ne boucle pas même sil y a des cycles dans la structure des branches.<br />
Le voici&nbsp;:</p>
<div class="small"><div class="code"><div class="file"><a href="/Scratch/fr/blog/2010-03-23-Encapsulate-git/code/eng"> &#x27A5; eng </a></div><div class="withfile">
<pre class="twilight">
<span class="Comment"><span class="Comment">#</span>!/usr/bin/env ruby</span>
<span class="Comment"><span class="Comment">#</span> encoding: utf-8</span>
<span class="Comment"><span class="Comment">#</span> architecture</span>
<span class="Comment"><span class="Comment">#</span></span>
<span class="Comment"><span class="Comment">#</span> master &lt;-&gt; dev</span>
<span class="Comment"><span class="Comment">#</span> master -&gt; client</span>
<span class="Comment"><span class="Comment">#</span> clien -&gt; clientA | clientB</span>
<span class="Comment"><span class="Comment">#</span></span>
<span class="Comment"><span class="Comment">#</span> merge using two of these branches should be </span>
<span class="Comment"><span class="Comment">#</span> restricted to these rules</span>
<span class="Comment"><span class="Comment">#</span> merge to one of these branch and an unknown one should</span>
<span class="Comment"><span class="Comment">#</span> raise a warning, and may the option to add this new branch</span>
<span class="Comment"><span class="Comment">#</span> to the hierarchy</span>
<span class="Variable"><span class="Variable">$</span>architecture</span><span class="Keyword">=</span>{
<span class="Constant"><span class="Constant">:</span>master</span> =&gt; [ <span class="Constant"><span class="Constant">:</span>dev</span>, <span class="Constant"><span class="Constant">:</span>client</span> ],
<span class="Constant"><span class="Constant">:</span>dev</span> =&gt; [ <span class="Constant"><span class="Constant">:</span>master</span> ],
<span class="Constant"><span class="Constant">:</span>client</span> =&gt; [ <span class="Constant"><span class="Constant">:</span>clientA</span>, <span class="Constant"><span class="Constant">:</span>clientB</span> ] }
<span class="Keyword">def</span> <span class="Entity">get_current_branch</span>(<span class="Variable" />)
(<span class="String"><span class="String">`</span>git branch --no-color | awk '$1 == &quot;*&quot; {print $2}'<span class="String">`</span></span>).<span class="Entity">chop</span>.<span class="Entity">intern</span>
<span class="Keyword">end</span>
<span class="Keyword">if</span> <span class="Variable">ARGV</span>.<span class="Entity">length</span> <span class="Keyword">==</span> <span class="Constant">0</span>
puts <span class="String"><span class="String">%{</span>usage: $0:t [git_command or local_command]</span>
<span class="String"> </span>
<span class="String">local commands:</span>
<span class="String"> allmerges: merge from top to down<span class="String">}</span></span>
exit <span class="Constant">0</span>
<span class="Keyword">end</span>
<span class="Keyword">require</span> <span class="String"><span class="String">'</span>set<span class="String">'</span></span>
<span class="Variable"><span class="Variable">$</span>known_branches</span><span class="Keyword">=</span><span class="Support">Set</span>.<span class="Entity">new</span>
<span class="Variable"><span class="Variable">$</span>architecture</span>.<span class="Entity">each</span> <span class="Keyword">do </span>|<span class="Variable">k</span>,<span class="Variable">v</span>|
<span class="Variable"><span class="Variable">$</span>known_branches</span>.<span class="Entity">add</span>(k)
v.<span class="Entity">each</span> { |<span class="Variable">b</span>| <span class="Variable"><span class="Variable">$</span>known_branches</span>.<span class="Entity">add</span>(b) }
<span class="Keyword">end</span>
<span class="Keyword">def</span> <span class="Entity">rec_merge</span>(<span class="Variable">branch</span>)
<span class="Keyword">if</span> <span class="Variable"><span class="Variable">$</span>architecture</span>[branch].<span class="Entity">nil?</span>
<span class="Keyword">return</span>
<span class="Keyword">end</span>
<span class="Variable"><span class="Variable">$</span>architecture</span>[branch].<span class="Entity">each</span> <span class="Keyword">do </span>|<span class="Variable">b</span>|
<span class="Keyword">if</span> <span class="Variable"><span class="Variable">$</span>flag</span>.<span class="Entity">has_key?</span>(b.<span class="Entity">to_s</span> <span class="Keyword">+</span> branch.<span class="Entity">to_s</span>)
<span class="Keyword">next</span>
<span class="Keyword">end</span>
flagname<span class="Keyword">=</span>branch.<span class="Entity">to_s</span> <span class="Keyword">+</span> b.<span class="Entity">to_s</span>
<span class="Keyword">if</span> <span class="Variable"><span class="Variable">$</span>flag</span>.<span class="Entity">has_key?</span>(flagname)
<span class="Keyword">next</span>
<span class="Keyword">end</span>
<span class="Keyword">if</span> system <span class="String"><span class="String">%{</span>eng checkout <span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span>b<span class="StringEmbeddedSource">}</span></span><span class="String">}</span></span>
<span class="Keyword">if</span> get_current_branch <span class="Keyword">!=</span> b
puts <span class="String"><span class="String">&quot;</span>Can't checkout to <span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span>b<span class="StringEmbeddedSource">}</span></span><span class="String">&quot;</span></span>
exit <span class="Constant">2</span>
<span class="Keyword">end</span>
<span class="Keyword">if</span> system <span class="String"><span class="String">%{</span>eng merge <span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span>branch<span class="StringEmbeddedSource">}</span></span><span class="String">}</span></span>
<span class="Variable"><span class="Variable">$</span>flag</span>[flagname]<span class="Keyword">=</span><span class="Constant">true</span>
<span class="Entity">rec_merge</span>(b)
<span class="Keyword">else</span>
exit <span class="Constant">1</span>
<span class="Keyword">end</span>
<span class="Keyword">else</span>
exit <span class="Constant">1</span>
<span class="Keyword">end</span>
<span class="Keyword">end</span>
<span class="Keyword">end</span>
<span class="Keyword">def</span> <span class="Entity">do_all_merges</span>
puts <span class="String"><span class="String">'</span>Will merge from father to sons<span class="String">'</span></span>
current_branch<span class="Keyword">=</span>get_current_branch
<span class="Variable"><span class="Variable">$</span>flag</span><span class="Keyword">=</span>{}
<span class="Entity">rec_merge</span>(<span class="Constant"><span class="Constant">:</span>master</span>)
system <span class="String"><span class="String">%{</span>git co <span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span>current_branch<span class="StringEmbeddedSource">}</span></span><span class="String">}</span></span>
<span class="Keyword">end</span>
<span class="Keyword">def</span> <span class="Entity">do_merge</span>
current_branch<span class="Keyword">=</span>get_current_branch
src_branch<span class="Keyword">=</span><span class="Variable">ARGV</span>[<span class="Constant">1</span>].<span class="Entity">intern</span>
puts <span class="String"><span class="String">%{</span>do_merge: <span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span>src_branch<span class="StringEmbeddedSource">}</span></span> =&gt; <span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span>current_branch<span class="StringEmbeddedSource">}</span></span><span class="String">}</span></span>
<span class="Keyword">if</span> <span class="Variable"><span class="Variable">$</span>known_branches</span>.<span class="Entity">include?</span>(current_branch)
<span class="Keyword">if</span> <span class="Variable"><span class="Variable">$</span>known_branches</span>.<span class="Entity">include?</span>(src_branch)
<span class="Keyword">if</span> <span class="Variable"><span class="Variable">$</span>architecture</span>.<span class="Entity">has_key?</span>(src_branch) <span class="Keyword">and</span>
<span class="Variable"><span class="Variable">$</span>architecture</span>[src_branch].<span class="Entity">include?</span>(current_branch)
system <span class="String"><span class="String">%{</span>git merge <span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span>src_branch<span class="StringEmbeddedSource">}</span></span><span class="String">}</span></span>
<span class="Keyword">else</span>
puts <span class="String"><span class="String">%{</span>Forbidden merge: <span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span>src_branch<span class="StringEmbeddedSource">}</span></span> =&gt; <span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span>current_branch<span class="StringEmbeddedSource">}</span></span><span class="String">}</span></span>
<span class="Keyword">end</span>
<span class="Keyword">else</span>
puts <span class="String"><span class="String">%{</span>Warning! <span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span>src_branch<span class="StringEmbeddedSource">}</span></span> not mentionned in rb configuration<span class="String">}</span></span>
sleep <span class="Constant">2</span>
f system <span class="String"><span class="String">%{</span>git merge <span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span>src_branch<span class="StringEmbeddedSource">}</span></span><span class="String">}</span></span>
puts <span class="String"><span class="String">%{</span>Warning! <span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span>src_branch<span class="StringEmbeddedSource">}</span></span> not mentionned in rb configuration<span class="String">}</span></span>
<span class="Keyword">end</span>
<span class="Keyword">end</span>
<span class="Keyword">end</span>
<span class="Keyword">case</span> <span class="Variable">ARGV</span>[<span class="Constant">0</span>]
<span class="Keyword">when</span> <span class="String"><span class="String">'</span>allmerges<span class="String">'</span></span> <span class="Keyword">then</span> do_all_merges
<span class="Keyword">when</span> <span class="String"><span class="String">'</span>merge<span class="String">'</span></span> <span class="Keyword">then</span> do_merge
<span class="Keyword">else</span> system <span class="String"><span class="String">%{</span>git <span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span><span class="StringVariable">ARGV</span><span class="StringEmbeddedSource"><span class="StringEmbeddedSource">.</span><span class="Entity">join</span></span><span class="StringEmbeddedSource">(</span><span class="String"><span class="String">'</span> <span class="String">'</span></span><span class="StringEmbeddedSource">)</span><span class="StringEmbeddedSource">}</span></span><span class="String">}</span></span>
<span class="Keyword">end</span>
</pre>
</div></div></div>
<p>Pour que ça fonctionne il vous suffit de copier <code>eng</code> dans un répertoire présent dans votre <code>PATH</code>.</p>
<p>Bien entendu, il faut essayer de faire aussi peu que possible des <code>cherry-pick</code> et des <code>rebase</code>. Ce script a pour but de sintégrer avec les workflow basé sur les <code>pull</code> et <code>merge</code>.</p>
</div>
<div id="choixrss">
<a id="rss" href="http://feeds.feedburner.com/yannespositocomfr">
s'abonner
</a>
</div>
<script type="text/javascript">
$(document).ready(function(){
$('#comment').hide();
$('#clickcomment').click(showComments);
});
function showComments() {
$('#comment').show();
$('#clickcomment').fadeOut();
}
document.write('<div id="clickcomment">Commentaires</div>');
</script>
<div class="flush"></div>
<div class="corps" id="comment">
<h2 class="first">commentaires</h2>
<noscript>
Vous devez activer javascript pour commenter.
</noscript>
<script type="text/javascript">
var idcomments_acct = 'a307f0044511ff1b5cfca573fc0a52e7';
var idcomments_post_id = '/Scratch/fr/blog/2010-03-23-Encapsulate-git/';
var idcomments_post_url = 'http://yannesposito.com/Scratch/fr/blog/2010-03-23-Encapsulate-git/';
</script>
<span id="IDCommentsPostTitle" style="display:none"></span>
<script type='text/javascript' src='/Scratch/js/genericCommentWrapperV2.js'></script>
</div>
<div id="entete" class="corps_spaced">
<div id="liens">
<ul><li><a href="/Scratch/fr/">Bienvenue</a></li>
<li><a href="/Scratch/fr/blog/">Blog</a></li>
<li><a href="/Scratch/fr/softwares/">Softwares</a></li>
<li><a href="/Scratch/fr/about/">À propos</a></li></ul>
</div>
<div class="flush"></div>
<hr/>
<div id="next_before_articles">
<div id="previous_articles">
articles précédents
<div class="previous_article">
<a href="/Scratch/fr/blog/2010-03-22-Git-Tips/"><span class="nicer">«</span>&nbsp;Astuces Git</a>
</div>
<div class="previous_article">
<a href="/Scratch/fr/blog/2010-02-23-When-regexp-is-not-the-best-solution/"><span class="nicer">«</span>&nbsp;Quand se passer des expressions régulières ?</a>
</div>
<div class="previous_article">
<a href="/Scratch/fr/blog/2010-02-18-split-a-file-by-keyword/"><span class="nicer">«</span>&nbsp;découper un fichier par mots clés</a>
</div>
</div>
<div id="next_articles">
articles suivants
<div class="next_article">
<a href="/Scratch/fr/blog/2010-05-17-at-least-this-blog-revive/">Je reviens à la vie !&nbsp;<span class="nicer">»</span></a>
</div>
<div class="next_article">
<a href="/Scratch/fr/blog/2010-05-19-How-to-cut-HTML-and-repair-it/">Comment réparer un XML coupé ?&nbsp;<span class="nicer">»</span></a>
</div>
<div class="next_article">
<a href="/Scratch/fr/blog/2010-05-24-Trees--Pragmatism-and-Formalism/">Arbres ; Pragmatisme et Formalisme&nbsp;<span class="nicer">»</span></a>
</div>
</div>
<div class="flush"></div>
</div>
</div>
<div id="bottom">
<div>
<a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/deed.fr">Droits de reproduction ©, Yann Esposito</a>
</div>
<div id="lastmod">
Écrit le : 23/03/2010
modifié le : 30/05/2011
</div>
<div>
Site entièrement réalisé avec
<a href="http://www.vim.org">Vim</a>
et
<a href="http://nanoc.stoneship.org">nanoc</a>
</div>
<div>
<a href="/Scratch/fr/validation/">Validation</a>
<a href="http://validator.w3.org/check?uri=referer"> [xhtml] </a>
.
<a href="http://jigsaw.w3.org/css-validator/check/referer?profile=css3"> [css] </a>
.
<a href="http://validator.w3.org/feed/check.cgi?url=http%3A//yannesposito.com/Scratch/fr/blog/feed/feed.xml">[rss]</a>
</div>
</div>
<div class="clear"></div>
</div>
</body>
</html>