You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
475 lines
18 KiB
475 lines
18 KiB
From: Junio C Hamano <gitster@pobox.com> |
|
Date: Wed, 21 Nov 2007 16:32:55 -0800 |
|
Subject: Addendum to "MaintNotes" |
|
Abstract: Imagine that Git development is racing along as usual, when our friendly |
|
neighborhood maintainer is struck down by a wayward bus. Out of the |
|
hordes of suckers (loyal developers), you have been tricked (chosen) to |
|
step up as the new maintainer. This howto will show you "how to" do it. |
|
Content-type: text/asciidoc |
|
|
|
How to maintain Git |
|
=================== |
|
|
|
Activities |
|
---------- |
|
|
|
The maintainer's Git time is spent on three activities. |
|
|
|
- Communication (45%) |
|
|
|
Mailing list discussions on general design, fielding user |
|
questions, diagnosing bug reports; reviewing, commenting on, |
|
suggesting alternatives to, and rejecting patches. |
|
|
|
- Integration (50%) |
|
|
|
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. |
|
|
|
- Own development (5%) |
|
|
|
Scratching my own itch and sending proposed patch series out. |
|
|
|
The Policy |
|
---------- |
|
|
|
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. |
|
|
|
- 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. |
|
|
|
- One release cycle for a feature release is expected to last for |
|
eight to ten weeks. |
|
|
|
- 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). |
|
|
|
- 'master' branch is used to prepare for the next feature |
|
release. In other words, at some point, the tip of 'master' |
|
branch is tagged with vX.Y.0. |
|
|
|
- 'maint' branch is used to prepare for the next maintenance |
|
release. After the feature release vX.Y.0 is made, the tip |
|
of 'maint' 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. |
|
|
|
- 'next' 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 'next' before merged to 'master'. |
|
|
|
- 'seen' branch is used to publish other proposed changes that do |
|
not yet pass the criteria set for 'next'. |
|
|
|
- The tips of 'master' and 'maint' branches will not be rewound to |
|
allow people to build their own customization on top of them. |
|
Early in a new development cycle, 'next' is rewound to the tip of |
|
'master' once, but otherwise it will not be rewound until the end |
|
of the cycle. |
|
|
|
- Usually 'master' contains all of 'maint' and 'next' contains all |
|
of 'master'. 'seen' contains all the topics merged to 'next', but |
|
is rebuilt directly on 'master'. |
|
|
|
- The tip of 'master' is meant to be more stable than any |
|
tagged releases, and the users are encouraged to follow it. |
|
|
|
- The 'next' 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 'master'. |
|
|
|
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. |
|
|
|
|
|
A Typical Git Day |
|
----------------- |
|
|
|
A typical Git day for the maintainer implements the above policy |
|
by doing the following: |
|
|
|
- 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). |
|
|
|
- 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). |
|
|
|
- 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. |
|
|
|
- Classify the collected patches and handle 'master' and |
|
'maint' updates: |
|
|
|
- Obviously correct fixes that pertain to the tip of 'maint' |
|
are directly applied to 'maint'. |
|
|
|
- Obviously correct fixes that pertain to the tip of 'master' |
|
are directly applied to 'master'. |
|
|
|
- Other topics are not handled in this step. |
|
|
|
This step is done with "git am". |
|
|
|
$ git checkout master ;# or "git checkout maint" |
|
$ git am -sc3 mailbox |
|
$ make test |
|
|
|
In practice, almost no patch directly goes to 'master' or |
|
'maint'. |
|
|
|
- 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 |
|
'todo' branch) to aid this step. |
|
|
|
And perform the merge. Use "Meta/Reintegrate -e" script (see |
|
later) to aid this step. |
|
|
|
$ Meta/cook -w last-issue-of-whats-cooking.mbox |
|
|
|
$ 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 |
|
|
|
- Handle the remaining patches: |
|
|
|
- Anything unobvious that is applicable to 'master' (in other |
|
words, does not depend on anything that is still in 'next' |
|
and not in 'master') is applied to a new topic branch that |
|
is forked from the tip of 'master' (or the last feature release, |
|
which is a bit older than 'master'). This includes both |
|
enhancements and unobvious fixes to 'master'. 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"). |
|
|
|
- An unobvious fix meant for 'maint' is applied to a new |
|
topic branch that is forked from the tip of 'maint' (or the |
|
oldest and still relevant maintenance branch). The |
|
topic may be named as ai/maint-topic. |
|
|
|
- Changes that pertain to an existing topic are applied to |
|
the branch, but: |
|
|
|
- obviously correct ones are applied first; |
|
|
|
- questionable ones are discarded or applied to near the tip; |
|
|
|
- Replacement patches to an existing topic are accepted only |
|
for commits not in 'next'. |
|
|
|
The initial round is done with: |
|
|
|
$ git checkout ai/topic ;# or "git checkout -b ai/topic master" |
|
$ git am -sc3 mailbox |
|
|
|
and replacing an existing topic with subsequent round is done with: |
|
|
|
$ git checkout master...ai/topic ;# try to reapply to the same base |
|
$ git am -sc3 mailbox |
|
|
|
to prepare the new round on a detached HEAD, and then |
|
|
|
$ git range-diff @{-1}... |
|
$ git diff @{-1} |
|
|
|
to double check what changed since the last round, and finally |
|
|
|
$ git checkout -B @{-1} |
|
|
|
to conclude (the last step is why a topic already in 'next' is |
|
not replaced but updated incrementally). |
|
|
|
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. |
|
|
|
|
|
- Merge maint to master as needed: |
|
|
|
$ git checkout master |
|
$ git merge maint |
|
$ make test |
|
|
|
- Merge master to next as needed: |
|
|
|
$ git checkout next |
|
$ git merge master |
|
$ make test |
|
|
|
- Review the last issue of "What's cooking" again and see if topics |
|
that are ready to be merged to 'next' are still in good shape |
|
(e.g. has there any new issue identified on the list with the |
|
series?) |
|
|
|
- Prepare 'jch' branch, which is used to represent somewhere |
|
between 'master' and 'seen' and often is slightly ahead of 'next'. |
|
|
|
$ Meta/Reintegrate master..seen >Meta/redo-jch.sh |
|
|
|
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. |
|
|
|
- Now we are ready to start merging topics to 'next'. For each |
|
branch whose tip is not merged to 'next', one of three things can |
|
happen: |
|
|
|
- The commits are all next-worthy; merge the topic to next; |
|
- The new parts are of mixed quality, but earlier ones are |
|
next-worthy; merge the early parts to next; |
|
- Nothing is next-worthy; do not do anything. |
|
|
|
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: |
|
|
|
$ git checkout -B jch master |
|
$ Meta/redo-jch.sh -c1 |
|
|
|
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). |
|
|
|
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'. |
|
|
|
Then do the same to 'next' |
|
|
|
$ git checkout next |
|
$ sh Meta/redo-jch.sh -c1 -e |
|
|
|
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. |
|
|
|
$ git diff jch next |
|
|
|
When all is well, clean up the redo-jch.sh script with |
|
|
|
$ sh Meta/redo-jch.sh -u |
|
|
|
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. |
|
|
|
- Rebuild 'seen'. |
|
|
|
$ Meta/Reintegrate master..seen >Meta/redo-seen.sh |
|
|
|
Edit the result by adding new topics that are not still in 'seen' |
|
in the script. Then |
|
|
|
$ git checkout -B seen jch |
|
$ sh Meta/redo-seen.sh |
|
|
|
When all is well, clean up the redo-seen.sh script with |
|
|
|
$ sh Meta/redo-seen.sh -u |
|
|
|
Double check by running |
|
|
|
$ git branch --no-merged seen |
|
|
|
to see there is no unexpected leftover topics. |
|
|
|
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'. |
|
|
|
- Update "What's cooking" message to review the updates to |
|
existing topics, newly added topics and graduated topics. |
|
|
|
This step is helped with Meta/cook script. |
|
|
|
$ Meta/cook |
|
|
|
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 ">>". |
|
|
|
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 |
|
|
|
$ Meta/cook -w |
|
|
|
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). |
|
|
|
- Compile, test and install all four (five) integration branches; |
|
Meta/Dothem script may aid this step. |
|
|
|
- Format documentation if the 'master' branch was updated; |
|
Meta/dodoc.sh script may aid this step. |
|
|
|
- Push the integration branches out to public places; Meta/pushall |
|
script may aid this step. |
|
|
|
Observations |
|
------------ |
|
|
|
Some observations to be made. |
|
|
|
* Each topic is tested individually, and also together with other |
|
topics cooking first in 'seen', then in 'jch' and then in 'next'. |
|
Until it matures, no part of it is merged to 'master'. |
|
|
|
* A topic already in 'next' can get fixes while still in |
|
'next'. Such a topic will have many merges to 'next' (in |
|
other words, "git log --first-parent next" will show many |
|
"Merge branch 'ai/topic' to next" for the same topic. |
|
|
|
* An unobvious fix for 'maint' is cooked in 'next' and then |
|
merged to 'master' to make extra sure it is Ok and then |
|
merged to 'maint'. |
|
|
|
* Even when 'next' becomes empty (in other words, all topics |
|
prove stable and are merged to 'master' and "git diff master |
|
next" shows empty), it has tons of merge commits that will |
|
never be in 'master'. |
|
|
|
* 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). |
|
|
|
* Commits near the tip of a topic branch that are not in 'next' |
|
are fair game to be discarded, replaced or rewritten. |
|
Commits already merged to 'next' will not be. |
|
|
|
* Being in the 'next' branch is not a guarantee for a topic to |
|
be included in the next feature release. Being in the |
|
'master' branch typically is. |
|
|
|
* 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. |
|
|
|
|
|
Appendix |
|
-------- |
|
|
|
Preparing a "merge-fix" |
|
~~~~~~~~~~~~~~~~~~~~~~~ |
|
|
|
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. |
|
|
|
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, |
|
|
|
$ echo $X | Meta/Reintegrate |
|
|
|
is roughly equivalent to this sequence: |
|
|
|
$ git merge --rerere-autoupdate $X |
|
$ git commit |
|
$ git cherry-pick -n refs/merge-fix/$X |
|
$ git commit --amend |
|
|
|
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. |
|
|
|
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: |
|
|
|
$ 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 |
|
|
|
Then make a reference "refs/merge-fix/ai/topic" to point at this |
|
result: |
|
|
|
$ git update-ref refs/merge-fix/ai/topic HEAD |
|
|
|
Then double check the result by asking Meta/Reintegrate to redo the |
|
merge: |
|
|
|
$ git checkout seen~5 ;# the parent of the problem merge |
|
$ echo ai/topic | Meta/Reintegrate |
|
$ git diff seen~4 |
|
|
|
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. |
|
|
|
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: |
|
|
|
$ mf=refs/merge-fix |
|
$ git update-ref $mf/$the_other_branch $mf/ai/topic |
|
$ git update-ref -d $mf/ai/topic
|
|
|