147 lines
9.8 KiB
HTML
147 lines
9.8 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="fr">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<title>YBlog - Encapsuler git</title>
|
||
<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="../../../../css/y.css" />
|
||
<link rel="stylesheet" type="text/css" href="/css/legacy.css" />
|
||
<link rel="alternate" type="application/rss+xml" title="RSS" href="/rss.xml" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<link rel="apple-touch-icon" href="../../../../Scratch/img/about/FlatAvatar@2x.png" />
|
||
<!--[if lt IE 9]>
|
||
<script src="http://ie7-js.googlecode.com/svn/version/2.1(beta4)/IE9.js"></script>
|
||
<![endif]-->
|
||
<!-- IndieAuth -->
|
||
<link href="https://twitter.com/yogsototh" rel="me">
|
||
<link href="https://github.com/yogsototh" rel="me">
|
||
<link href="mailto:yann.esposito@gmail.com" rel="me">
|
||
<link rel="pgpkey" href="../../../../pubkey.txt">
|
||
</head>
|
||
<body lang="fr" class="article">
|
||
<div id="content">
|
||
<div id="header">
|
||
<div id="choix">
|
||
<span id="choixlang">
|
||
<a href="../../../../Scratch/en/blog/2010-03-23-Encapsulate-git/">Anglais</a>
|
||
</span>
|
||
<span class="tomenu"><a href="#navigation">↓ Menu ↓</a></span>
|
||
<span class="flush"></span>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="titre">
|
||
<h1>Encapsuler git</h1>
|
||
|
||
</div>
|
||
<div class="flush"></div>
|
||
<div id="afterheader" class="article">
|
||
<div class="corps">
|
||
<p><span class="intro"> Voici une solution pour conserver des branches divergentes avec <code>git</code>. Parce qu’il 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-prémunir-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 s’accentuant.</p>
|
||
<p>J’utilise aussi certaines branches qui contiennent la partie commune de ces projets.</p>
|
||
<p>Disons que j’ai les branches :</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>
|
||
<div>
|
||
<img src="../../../../Scratch/img/blog/2010-03-23-Encapsulate-git/dynamic_branching.png" alt="Dynamic branching" />
|
||
</div>
|
||
<p>Et plus précisément la hiérarchie des branches :</p>
|
||
<div>
|
||
<img src="../../../../Scratch/img/blog/2010-03-23-Encapsulate-git/branch_hierarchy.png" alt="Branch hierarchy" />
|
||
</div>
|
||
<p>Une flèche de A vers B signifie que l’on peut merger A dans B. S’il n’y a pas de flèche de A vers B cela signifie qu’il est <em>interdit</em> de merger A dans B. Voici le code ruby correspondant :</p>
|
||
<div>
|
||
<code class="ruby"> $architecture={ :master => [ :dev, :client ], :dev => [ :master ], :client => [ :clientA, :clientB ] } </code>
|
||
</div>
|
||
<p><code>:master => [ :dev, :client ]</code> signifie que l’on 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 && git merge clientA</code>. C’est pour éviter ça que j’ai 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 l’acion <code>allmerges</code>.</p>
|
||
<div>
|
||
<code class="zsh"> git co dev && git merge master git co client && git merge master git co clientA && git merge client git co clientB && git merge client </code>
|
||
</div>
|
||
<p>Je peux ainsi mettre à jour toutes les branches. L’algorithme ne boucle pas même s’il y a des cycles dans la structure des branches.<br />
|
||
Le voici :</p>
|
||
<div class="small">
|
||
<p><code class="ruby" file="eng"> #!/usr/bin/env ruby # encoding: utf-8</p>
|
||
<h1 id="architecture">architecture</h1>
|
||
<h1 id="section"></h1>
|
||
<h1 id="master---dev">master <-> dev</h1>
|
||
<h1 id="master---client">master -> client</h1>
|
||
<h1 id="clien---clienta-clientb">clien -> clientA | clientB</h1>
|
||
<h1 id="section-1"></h1>
|
||
<h1 id="merge-using-two-of-these-branches-should-be">merge using two of these branches should be</h1>
|
||
<h1 id="restricted-to-these-rules">restricted to these rules</h1>
|
||
<h1 id="merge-to-one-of-these-branch-and-an-unknown-one-should">merge to one of these branch and an unknown one should</h1>
|
||
<h1 id="raise-a-warning-and-may-the-option-to-add-this-new-branch">raise a warning, and may the option to add this new branch</h1>
|
||
<h1 id="to-the-hierarchy">to the hierarchy</h1>
|
||
<p>$architecture={ :master => [ :dev, :client ], :dev => [ :master ], :client => [ :clientA, :clientB ] }</p>
|
||
<p>def get_current_branch() (<code>git branch --no-color | awk '$1 == "*" {print $2}'</code>).chop.intern end</p>
|
||
<p>if ARGV.length == 0 puts %{usage: $0:t [git_command or local_command]</p>
|
||
<p>local commands: allmerges: merge from top to down} exit 0 end</p>
|
||
<p>require ‘set’ $known_branches=Set.new $architecture.each do |k,v| $known_branches.add(k) v.each { |b| $known_branches.add(b) } end</p>
|
||
<p>def rec_merge(branch) if $architecture[branch].nil? return end $architecture[branch].each do |b| if $flag.has_key?(b.to_s + branch.to_s) next end flagname=branch.to_s + b.to_s if $flag.has_key?(flagname) next end if system %{eng checkout #{b}} if get_current_branch != b puts “Can’t checkout to #{b}” exit 2 end if system %{eng merge #{branch}} $flag[flagname]=true rec_merge(b) else exit 1 end else exit 1 end end end</p>
|
||
<p>def do_all_merges puts ‘Will merge from father to sons’ current_branch=get_current_branch $flag={} rec_merge(:master) system %{git co #{current_branch}} end</p>
|
||
<p>def do_merge current_branch=get_current_branch src_branch=ARGV[1].intern puts %{do_merge: #{src_branch} => #{current_branch}} if $known_branches.include?(current_branch) if $known_branches.include?(src_branch) if $architecture.has_key?(src_branch) and $architecture[src_branch].include?(current_branch) system %{git merge #{src_branch}} else puts %{Forbidden merge: #{src_branch} => #{current_branch}} end else puts %{Warning! #{src_branch} not mentionned in rb configuration} sleep 2 f system %{git merge #{src_branch}} puts %{Warning! #{src_branch} not mentionned in rb configuration} end end end</p>
|
||
case ARGV[0] when ‘allmerges’ then do_all_merges when ‘merge’ then do_merge else system %{git #{ARGV.join(’ ’)}} end </code>
|
||
</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 s’intégrer avec les workflow basé sur les <code>pull</code> et <code>merge</code>.</p>
|
||
</div>
|
||
<div id="afterarticle">
|
||
<div id="social">
|
||
<a href="/rss.xml" target="_blank" rel="noopener noreferrer nofollow" class="social">RSS</a>
|
||
·
|
||
<a href="https://twitter.com/home?status=http%3A%2F%2Fyannesposito.com/Scratch/fr/blog/2010-03-23-Encapsulate-git/%20via%20@yogsototh" target="_blank" rel="noopener noreferrer nofollow" class="social">Tweet</a>
|
||
·
|
||
<a href="http://www.facebook.com/sharer/sharer.php?u=http%3A%2F%2Fyannesposito.com/Scratch/fr/blog/2010-03-23-Encapsulate-git/" target="_blank" rel="noopener noreferrer nofollow" class="social">FB</a>
|
||
<br />
|
||
<a class="message" href="../../../../Scratch/fr/blog/Social-link-the-right-way/">Ces liens sociaux préservent votre vie privée</a>
|
||
</div>
|
||
<div id="navigation">
|
||
<a href="../../../../">Accueil</a>
|
||
<span class="sep">¦</span>
|
||
<a href="../../../../Scratch/fr/blog">Blog</a>
|
||
<span class="sep">¦</span>
|
||
<a href="../../../../Scratch/fr/softwares">Logiciels</a>
|
||
<span class="sep">¦</span>
|
||
<a href="../../../../Scratch/fr/about">Auteur</a>
|
||
</div>
|
||
<div id="totop"><a href="#header">↑ Top ↑</a></div>
|
||
<div id="bottom">
|
||
<div>
|
||
Published on 2010-03-23
|
||
</div>
|
||
<div>
|
||
<a href="https://twitter.com/yogsototh">Follow @yogsototh</a>
|
||
</div>
|
||
<div>
|
||
<a rel="license" href="http://creativecommons.org/licenses/by/3.0/deed.en_US">Yann Esposito©</a>
|
||
</div>
|
||
|
||
<div>
|
||
Done with
|
||
<a href="http://www.vim.org" target="_blank" rel="noopener noreferrer nofollow"><strike>Vim</strike></a>
|
||
<a href="http://spacemacs.org" target="_blank" rel="noopener noreferrer nofollow">spacemacs</a>
|
||
<span class="pala">&</span>
|
||
<a href="http://nanoc.ws" target="_blank" rel="noopener noreferrer nofollow"><strike>nanoc</strike></a>
|
||
<a href="http://jaspervdj.be/hakyll" target="_blank" rel="noopener noreferrer nofollow">Hakyll</a>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</body>
|
||
</html>
|