Spaces:
Running
Running
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> | |
<head> | |
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" /> | |
<meta name="generator" content="AsciiDoc 10.2.0" /> | |
<title>How to maintain Git</title> | |
<style type="text/css"> | |
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */ | |
/* Default font. */ | |
body { | |
font-family: Georgia,serif; | |
} | |
/* Title font. */ | |
h1, h2, h3, h4, h5, h6, | |
div.title, caption.title, | |
thead, p.table.header, | |
#toctitle, | |
#author, #revnumber, #revdate, #revremark, | |
#footer { | |
font-family: Arial,Helvetica,sans-serif; | |
} | |
body { | |
margin: 1em 5% 1em 5%; | |
} | |
a { | |
color: blue; | |
text-decoration: underline; | |
} | |
a:visited { | |
color: fuchsia; | |
} | |
em { | |
font-style: italic; | |
color: navy; | |
} | |
strong { | |
font-weight: bold; | |
color: #083194; | |
} | |
h1, h2, h3, h4, h5, h6 { | |
color: #527bbd; | |
margin-top: 1.2em; | |
margin-bottom: 0.5em; | |
line-height: 1.3; | |
} | |
h1, h2, h3 { | |
border-bottom: 2px solid silver; | |
} | |
h2 { | |
padding-top: 0.5em; | |
} | |
h3 { | |
float: left; | |
} | |
h3 + * { | |
clear: left; | |
} | |
h5 { | |
font-size: 1.0em; | |
} | |
div.sectionbody { | |
margin-left: 0; | |
} | |
hr { | |
border: 1px solid silver; | |
} | |
p { | |
margin-top: 0.5em; | |
margin-bottom: 0.5em; | |
} | |
ul, ol, li > p { | |
margin-top: 0; | |
} | |
ul > li { color: #aaa; } | |
ul > li > * { color: black; } | |
.monospaced, code, pre { | |
font-family: "Courier New", Courier, monospace; | |
font-size: inherit; | |
color: navy; | |
padding: 0; | |
margin: 0; | |
} | |
pre { | |
white-space: pre-wrap; | |
} | |
#author { | |
color: #527bbd; | |
font-weight: bold; | |
font-size: 1.1em; | |
} | |
#email { | |
} | |
#revnumber, #revdate, #revremark { | |
} | |
#footer { | |
font-size: small; | |
border-top: 2px solid silver; | |
padding-top: 0.5em; | |
margin-top: 4.0em; | |
} | |
#footer-text { | |
float: left; | |
padding-bottom: 0.5em; | |
} | |
#footer-badges { | |
float: right; | |
padding-bottom: 0.5em; | |
} | |
#preamble { | |
margin-top: 1.5em; | |
margin-bottom: 1.5em; | |
} | |
div.imageblock, div.exampleblock, div.verseblock, | |
div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, | |
div.admonitionblock { | |
margin-top: 1.0em; | |
margin-bottom: 1.5em; | |
} | |
div.admonitionblock { | |
margin-top: 2.0em; | |
margin-bottom: 2.0em; | |
margin-right: 10%; | |
color: #606060; | |
} | |
div.content { /* Block element content. */ | |
padding: 0; | |
} | |
/* Block element titles. */ | |
div.title, caption.title { | |
color: #527bbd; | |
font-weight: bold; | |
text-align: left; | |
margin-top: 1.0em; | |
margin-bottom: 0.5em; | |
} | |
div.title + * { | |
margin-top: 0; | |
} | |
td div.title:first-child { | |
margin-top: 0.0em; | |
} | |
div.content div.title:first-child { | |
margin-top: 0.0em; | |
} | |
div.content + div.title { | |
margin-top: 0.0em; | |
} | |
div.sidebarblock > div.content { | |
background: #ffffee; | |
border: 1px solid #dddddd; | |
border-left: 4px solid #f0f0f0; | |
padding: 0.5em; | |
} | |
div.listingblock > div.content { | |
border: 1px solid #dddddd; | |
border-left: 5px solid #f0f0f0; | |
background: #f8f8f8; | |
padding: 0.5em; | |
} | |
div.quoteblock, div.verseblock { | |
padding-left: 1.0em; | |
margin-left: 1.0em; | |
margin-right: 10%; | |
border-left: 5px solid #f0f0f0; | |
color: #888; | |
} | |
div.quoteblock > div.attribution { | |
padding-top: 0.5em; | |
text-align: right; | |
} | |
div.verseblock > pre.content { | |
font-family: inherit; | |
font-size: inherit; | |
} | |
div.verseblock > div.attribution { | |
padding-top: 0.75em; | |
text-align: left; | |
} | |
/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ | |
div.verseblock + div.attribution { | |
text-align: left; | |
} | |
div.admonitionblock .icon { | |
vertical-align: top; | |
font-size: 1.1em; | |
font-weight: bold; | |
text-decoration: underline; | |
color: #527bbd; | |
padding-right: 0.5em; | |
} | |
div.admonitionblock td.content { | |
padding-left: 0.5em; | |
border-left: 3px solid #dddddd; | |
} | |
div.exampleblock > div.content { | |
border-left: 3px solid #dddddd; | |
padding-left: 0.5em; | |
} | |
div.imageblock div.content { padding-left: 0; } | |
span.image img { border-style: none; vertical-align: text-bottom; } | |
a.image:visited { color: white; } | |
dl { | |
margin-top: 0.8em; | |
margin-bottom: 0.8em; | |
} | |
dt { | |
margin-top: 0.5em; | |
margin-bottom: 0; | |
font-style: normal; | |
color: navy; | |
} | |
dd > *:first-child { | |
margin-top: 0.1em; | |
} | |
ul, ol { | |
list-style-position: outside; | |
} | |
ol.arabic { | |
list-style-type: decimal; | |
} | |
ol.loweralpha { | |
list-style-type: lower-alpha; | |
} | |
ol.upperalpha { | |
list-style-type: upper-alpha; | |
} | |
ol.lowerroman { | |
list-style-type: lower-roman; | |
} | |
ol.upperroman { | |
list-style-type: upper-roman; | |
} | |
div.compact ul, div.compact ol, | |
div.compact p, div.compact p, | |
div.compact div, div.compact div { | |
margin-top: 0.1em; | |
margin-bottom: 0.1em; | |
} | |
tfoot { | |
font-weight: bold; | |
} | |
td > div.verse { | |
white-space: pre; | |
} | |
div.hdlist { | |
margin-top: 0.8em; | |
margin-bottom: 0.8em; | |
} | |
div.hdlist tr { | |
padding-bottom: 15px; | |
} | |
dt.hdlist1.strong, td.hdlist1.strong { | |
font-weight: bold; | |
} | |
td.hdlist1 { | |
vertical-align: top; | |
font-style: normal; | |
padding-right: 0.8em; | |
color: navy; | |
} | |
td.hdlist2 { | |
vertical-align: top; | |
} | |
div.hdlist.compact tr { | |
margin: 0; | |
padding-bottom: 0; | |
} | |
.comment { | |
background: yellow; | |
} | |
.footnote, .footnoteref { | |
font-size: 0.8em; | |
} | |
span.footnote, span.footnoteref { | |
vertical-align: super; | |
} | |
#footnotes { | |
margin: 20px 0 20px 0; | |
padding: 7px 0 0 0; | |
} | |
#footnotes div.footnote { | |
margin: 0 0 5px 0; | |
} | |
#footnotes hr { | |
border: none; | |
border-top: 1px solid silver; | |
height: 1px; | |
text-align: left; | |
margin-left: 0; | |
width: 20%; | |
min-width: 100px; | |
} | |
div.colist td { | |
padding-right: 0.5em; | |
padding-bottom: 0.3em; | |
vertical-align: top; | |
} | |
div.colist td img { | |
margin-top: 0.3em; | |
} | |
@media print { | |
#footer-badges { display: none; } | |
} | |
#toc { | |
margin-bottom: 2.5em; | |
} | |
#toctitle { | |
color: #527bbd; | |
font-size: 1.1em; | |
font-weight: bold; | |
margin-top: 1.0em; | |
margin-bottom: 0.1em; | |
} | |
div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { | |
margin-top: 0; | |
margin-bottom: 0; | |
} | |
div.toclevel2 { | |
margin-left: 2em; | |
font-size: 0.9em; | |
} | |
div.toclevel3 { | |
margin-left: 4em; | |
font-size: 0.9em; | |
} | |
div.toclevel4 { | |
margin-left: 6em; | |
font-size: 0.9em; | |
} | |
span.aqua { color: aqua; } | |
span.black { color: black; } | |
span.blue { color: blue; } | |
span.fuchsia { color: fuchsia; } | |
span.gray { color: gray; } | |
span.green { color: green; } | |
span.lime { color: lime; } | |
span.maroon { color: maroon; } | |
span.navy { color: navy; } | |
span.olive { color: olive; } | |
span.purple { color: purple; } | |
span.red { color: red; } | |
span.silver { color: silver; } | |
span.teal { color: teal; } | |
span.white { color: white; } | |
span.yellow { color: yellow; } | |
span.aqua-background { background: aqua; } | |
span.black-background { background: black; } | |
span.blue-background { background: blue; } | |
span.fuchsia-background { background: fuchsia; } | |
span.gray-background { background: gray; } | |
span.green-background { background: green; } | |
span.lime-background { background: lime; } | |
span.maroon-background { background: maroon; } | |
span.navy-background { background: navy; } | |
span.olive-background { background: olive; } | |
span.purple-background { background: purple; } | |
span.red-background { background: red; } | |
span.silver-background { background: silver; } | |
span.teal-background { background: teal; } | |
span.white-background { background: white; } | |
span.yellow-background { background: yellow; } | |
span.big { font-size: 2em; } | |
span.small { font-size: 0.6em; } | |
span.underline { text-decoration: underline; } | |
span.overline { text-decoration: overline; } | |
span.line-through { text-decoration: line-through; } | |
div.unbreakable { page-break-inside: avoid; } | |
/* | |
* xhtml11 specific | |
* | |
* */ | |
div.tableblock { | |
margin-top: 1.0em; | |
margin-bottom: 1.5em; | |
} | |
div.tableblock > table { | |
border: 3px solid #527bbd; | |
} | |
thead, p.table.header { | |
font-weight: bold; | |
color: #527bbd; | |
} | |
p.table { | |
margin-top: 0; | |
} | |
/* Because the table frame attribute is overridden by CSS in most browsers. */ | |
div.tableblock > table[frame="void"] { | |
border-style: none; | |
} | |
div.tableblock > table[frame="hsides"] { | |
border-left-style: none; | |
border-right-style: none; | |
} | |
div.tableblock > table[frame="vsides"] { | |
border-top-style: none; | |
border-bottom-style: none; | |
} | |
/* | |
* html5 specific | |
* | |
* */ | |
table.tableblock { | |
margin-top: 1.0em; | |
margin-bottom: 1.5em; | |
} | |
thead, p.tableblock.header { | |
font-weight: bold; | |
color: #527bbd; | |
} | |
p.tableblock { | |
margin-top: 0; | |
} | |
table.tableblock { | |
border-width: 3px; | |
border-spacing: 0px; | |
border-style: solid; | |
border-color: #527bbd; | |
border-collapse: collapse; | |
} | |
th.tableblock, td.tableblock { | |
border-width: 1px; | |
padding: 4px; | |
border-style: solid; | |
border-color: #527bbd; | |
} | |
table.tableblock.frame-topbot { | |
border-left-style: hidden; | |
border-right-style: hidden; | |
} | |
table.tableblock.frame-sides { | |
border-top-style: hidden; | |
border-bottom-style: hidden; | |
} | |
table.tableblock.frame-none { | |
border-style: hidden; | |
} | |
th.tableblock.halign-left, td.tableblock.halign-left { | |
text-align: left; | |
} | |
th.tableblock.halign-center, td.tableblock.halign-center { | |
text-align: center; | |
} | |
th.tableblock.halign-right, td.tableblock.halign-right { | |
text-align: right; | |
} | |
th.tableblock.valign-top, td.tableblock.valign-top { | |
vertical-align: top; | |
} | |
th.tableblock.valign-middle, td.tableblock.valign-middle { | |
vertical-align: middle; | |
} | |
th.tableblock.valign-bottom, td.tableblock.valign-bottom { | |
vertical-align: bottom; | |
} | |
/* | |
* manpage specific | |
* | |
* */ | |
body.manpage h1 { | |
padding-top: 0.5em; | |
padding-bottom: 0.5em; | |
border-top: 2px solid silver; | |
border-bottom: 2px solid silver; | |
} | |
body.manpage h2 { | |
border-style: none; | |
} | |
body.manpage div.sectionbody { | |
margin-left: 3em; | |
} | |
@media print { | |
body.manpage div#toc { display: none; } | |
} | |
</style> | |
<script type="text/javascript"> | |
/*<+'])'); | |
// Function that scans the DOM tree for header elements (the DOM2 | |
// nodeIterator API would be a better technique but not supported by all | |
// browsers). | |
var iterate = function (el) { | |
for (var i = el.firstChild; i != null; i = i.nextSibling) { | |
if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { | |
var mo = re.exec(i.tagName); | |
if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { | |
result[result.length] = new TocEntry(i, getText(i), mo[1]-1); | |
} | |
iterate(i); | |
} | |
} | |
} | |
iterate(el); | |
return result; | |
} | |
var toc = document.getElementById("toc"); | |
if (!toc) { | |
return; | |
} | |
// Delete existing TOC entries in case we're reloading the TOC. | |
var tocEntriesToRemove = []; | |
var i; | |
for (i = 0; i < toc.childNodes.length; i++) { | |
var entry = toc.childNodes[i]; | |
if (entry.nodeName.toLowerCase() == 'div' | |
&& entry.getAttribute("class") | |
&& entry.getAttribute("class").match(/^toclevel/)) | |
tocEntriesToRemove.push(entry); | |
} | |
for (i = 0; i < tocEntriesToRemove.length; i++) { | |
toc.removeChild(tocEntriesToRemove[i]); | |
} | |
// Rebuild TOC entries. | |
var entries = tocEntries(document.getElementById("content"), toclevels); | |
for (var i = 0; i < entries.length; ++i) { | |
var entry = entries[i]; | |
if (entry.element.id == "") | |
entry.element.id = "_toc_" + i; | |
var a = document.createElement("a"); | |
a.href = "#" + entry.element.id; | |
a.appendChild(document.createTextNode(entry.text)); | |
var div = document.createElement("div"); | |
div.appendChild(a); | |
div.className = "toclevel" + entry.toclevel; | |
toc.appendChild(div); | |
} | |
if (entries.length == 0) | |
toc.parentNode.removeChild(toc); | |
}, | |
///////////////////////////////////////////////////////////////////// | |
// Footnotes generator | |
///////////////////////////////////////////////////////////////////// | |
/* Based on footnote generation code from: | |
* http://www.brandspankingnew.net/archive/2005/07/format_footnote.html | |
*/ | |
footnotes: function () { | |
// Delete existing footnote entries in case we're reloading the footnodes. | |
var i; | |
var noteholder = document.getElementById("footnotes"); | |
if (!noteholder) { | |
return; | |
} | |
var entriesToRemove = []; | |
for (i = 0; i < noteholder.childNodes.length; i++) { | |
var entry = noteholder.childNodes[i]; | |
if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote") | |
entriesToRemove.push(entry); | |
} | |
for (i = 0; i < entriesToRemove.length; i++) { | |
noteholder.removeChild(entriesToRemove[i]); | |
} | |
// Rebuild footnote entries. | |
var cont = document.getElementById("content"); | |
var spans = cont.getElementsByTagName("span"); | |
var refs = {}; | |
var n = 0; | |
for (i=0; i<spans.length; i++) { | |
if (spans[i].className == "footnote") { | |
n++; | |
var note = spans[i].getAttribute("data-note"); | |
if (!note) { | |
// Use [\s\S] in place of . so multi-line matches work. | |
// Because JavaScript has no s (dotall) regex flag. | |
note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; | |
spans[i].innerHTML = | |
"[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + | |
"' title='View footnote' class='footnote'>" + n + "</a>]"; | |
spans[i].setAttribute("data-note", note); | |
} | |
noteholder.innerHTML += | |
"<div class='footnote' id='_footnote_" + n + "'>" + | |
"<a href='#_footnoteref_" + n + "' title='Return to text'>" + | |
n + "</a>. " + note + "</div>"; | |
var id =spans[i].getAttribute("id"); | |
if (id != null) refs["#"+id] = n; | |
} | |
} | |
if (n == 0) | |
noteholder.parentNode.removeChild(noteholder); | |
else { | |
// Process footnoterefs. | |
for (i=0; i<spans.length; i++) { | |
if (spans[i].className == "footnoteref") { | |
var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); | |
href = href.match(/#.*/)[0]; // Because IE return full URL. | |
n = refs[href]; | |
spans[i].innerHTML = | |
"[<a href='#_footnote_" + n + | |
"' title='View footnote' class='footnote'>" + n + "</a>]"; | |
} | |
} | |
} | |
}, | |
install: function(toclevels) { | |
var timerId; | |
function reinstall() { | |
asciidoc.footnotes(); | |
if (toclevels) { | |
asciidoc.toc(toclevels); | |
} | |
} | |
function reinstallAndRemoveTimer() { | |
clearInterval(timerId); | |
reinstall(); | |
} | |
timerId = setInterval(reinstall, 500); | |
if (document.addEventListener) | |
document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false); | |
else | |
window.onload = reinstallAndRemoveTimer; | |
} | |
} | |
asciidoc.install(); | |
/*]]>*/ | |
</script> | |
</head> | |
<body class="article"> | |
<div id="header"> | |
<h1>How to maintain Git</h1> | |
</div> | |
<div id="content"> | |
<div class="sect1"> | |
<h2 id="_activities">Activities</h2> | |
<div class="sectionbody"> | |
<div class="paragraph"><p>The maintainer’s Git time is spent on three activities.</p></div> | |
<div class="ulist"><ul> | |
<li> | |
<p> | |
Communication (45%) | |
</p> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>Mailing list discussions on general design, fielding user | |
questions, diagnosing bug reports; reviewing, commenting on, | |
suggesting alternatives to, and rejecting patches.</code></pre> | |
</div></div> | |
</li> | |
<li> | |
<p> | |
Integration (50%) | |
</p> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>Applying new patches from the contributors while spotting and | |
correcting minor mistakes, shuffling the integration and | |
testing branches, pushing the results out, cutting the | |
releases, and making announcements.</code></pre> | |
</div></div> | |
</li> | |
<li> | |
<p> | |
Own development (5%) | |
</p> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>Scratching my own itch and sending proposed patch series out.</code></pre> | |
</div></div> | |
</li> | |
</ul></div> | |
</div> | |
</div> | |
<div class="sect1"> | |
<h2 id="_the_policy">The Policy</h2> | |
<div class="sectionbody"> | |
<div class="paragraph"><p>The policy on Integration is informally mentioned in "A Note | |
from the maintainer" message, which is periodically posted to | |
this mailing list after each feature release is made.</p></div> | |
<div class="ulist"><ul> | |
<li> | |
<p> | |
Feature releases are numbered as vX.Y.0 and are meant to | |
contain bugfixes and enhancements in any area, including | |
functionality, performance and usability, without regression. | |
</p> | |
</li> | |
<li> | |
<p> | |
One release cycle for a feature release is expected to last for | |
eight to ten weeks. | |
</p> | |
</li> | |
<li> | |
<p> | |
Maintenance releases are numbered as vX.Y.Z and are meant | |
to contain only bugfixes for the corresponding vX.Y.0 feature | |
release and earlier maintenance releases vX.Y.W (W < Z). | |
</p> | |
</li> | |
<li> | |
<p> | |
<em>master</em> branch is used to prepare for the next feature | |
release. In other words, at some point, the tip of <em>master</em> | |
branch is tagged with vX.Y.0. | |
</p> | |
</li> | |
<li> | |
<p> | |
<em>maint</em> branch is used to prepare for the next maintenance | |
release. After the feature release vX.Y.0 is made, the tip | |
of <em>maint</em> branch is set to that release, and bugfixes will | |
accumulate on the branch, and at some point, the tip of the | |
branch is tagged with vX.Y.1, vX.Y.2, and so on. | |
</p> | |
</li> | |
<li> | |
<p> | |
<em>next</em> branch is used to publish changes (both enhancements | |
and fixes) that (1) have worthwhile goal, (2) are in a fairly | |
good shape suitable for everyday use, (3) but have not yet | |
demonstrated to be regression free. New changes are tested | |
in <em>next</em> before merged to <em>master</em>. | |
</p> | |
</li> | |
<li> | |
<p> | |
<em>seen</em> branch is used to publish other proposed changes that do | |
not yet pass the criteria set for <em>next</em>. | |
</p> | |
</li> | |
<li> | |
<p> | |
The tips of <em>master</em> and <em>maint</em> branches will not be rewound to | |
allow people to build their own customization on top of them. | |
Early in a new development cycle, <em>next</em> is rewound to the tip of | |
<em>master</em> once, but otherwise it will not be rewound until the end | |
of the cycle. | |
</p> | |
</li> | |
<li> | |
<p> | |
Usually <em>master</em> contains all of <em>maint</em> and <em>next</em> contains all | |
of <em>master</em>. <em>seen</em> contains all the topics merged to <em>next</em>, but | |
is rebuilt directly on <em>master</em>. | |
</p> | |
</li> | |
<li> | |
<p> | |
The tip of <em>master</em> is meant to be more stable than any | |
tagged releases, and the users are encouraged to follow it. | |
</p> | |
</li> | |
<li> | |
<p> | |
The <em>next</em> branch is where new action takes place, and the | |
users are encouraged to test it so that regressions and bugs | |
are found before new topics are merged to <em>master</em>. | |
</p> | |
</li> | |
</ul></div> | |
<div class="paragraph"><p>Note that before v1.9.0 release, the version numbers used to be | |
structured slightly differently. vX.Y.Z were feature releases while | |
vX.Y.Z.W were maintenance releases for vX.Y.Z.</p></div> | |
</div> | |
</div> | |
<div class="sect1"> | |
<h2 id="_a_typical_git_day">A Typical Git Day</h2> | |
<div class="sectionbody"> | |
<div class="paragraph"><p>A typical Git day for the maintainer implements the above policy | |
by doing the following:</p></div> | |
<div class="ulist"><ul> | |
<li> | |
<p> | |
Scan mailing list. Respond with review comments, suggestions | |
etc. Kibitz. Collect potentially usable patches from the | |
mailing list. Patches about a single topic go to one mailbox (I | |
read my mail in Gnus, and type \C-o to save/append messages in | |
files in mbox format). | |
</p> | |
</li> | |
<li> | |
<p> | |
Write his own patches to address issues raised on the list but | |
nobody has stepped up solving. Send it out just like other | |
contributors do, and pick them up just like patches from other | |
contributors (see above). | |
</p> | |
</li> | |
<li> | |
<p> | |
Review the patches in the saved mailboxes. Edit proposed log | |
message for typofixes and clarifications, and add Acks | |
collected from the list. Edit patch to incorporate "Oops, | |
that should have been like this" fixes from the discussion. | |
</p> | |
</li> | |
<li> | |
<p> | |
Classify the collected patches and handle <em>master</em> and | |
<em>maint</em> updates: | |
</p> | |
</li> | |
<li> | |
<p> | |
Obviously correct fixes that pertain to the tip of <em>maint</em> | |
are directly applied to <em>maint</em>. | |
</p> | |
</li> | |
<li> | |
<p> | |
Obviously correct fixes that pertain to the tip of <em>master</em> | |
are directly applied to <em>master</em>. | |
</p> | |
</li> | |
<li> | |
<p> | |
Other topics are not handled in this step. | |
</p> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>This step is done with "git am".</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ git checkout master ;# or "git checkout maint" | |
$ git am -sc3 mailbox | |
$ make test</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>In practice, almost no patch directly goes to 'master' or | |
'maint'.</code></pre> | |
</div></div> | |
</li> | |
<li> | |
<p> | |
Review the last issue of "What’s cooking" message, review the | |
topics ready for merging (topic→master and topic→maint). Use | |
"Meta/cook -w" script (where Meta/ contains a checkout of the | |
<em>todo</em> branch) to aid this step. | |
</p> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>And perform the merge. Use "Meta/Reintegrate -e" script (see | |
later) to aid this step.</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ Meta/cook -w last-issue-of-whats-cooking.mbox</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ git checkout master ;# or "git checkout maint" | |
$ echo ai/topic | Meta/Reintegrate -e ;# "git merge ai/topic" | |
$ git log -p ORIG_HEAD.. ;# final review | |
$ git diff ORIG_HEAD.. ;# final review | |
$ make test ;# final review</code></pre> | |
</div></div> | |
</li> | |
<li> | |
<p> | |
Handle the remaining patches: | |
</p> | |
</li> | |
<li> | |
<p> | |
Anything unobvious that is applicable to <em>master</em> (in other | |
words, does not depend on anything that is still in <em>next</em> | |
and not in <em>master</em>) is applied to a new topic branch that | |
is forked from the tip of <em>master</em> (or the last feature release, | |
which is a bit older than <em>master</em>). This includes both | |
enhancements and unobvious fixes to <em>master</em>. A topic | |
branch is named as ai/topic where "ai" is two-letter string | |
named after author’s initial and "topic" is a descriptive name | |
of the topic (in other words, "what’s the series is about"). | |
</p> | |
</li> | |
<li> | |
<p> | |
An unobvious fix meant for <em>maint</em> is applied to a new | |
topic branch that is forked from the tip of <em>maint</em> (or the | |
oldest and still relevant maintenance branch). The | |
topic may be named as ai/maint-topic. | |
</p> | |
</li> | |
<li> | |
<p> | |
Changes that pertain to an existing topic are applied to | |
the branch, but: | |
</p> | |
</li> | |
<li> | |
<p> | |
obviously correct ones are applied first; | |
</p> | |
</li> | |
<li> | |
<p> | |
questionable ones are discarded or applied to near the tip; | |
</p> | |
</li> | |
<li> | |
<p> | |
Replacement patches to an existing topic are accepted only | |
for commits not in <em>next</em>. | |
</p> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>The initial round is done with:</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ git checkout ai/topic ;# or "git checkout -b ai/topic master" | |
$ git am -sc3 mailbox</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>and replacing an existing topic with subsequent round is done with:</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ git checkout master...ai/topic ;# try to reapply to the same base | |
$ git am -sc3 mailbox</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>to prepare the new round on a detached HEAD, and then</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ git range-diff @{-1}... | |
$ git diff @{-1}</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>to double check what changed since the last round, and finally</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ git checkout -B @{-1}</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>to conclude (the last step is why a topic already in 'next' is | |
not replaced but updated incrementally).</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>Whether it is the initial round or a subsequent round, the topic | |
may not build even in isolation, or may break the build when | |
merged to integration branches due to bugs. There may already | |
be obvious and trivial improvements suggested on the list. The | |
maintainer often adds an extra commit, with "SQUASH???" in its | |
title, to fix things up, before publishing the integration | |
branches to make it usable by other developers for testing. | |
These changes are what the maintainer is not 100% committed to | |
(trivial typofixes etc. are often squashed directly into the | |
patches that need fixing, without being applied as a separate | |
"SQUASH???" commit), so that they can be removed easily as needed.</code></pre> | |
</div></div> | |
</li> | |
<li> | |
<p> | |
Merge maint to master as needed: | |
</p> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ git checkout master | |
$ git merge maint | |
$ make test</code></pre> | |
</div></div> | |
</li> | |
<li> | |
<p> | |
Merge master to next as needed: | |
</p> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ git checkout next | |
$ git merge master | |
$ make test</code></pre> | |
</div></div> | |
</li> | |
<li> | |
<p> | |
Review the last issue of "What’s cooking" again and see if topics | |
that are ready to be merged to <em>next</em> are still in good shape | |
(e.g. has there any new issue identified on the list with the | |
series?) | |
</p> | |
</li> | |
<li> | |
<p> | |
Prepare <em>jch</em> branch, which is used to represent somewhere | |
between <em>master</em> and <em>seen</em> and often is slightly ahead of <em>next</em>. | |
</p> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ Meta/Reintegrate master..jch >Meta/redo-jch.sh</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>The result is a script that lists topics to be merged in order to | |
rebuild 'seen' as the input to Meta/Reintegrate script. Remove | |
later topics that should not be in 'jch' yet. Add a line that | |
consists of '### match next' before the name of the first topic | |
in the output that should be in 'jch' but not in 'next' yet.</code></pre> | |
</div></div> | |
</li> | |
<li> | |
<p> | |
Now we are ready to start merging topics to <em>next</em>. For each | |
branch whose tip is not merged to <em>next</em>, one of three things can | |
happen: | |
</p> | |
</li> | |
<li> | |
<p> | |
The commits are all next-worthy; merge the topic to next; | |
</p> | |
</li> | |
<li> | |
<p> | |
The new parts are of mixed quality, but earlier ones are | |
next-worthy; merge the early parts to next; | |
</p> | |
</li> | |
<li> | |
<p> | |
Nothing is next-worthy; do not do anything. | |
</p> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>This step is aided with Meta/redo-jch.sh script created earlier. | |
If a topic that was already in 'next' gained a patch, the script | |
would list it as "ai/topic~1". To include the new patch to the | |
updated 'next', drop the "~1" part; to keep it excluded, do not | |
touch the line. If a topic that was not in 'next' should be | |
merged to 'next', add it at the end of the list. Then:</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ git checkout -B jch master | |
$ sh Meta/redo-jch.sh -c1</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>to rebuild the 'jch' branch from scratch. "-c1" tells the script | |
to stop merging at the first line that begins with '###' | |
(i.e. the "### match next" line you added earlier).</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>At this point, build-test the result. It may reveal semantic | |
conflicts (e.g. a topic renamed a variable, another added a new | |
reference to the variable under its old name), in which case | |
prepare an appropriate merge-fix first (see appendix), and | |
rebuild the 'jch' branch from scratch, starting at the tip of | |
'master'.</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>Then do the same to 'next'</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ git checkout next | |
$ sh Meta/redo-jch.sh -c1 -e</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>The "-e" option allows the merge message that comes from the | |
history of the topic and the comments in the "What's cooking" to | |
be edited. The resulting tree should match 'jch' as the same set | |
of topics are merged on 'master'; otherwise there is a mismerge. | |
Investigate why and do not proceed until the mismerge is found | |
and rectified.</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ git diff jch next</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>Then build the rest of 'jch':</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ git checkout jch | |
$ sh Meta/redo-jch.sh</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>When all is well, clean up the redo-jch.sh script with</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ sh Meta/redo-jch.sh -u</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>This removes topics listed in the script that have already been | |
merged to 'master'. This may lose '### match next' marker; | |
add it again to the appropriate place when it happens.</code></pre> | |
</div></div> | |
</li> | |
<li> | |
<p> | |
Rebuild <em>seen</em>. | |
</p> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ Meta/Reintegrate jch..seen >Meta/redo-seen.sh</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>Edit the result by adding new topics that are not still in 'seen' | |
in the script. Then</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ git checkout -B seen jch | |
$ sh Meta/redo-seen.sh</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>When all is well, clean up the redo-seen.sh script with</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ sh Meta/redo-seen.sh -u</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>Double check by running</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ git branch --no-merged seen</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>to see there is no unexpected leftover topics.</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>At this point, build-test the result for semantic conflicts, and | |
if there are, prepare an appropriate merge-fix first (see | |
appendix), and rebuild the 'seen' branch from scratch, starting at | |
the tip of 'jch'.</code></pre> | |
</div></div> | |
</li> | |
<li> | |
<p> | |
Update "What’s cooking" message to review the updates to | |
existing topics, newly added topics and graduated topics. | |
</p> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>This step is helped with Meta/cook script.</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ Meta/cook</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>This script inspects the history between master..seen, finds tips | |
of topic branches, compares what it found with the current | |
contents in Meta/whats-cooking.txt, and updates that file. | |
Topics not listed in the file but are found in master..seen are | |
added to the "New topics" section, topics listed in the file that | |
are no longer found in master..seen are moved to the "Graduated to | |
master" section, and topics whose commits changed their states | |
(e.g. used to be only in 'seen', now merged to 'next') are updated | |
with change markers "<<" and ">>".</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>Look for lines enclosed in "<<" and ">>"; they hold contents from | |
old file that are replaced by this integration round. After | |
verifying them, remove the old part. Review the description for | |
each topic and update its doneness and plan as needed. To review | |
the updated plan, run</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ Meta/cook -w</code></pre> | |
</div></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>which will pick up comments given to the topics, such as "Will | |
merge to 'next'", etc. (see Meta/cook script to learn what kind | |
of phrases are supported).</code></pre> | |
</div></div> | |
</li> | |
<li> | |
<p> | |
Compile, test and install all four (five) integration branches; | |
Meta/Dothem script may aid this step. | |
</p> | |
</li> | |
<li> | |
<p> | |
Format documentation if the <em>master</em> branch was updated; | |
Meta/dodoc.sh script may aid this step. | |
</p> | |
</li> | |
<li> | |
<p> | |
Push the integration branches out to public places; Meta/pushall | |
script may aid this step. | |
</p> | |
</li> | |
</ul></div> | |
</div> | |
</div> | |
<div class="sect1"> | |
<h2 id="_observations">Observations</h2> | |
<div class="sectionbody"> | |
<div class="paragraph"><p>Some observations to be made.</p></div> | |
<div class="ulist"><ul> | |
<li> | |
<p> | |
Each topic is tested individually, and also together with other | |
topics cooking first in <em>seen</em>, then in <em>jch</em> and then in <em>next</em>. | |
Until it matures, no part of it is merged to <em>master</em>. | |
</p> | |
</li> | |
<li> | |
<p> | |
A topic already in <em>next</em> can get fixes while still in | |
<em>next</em>. Such a topic will have many merges to <em>next</em> (in | |
other words, "git log --first-parent next" will show many | |
"Merge branch <em>ai/topic</em> to next" for the same topic. | |
</p> | |
</li> | |
<li> | |
<p> | |
An unobvious fix for <em>maint</em> is cooked in <em>next</em> and then | |
merged to <em>master</em> to make extra sure it is Ok and then | |
merged to <em>maint</em>. | |
</p> | |
</li> | |
<li> | |
<p> | |
Even when <em>next</em> becomes empty (in other words, all topics | |
prove stable and are merged to <em>master</em> and "git diff master | |
next" shows empty), it has tons of merge commits that will | |
never be in <em>master</em>. | |
</p> | |
</li> | |
<li> | |
<p> | |
In principle, "git log --first-parent master..next" should | |
show nothing but merges (in practice, there are fixup commits | |
and reverts that are not merges). | |
</p> | |
</li> | |
<li> | |
<p> | |
Commits near the tip of a topic branch that are not in <em>next</em> | |
are fair game to be discarded, replaced or rewritten. | |
Commits already merged to <em>next</em> will not be. | |
</p> | |
</li> | |
<li> | |
<p> | |
Being in the <em>next</em> branch is not a guarantee for a topic to | |
be included in the next feature release. Being in the | |
<em>master</em> branch typically is. | |
</p> | |
</li> | |
<li> | |
<p> | |
Due to the nature of "SQUASH???" fix-ups, if the original author | |
agrees with the suggested changes, it is OK to squash them to | |
appropriate patches in the next round (when the suggested change | |
is small enough, the author should not even bother with | |
"Helped-by"). It is also OK to drop them from the next round | |
when the original author does not agree with the suggestion, but | |
the author is expected to say why somewhere in the discussion. | |
</p> | |
</li> | |
</ul></div> | |
</div> | |
</div> | |
<div class="sect1"> | |
<h2 id="_appendix">Appendix</h2> | |
<div class="sectionbody"> | |
<div class="sect2"> | |
<h3 id="_preparing_a_merge_fix">Preparing a "merge-fix"</h3> | |
<div class="paragraph"><p>A merge of two topics may not textually conflict but still have | |
conflict at the semantic level. A classic example is for one topic | |
to rename an variable and all its uses, while another topic adds a | |
new use of the variable under its old name. When these two topics | |
are merged together, the reference to the variable newly added by | |
the latter topic will still use the old name in the result.</p></div> | |
<div class="paragraph"><p>The Meta/Reintegrate script that is used by redo-jch and redo-seen | |
scripts implements a crude but usable way to work this issue around. | |
When the script merges branch $X, it checks if "refs/merge-fix/$X" | |
exists, and if so, the effect of it is squashed into the result of | |
the mechanical merge. In other words,</p></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ echo $X | Meta/Reintegrate</code></pre> | |
</div></div> | |
<div class="paragraph"><p>is roughly equivalent to this sequence:</p></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ git merge --rerere-autoupdate $X | |
$ git commit | |
$ git cherry-pick -n refs/merge-fix/$X | |
$ git commit --amend</code></pre> | |
</div></div> | |
<div class="paragraph"><p>The goal of this "prepare a merge-fix" step is to come up with a | |
commit that can be squashed into a result of mechanical merge to | |
correct semantic conflicts.</p></div> | |
<div class="paragraph"><p>After finding that the result of merging branch "ai/topic" to an | |
integration branch had such a semantic conflict, say seen~4, check the | |
problematic merge out on a detached HEAD, edit the working tree to | |
fix the semantic conflict, and make a separate commit to record the | |
fix-up:</p></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ git checkout seen~4 | |
$ git show -s --pretty=%s ;# double check | |
Merge branch 'ai/topic' to seen | |
$ edit | |
$ git commit -m 'merge-fix/ai/topic' -a</code></pre> | |
</div></div> | |
<div class="paragraph"><p>Then make a reference "refs/merge-fix/ai/topic" to point at this | |
result:</p></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ git update-ref refs/merge-fix/ai/topic HEAD</code></pre> | |
</div></div> | |
<div class="paragraph"><p>Then double check the result by asking Meta/Reintegrate to redo the | |
merge:</p></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ git checkout seen~5 ;# the parent of the problem merge | |
$ echo ai/topic | Meta/Reintegrate | |
$ git diff seen~4</code></pre> | |
</div></div> | |
<div class="paragraph"><p>This time, because you prepared refs/merge-fix/ai/topic, the | |
resulting merge should have been tweaked to include the fix for the | |
semantic conflict.</p></div> | |
<div class="paragraph"><p>Note that this assumes that the order in which conflicting branches | |
are merged does not change. If the reason why merging ai/topic | |
branch needs this merge-fix is because another branch merged earlier | |
to the integration branch changed the underlying assumption ai/topic | |
branch made (e.g. ai/topic branch added a site to refer to a | |
variable, while the other branch renamed that variable and adjusted | |
existing use sites), and if you changed redo-jch (or redo-seen) script | |
to merge ai/topic branch before the other branch, then the above | |
merge-fix should not be applied while merging ai/topic, but should | |
instead be applied while merging the other branch. You would need | |
to move the fix to apply to the other branch, perhaps like this:</p></div> | |
<div class="literalblock"> | |
<div class="content"> | |
<pre><code>$ mf=refs/merge-fix | |
$ git update-ref $mf/$the_other_branch $mf/ai/topic | |
$ git update-ref -d $mf/ai/topic</code></pre> | |
</div></div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div id="footnotes"><hr /></div> | |
<div id="footer"> | |
<div id="footer-text"> | |
Last updated | |
2023-04-24 08:32:54 PDT | |
</div> | |
</div> | |
</body> | |
</html> | |