5.3 KiB
isHidden | menupriority | kind | created_at | title | author_name | author_uri | tags | |||
---|---|---|---|---|---|---|---|---|---|---|
false | 1 | article | 2010-03-23T22:37:36+02:00 | Encapsuler git | Yann Esposito | yannesposito.com |
|
Se prémunir contre les erreurs
Je travaille sur un projet dans lequel certaines de mes branches git
doivent rester divergentes. Et les divergences devraient aller en s'accentuant.
J'utilise aussi certaines branches qui contiennent la partie commune de ces projets.
Disons que j'ai les branches :
- master: commune à toutes les branches
- dev: branche instable pour le développement
- client: Branche commune à plusieurs clients
- clientA: le projet spécialisé pour le client A
- clientB: le projet spécialisé pour le client B
Voilà comment je souhaiterai que ça fonctionne
blogimage("dynamic_branching.png","Dynamic branching")
Et plus précisément la hiérarchie des branches :
blogimage("branch_hierarchy.png","Branch hierarchy")
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 interdit de merger A dans B. Voici le code ruby correspondant :
$architecture={
:master => [ :dev, :client ],
:dev => [ :master ],
:client => [ :clientA, :clientB ] }
:master => [ :dev, :client ]
signifie que l'on peut merger la branche master
dans la branche dev
et la branche client
.
Je fait une erreur si je tape git checkout master && git merge clientA
.
C'est pour éviter ça que j'ai fait un script pour encapsuler le comportement de git
.
Mais ce script fait bien plus que ça. Il fait des merges en cascade de la racine vers les feuilles avec l'acion allmerges
.
git co dev && git merge master
git co client && git merge master
git co clientA && git merge client
git co clientB && git merge client
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.
Le voici :
#!/usr/bin/env ruby
# encoding: utf-8
architecture
master <-> dev
master -> client
clien -> clientA | clientB
merge using two of these branches should be
restricted to these rules
merge to one of these branch and an unknown one should
raise a warning, and may the option to add this new branch
to the hierarchy
$architecture={
:master => [ :dev, :client ],
:dev => [ :master ],
:client => [ :clientA, :clientB ] }
def get_current_branch()
(git branch --no-color | awk '$1 == "*" {print $2}'
).chop.intern
end
if ARGV.length == 0
puts %{usage: $0:t [git_command or local_command]
local commands:
allmerges: merge from top to down}
exit 0
end
require 'set'
$known_branches=Set.new
$architecture.each do |k,v|
$known_branches.add(k)
v.each { |b| $known_branches.add(b) }
end
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
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
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
case ARGV[0]
when 'allmerges' then do_all_merges
when 'merge' then do_merge
else system %{git #{ARGV.join(' ')}}
end
Pour que ça fonctionne il vous suffit de copier eng
dans un répertoire présent dans votre PATH
.
Bien entendu, il faut essayer de faire aussi peu que possible des cherry-pick
et des rebase
. Ce script a pour but de s'intégrer avec les workflow basé sur les pull
et merge
.