Note: This document is an incomplete draft of a proposal for a design for adding "merge history" to CVS. This would allow you to do multiple merges between the same two branches without getting artificial conflicts.
I have not officially announced this idea anywhere. Maybe someday I will decide to commit the time to actually implement this, and as the first steps I will finish this document and announce it on the mailing list.
Update (Jan 2004): My current thoughts are:
START INTRODUCTION:
One weakness with CVS is that it doesn't automatically keep track
of merges, so if you want to continue development on a branch
after it has already been merged into the main branch, it requires
a lot of careful manual tracking of what was merged when (using tags)
so that you can cleanly merge the new branch development later without
getting conflicts from the already merged changes.
So I am seriously thinking about adding merge tracking capabilities
to CVS.
- This occasionally comes up in the mailing list. It is also
mentioned in the TODO list (item 39).
- Is there any chance this could make it into CVS proper?
I probably won't bother unless there is some assurance that
it will make it in as long as it is done well.
CVS definately seems to be in a "no new features" mode, with
only a few people working on bug fixes part time. It doesn't
look particularly likely for any large change to make it in,
no matter how useful it might be...
The brief version of this proposal is to add a newphrase to
the RCS file format to record whenever a merge is done, and
modifiy the default single -j "update -j" common-ancestor search
algorithm to take into account previous merge history.
This idea is expanded on in a fair amount of detail below.
If anyone has any additional thoughts or concerns, let me know.
END INTRODUCTION.
==========================
HERE: Update sourceforge, add links, .
================================================
Expanded Version:
Index:
- Introduction.
- Use cases.
- Future extension ideas (not intended to be in original patch)
- UI changes brainstorm.
- A theoretical, extendable way to represent a merge.
- Specific ways to encode merge info in real files and protocols.
- Internal design of changes.
- Development plan.
================================================
Use case A. Basic:
1. Developers develop some software on the main branch.
2. It is time for release, so they create a release branch. They
start fixing bugs and cutting releases off the branch.
3. New features continue to be developed on the main branch.
4. You think you are done with the release branch, so you merge
the fixes into the main branch, and you intend to drop the
old branch.
[When you do the 'cvs update -j', it automatically
remembers (in your sandbox) some details about what was merged.
When you commit it, that info is automatically stored in a
newphrase of the RCS file.]
5. Oops, you are still supporting the old release, and someone
just found some more problems. So you fix the problems on
the release branch.
6. Now you want to merge the fixes into the main branch as well.
All you do is a simple "cvs update -j RELEASE_BRANCH", and
it automatically takes the earlier merge into account when
calculating which version to use as the common ancestor.
[Specifically, it uses what was the old head of the release
branch as the new common ancestor.]
================================================
Use case B. Backport:
1. Developers develop some software on the main branch.
2. It is time for release, so they create a release branch. They
start fixing bugs and cutting releases off the branch.
3. New features continue to be developed on the main branch.
4. The main branch is currently unstable, but there is one relatively
simple feature in it that customers really want now. So you go
in and carfully merge the few files needed for that feature
from the main branch to the release branch.
[Again, merge details are transiently remembered in your
sandbox, and then later added to the RCS file.]
5. You continue development on the main branch.
6. Now you want to merge the release branch into the main branch.
All you do is a simple "cvs update -j RELEASE_BRANCH", and
it automatically takes the earlier merge into account when
calculating which version to use as the common ancestor.
================================================
Use case C. External Tools
0. [This is kind of a generalization of the "vendor branch import"
support in cvs already, but it should avoid some of the problems,
and support merges in both directions without conflicts.
No changes will be made to the existing vendor branch support.
Instead, it just provides hooks that external tools can use.
The external tools (not part of the proposed patch) would
treat multiple different repositories as different branches in
one big meta-repository. The patch would support ways for
those tools to inject extra merge info about the merges done
in the meta-repository.
So the external tool would use CVS as follows:]
1. The tool starts with 2 sandboxes, tied to the source and
destination of the merge.
[Perhaps an advanced tool could talk client/server protocol
directly, but we'll ignore that possibility.]
2. It searches them to find all controlled files in either one.
Then for each file it does the following:
3. The script pulls out the full version tree and merge history for
the file from both reposititories (using some cvs command(s) and parsing
the output). Then it combines the version trees and merge histories,
and seatches them to find what to use as the common ancestor.
4. It use 'cvs update -P' to get a copy of the common ancestor, and
perform the merge.
5. It uses some cvs commands to register the details of the merge
in the target sandbox. It uses an extended syntax to distinquish
other-repository versions from local versions.
(In might also add useful merge info fron the target
repository to the source repository.)
6. The user can test it, fix it, and commit as usual.
[Some scripts may want the user to use a special tool
to commit, particularly if the target repository is for
a system that can't acknowledge external merges.]
================================================
Mini use cases:
D1. If a patched client asks an old server to do a merge,
the new client should warn the user that it
won't properly record the merge: the server should be
upgraded and the merge redone. But continue the merge
anyways.
D2. If an old client asks a new server to do a merge, the new server
should warn the user that it won't properly record the merge:
the client should be upgraded and the merge redone. But continue
the merge anyways.
D3. If new client commits to an old server, and there are merge
records scheduled to be added, recover as gracefully as
possilble:
Maybe: abort the merge (unless -f is selected?)
Or: Do the merge, output a warning, and leave the merge records
in the sandbox to try again on the next commit (marked to
the actual version instead of floating with the sandbox
version...)?
D4. When the merge record is added to the sandboxes, refer to the
target as "checkedout", not a specific version number. Only
tie to a specific version when you actually comit a specific version.
This way the user can continue doing updates prior to committing,
and get the right result.
D5. Fix Up Merge History: The user will sometimes want to manually
add, remove, or change merge history information.
================================================
================================================
================================================
Future use case E: Rename a File
0. This will not be part of the patch I write. Maybe it will be
added in the future.
1. Developers develop some software on the main branch.
2. It is time for release, so they create a release branch. They
start fixing bugs and cutting releases off the branch.
3. On the main branch, you are doing massive cleanup, including
renaming many of the files. You use a special "cvs move"
command to rename the files, and it remembers some specialized
merge history information into both old and new files so
that tools can automatically follow the rename.
4. You are done with the release branch, so you merge
the fixes into the main branch. You use some special
option to 'cvs update' that causes it to follow the merge
history back to the old file in order to the find the changes
made on the branch. [Of course, it also records this new merge...]
5. Then you commit, and it remembers the merge so you could do it
again.
================================================
Future use case F: Merge Holes
0. This will not be part of the patch.
I intend to store merge history in enough detail that
in the future CVS could be extended to handle this case
correctly without changing the merge history
schema, but for now I'm not going to try to deal
with the multiple sub-merges for one user-requested merge,
or the possibility of N-way merge conflicts.
Instead (see below), it will simply treat "GoodChanges" as the
common ancestor, having the effect of erroneously removing
the UnrelatedChanges from the main branch. (At least the
changes are still in version history, so they could be
manually re-merged...)
1. Developers develop some software on the main branch.
2. It is time for release, so they create a release branch. They
start fixing bugs and cutting releases off the branch.
3. New features continue to be developed on the main branch.
4. The main branch is currently unstable, but there is one relatively
simple feature in it that customers really want now. But
the version tree currently looks like:
Base ------ UnrelatedChanges -------- GoodChanges
\
\------ BugFixes
So while working on the release branch, the user
does something like 'cvs update -jUnrelatedChanges -jGoodChanges FILE'.
Now the tree looks like:
Base ------ UnrelatedChanges -------- GoodChanges ------ MoreChanges
\ |
\ |
\ \|/
\------ BugFixes -------- MergedGoodChanges ------ MoreFixes
But not depicted in this picture is the fact that UnrelatedChanges
were *not* merged into MergedGoodChanges.
[These diagrams are kind of sloppy in distinguishing
actual versions from deltas between versions, but you should be
able to get the overall idea anyways...]
5. Now you want to merge the release branch into the main branch.
All you do is a simple "cvs update -j RELEASE_BRANCH", and
it automatically takes the earlier merge into account when
calculating which version to use as the common ancestor.
The merge history and merge algorithms are smart enough that cvs
will merge "BugFixes" and "MoreFixes" into the main branch,
but *not* merge MergeGoodChanges (since those changes
are already applied...).
================================================
Future miscellaneous semi-related changes:
0. None of these will be part of the patch...
See also .../WishList.txt (HERE), which expands on some of
these ideas and also includes some unrelated ideas.
G1. Add a per-version "mergetype" newphrase to the RCS file.
It would be used to look up (in some config file) plugin merge
algorithms to use instead of the default one. Give the config
format some way to resolve different "mergetypes" in one merge.
Have some mechanism to configure default mergetypes for new
files (or old files missing "mergetype").
Always do auto merge on server, but also support sending
the "from" and "ancestor" files to client for use by an optional
interactive client-side merge algorithm. It should be possible
to configure the client to automatically invoke such a thing
when possible.
I also have vague ideas of implementing a generic, bidirection
communications "tunnel" for the client/server protocol, that
could be used by things server-side interactive merge tools,
or an rsync-based file transfer subsystem.
G2. Add a per-version "keywordexpansion" newphrase to the RCS file
that takes precedence over the main file setting.
If you delete and readd a particular file name with a
totally different type, the old and new files can have different
keywordexpansion modes...
G3. Add a "conditionally override -k" to checkout and/or update,
that can be generically instructed to only override -k in
certain ways (for example, never override -kb).
G4. Add a "meta-operation log" newphrase to the RCS format that
records details about various meta-operations like adding and
removing tags. Theoretically, if a tag is erroneously removed,
this could be used to figure out specifically how to fix it.
G5. Patch management. I've got various ideas for making it so
CVS could help automate tracking multiple independent
"changesets", provide me with a combined view of
all the "changesets", yet being able to "commit" additional
changes to a specific changeset only. I get the impression
that BitKeeper may have some support for this, but I don't know
a whole lot about how it does it.
G6. Alternate/better rename idea: The files in a directory would be
controlled by a special "CVS/dir,v" file in the repository,
where each version of CVS/dir is a list of which RCS files
contribute to that version of the directory (ideally it would
only reference local RCS files, but might sometimes reference
ones in other directories). Carefully maintain backwards
compatibility in the absense of a CVS/dir,v file. (I've
got more ideas, like how to handle hard links cleanly; this is
just a summary. See the wishlist link above.)
This is conceptually cleaner then recording "merge history"
between different files, but the need to maintain backwards
compatibility and the significant internal redesign of CVS
that would likely be needed makes it so this probably isn't
practical. It might be best to drop client/server
compatibility for this, and overhaul a large chunk of the
CVS code.
G7. One specific instance of a specialize multi-system merge tool:
Be able to merge among multiple sandboxes tied to the same
repository (usefull for things like trying changes on both
UNIX and NT before committing.). See HERE for a tool
that kind of supports this, but doesn't really manage
merging...
================================================
================================================
================================================
Possible User Interface Changes:
Some of this is very tentative.
1. "cvs update -j [-j]" will record in the sandbox that a merge occured
2. "cvs update -j" will by default use the smarter algorithm for finding
a the common ancestor. But you can still get the old algorithm
with some new option (--ancestor-algorthm=treeOnly?)
3. "cvs update -C", or any time update replaces a missing file, it
will clear out any merge history info stored in the sandbox that
mentions the CHECKEDOUT version of that file.
4. What if 'cvs update" notices that a file is unmodified, but is
marked as having been merged? Should it warn the user? Clear out
the merge info automatically (probably not)? Report it as modified
(perhaps with a little m?)?
5. "cvs commit" will copy the sandbox merge history at the
same time it is committing the file.
6. What if 'cvs commit' notices an unmodified file that is marked
as having been merged? Should it abort the merge (unless
some kind of override option is set)? Should it drop the
merge info (probably not)? Should it write a new (unchanged)
version and point the merge history at that?
Should it just add the merge info to the file, without adding
new versions (probably best)?
7. "cvs status" should probably mention any sandbox merge history state
somehow.
8. "cvs log" should probably add a section to report merge history.
Should it be there by defualt?
9. Add a "cvs arrow" command with sub-commands for adding, removing,
and listing.
Include an option to control weather to save it in the sandbox
(for a later commit), or send it directly to the RCS file.
Possibly just go with "cvs log" changes for listing, but probably
not.
Possibly enhance "cvs admin" with new options for add/remove,
but probably no.
10. Maybe or maybe not: A "cvs decode" command that reads the output of
other commands (like "cvs log"), decodes the output, and then
outputs a specificaly asked for piece of information out of it.
This could allow scripts to easily and robustly parse the
output of a command. It would often be faster then adding
detailed queries to ("cvs log") [avoid repeated overhead of
client/server and reading a large RCS file], but not as fast as
a program internally parsing the output.
It could also be used to convert "escaped" strings back into
pure binary data (see 8-bit clean discussion lower down).
11. Maybe give "cvs tag" some options for tagging versions based
on searching the version tree? Perhaps "tag the common ancestor
that would be used for a specified merge", or "find the a merge
entry that matches a query, and tag the from, to, or
ancestor revision mentioned in that merge".
(FUTURE, not part of initial patch.)
#HERE: Expand on the above?
================================================
================================================
================================================
Theoretical representation for merges.
The representation I intend to use will store the version numbers
of the "from", "to" and "common ancestor" versions of the file for
every merge ever done involving that file. Also arbitrary name
value pairs (date, comment, (see below).).
Names will be match the RE "[A-Za-z_][A-Za-z_0-9]*" (like
C identifiers; or a subset of valid RCS "id"s.
#####
HERE: dropping default contributer to a version. Alternate locators.
MergeName (if the user wants to give a big, important merge a name
for some reason?)
Required:
from - The version number of the source of the merge.
to - The version number of the result of the merge.
ancestor - The common ancestor that was used for the merge.
Optional
ignoreParent - Normally defaults to 0 (though mayb the
default should be 1 when it is dead?)
When 1, don't consider the parent of the "to"
version to be to be a direct ancestor of the "to"
version.
comment - If the user wants a comment to go with the merge...
id - Some sort of name for the merge (might be queried for...)
HERE: Something to say "treat this as the direct ancestor".
A user supplied comment for the ", "id", "date", "user", ...
#####
Version numbers deserve some clarification:
1. If it looks like an RCS version number, then it refers to a
version of the same file.
2. If it is "CHECKEDOUT", it refers to the version currently
checked out and will be bound to a specific version when
the file is committed.
2. If it is anything else, then it refers to something external,
in another file, another repository, or even a completely
different version control system.
Naming convention for external versions is something like
"scheme:SCHEME_SPECIFIC_INFO". Model the after URLs: access
method/what kind of repository, where the repository is,
what file within that repository, what version of that file.
Issues:
- Relative references. If refering to another file in the
same repository, robustness would suggest that a relative
path is best (then you can relocate the repository without
breaking internal references). But that complicates checking
if multiple things represent the same file. Internally,
it would probably need to transiently normalize all
references to absolute references...
- UUIDs vs "current location" vs both to find files...
Clearcase at least uses UUIDs to refer to files. But
the ability to look things up by UUID may be missing
from the UI (I'm not sure), and certainly trying to
manually read a history using UUID references would be
difficult.
But if you try to use "current location", how would
tools handle it if it moved?
One desirable property of external version references
is that they be normalized (or easily/generically
normalizable) so that the string can uniquely ID a node
in the version graph without needing to know how to decod
the string. That doesn't work so well if you use CCase
rename capabilities.
A possibility is to use UUIDs in the from and to properties,
and have seperate path_from/path_to settings to record
the expected pathname at that location...
HERE: Expand on this some more.
#####
String representation also deserves some attention.
I think it is worth the time to carefully consider
how to encode strings so they can store any arbitrary 8 bit
data. (Although I don't think it is a good idea to actually use
that capability...)
1. Characters that need to be escaped probably include [\n\0\r"@],
anything that is "non-printable", and whatever character is
used for escaping.
2. Unicode: Essentially ignore it. Just store a stream of
bytes that is "typically" interpreted as IEEE (HERE) like the
rest of CVS. If someone wants to store unicode, the
8-bit-cleanliness means they can use any encoding they want,
though they may need to intercept and massage the output...
3. Three input encoding schemes are:
- Fully encode a supplied, unencoded byte stream.
When getting data directly from the user on a clean
channel, have this as an option selectable by command line
flags...
- Partial encoding: Except for the escape character, escape
all special characters. The escape character is left as
is, as long as it is part of a valid escape sequence.
The idea here is to allow a defensive programming strategy
where we always partially encode any string coming from an
external source, even if it is *supposed* to already be
encoded. If it really is encoded, the partial encoding
does nothing, but if it somehow is *not* encoded, partial
encoding it can protect you...
- Pre-encoded (no encoding): There should never
be a reason to assume the string is properly pre-encoded.
Use partial encoding instead.
4. Output encodings:
- Internally (including in RCS files), the string is stored
and manipulated in encoded format.
- Normally (and especially if output as part of a larger construct),
output strings in encoded format.
- Perhaps a "cvs decode" command that takes an encoded
string (either on standard input or on the command line)
and outputs the original binary string on standard output
would be useful?
4. Newlines are an issue:
- When decoding, be able to ignore unescaped newlines.
- For some forms of output, you don't want newlines at all.
(easier parsing by scripts...)
- For other forms of output, adding ignored real newlines next
to the encoded newlines can make the output more readable
but harder to parse.
- Can't be relied upon anyways ["\n" vs "\r\n" are often hosed
up by whatever tools you happen to be using].
5. Options:
- C style escapes. "\n\0"
- quoted-printable style escapes. "=0a=00"
- XML/HTML style escapes. "
�" HERE: correct?
--------------------
Alternate representation:
(I'm not planning on using this representation.)
- Subversion gives each version a list of all version deltas that
have been accounted for in that version.
I suspect my representation can theoretically represent about
the same information as the representation above (with reasonable
conversions between the representations), but I kind of like
a representation that closely resembles the input (the actual
merges performed).
- I believe clearcase is more limited: I think it only remembers the
from and to versions of a merge, not the common ancestor.
On the other hand, the initial common ancestor search algorithm
I have in mind is probably going to only use the "from" and
"to" versions of past merges. But storing more details
would allow future enhancements to be smarter.
================================================
================================================
================================================
Specifics of storing merges in sandbox, repository, and client/server
protocol. It might be useful to use the same format for
more then one thing (for example, output a fragment of an
RCS file in a CVS/mergeHistory file in the sandbox).
----------------
RCS:
(For context, see "man rcsfile")
Add a newphrase "merges" to the "delta" section of the RCS file,
as shown in the following addition to the RCS file grammer:
<admin> ::= # [snip] ...
merges { <mergeInfo> { : <mergeInfo> }* } ;
{ <newphrase> }*
<mergeInfo> ::= { <infoItemName> <infoValueValue> }+
<infoItemName> ::= <id>
<infoItemValue> ::= <string> | <id> | <num>
Alternatives:
- I considerred storing the merges to (or from?) version X
in the "delta" section for version X, but it doesn't seem
like a properly normalized representation (possibilities of
inconsistencies, etc). It also doesn't
eliminate the issue of storing multiple merges in one section
of the file, with each merge needing multiple name/value
pairs.
- I also considerred using one newphrase per merge, but that
would require multiple instances of the same newphrase
in one section of the RCS file, and:
a. There are no provisions for that in the existing format.
(See how locks and symbols (tags) are handled...)
b. I wouldn't be suprised if some RCS file parsers
can't manage multiple instances of a single newphrase.
Questions:
- Is there some semi-official registrar of newphrases that
people have added to RCS, to make sure I don't conflict with any
body else's extensions?
- Does anybody know of any other merge history extensions anyone
has added to RCS that I should try to be able to interoperate
with?
----------------
Sandbox:
I'm leaning towards using a new admin file (CVS/mergeHistory) that
just stores the relevent data fragment from one of the other
representations. I'll use whichever one seems easiest to factor
out.
Ooops: Needs to store a fragment per file, with additional
info to identify the file that each fragment is for.
----------------
Client/server protocol:
- I'm thinking of making sure there is no line length limit and that
the encoded form of the strings don't have any newlines,
and then just passing each merge in a form like:
"mergeHist ${var}=\"${value}\" ${var}="${value}" ...\n"
This will be recognized both client->server and server->client.
The file it applies to will be derived from context.
HERE: more details
----------------
Command line:
When a name/value pair needs to be specified on the command line,
each name/value pair will specified as something like:
--set NAME=VALUE # Fully encode value
--setEnc NAME=ENCODED_VALUE # Partially encode value.
--setD NAME=DATE # Use version number that goes with DATE.
--setR NAME=TAG # Use version number that goes with TAG.
--setRD NAME=BRANCH:DATE # Use version number for date on branch.
Of course, cvs update -j will automatically set all required names,
but they can be overridden or more added if desired.
----------------
CVS log output:
HERE
merge:
name="value"
name="value"
name="value"
merge:
name="value"
name="value"
name="value"
Values will appear in encoded format, no newlines. It is intended to
be easy to pull out the values with simple RE based parsers. (Nothing
tricky for embedded newlines, quotes, etc.)
================================================
================================================
================================================
Internal design:
- A new file will be created to house the common ancestor search
algorithm, and other merge history related functions.
In new code I'll try to aim for the reentrancy desire
expressed in the HACKING file.
- Things like I/O routines for various formats may go
in existing files (for those I/O formats) or in the new file,
depending on where it seems to fit best.
- Obviously changes to specific cvs subcommands will go in the
file for that subcommand.
- New cvs subcommands (cvs mergeHistory or something) will
get their own files (for high level code); lower level code
may go into the generic new file with the search algorithm...
- I think the RCS code can read and write newphrases already,
so I don't need to do much to it (except verify that it can
handle newphrases.)
Search Algorithm:
- First, create a combined directed graph from the version tree
and the "from" and "to" versions of all historical merges (both
from the RCS file and from the sandbox admin files).
- Now search the graph for the "closest" common predecessor.
This will likely be a relatively small part of the patch,
that will be easily changed or replaced as desired, but basic
dificulties are:
- Define "closest":
- Number of transitions?
- Sum of some kind of transition weights?
- Consider version tree common ancestor A and
a nearer ancestor B that happens to be common via a
long series of merges and changes through several
different branches. Even though B likely has
more transitions, it is still probably a better
choice then A for the common ancestor.
- Only consider direct ancestors as candidates; choose
the closest one that is any kind of ancestor of
the other version?
- External versions:
- It probably can't use an external version as any contributer
to the merge (although future changes (not part of this initial
proposal) might implement the ability to ask an
external plugin for a copy of the indicated external
version...).
- The simplest thing is to ignore transitions involving
external versions completely. They are only for use
by external tools.
- On the other hand, perhaps it would be useful to be able
to transition through external versions during the search
for the best internal common ancestor.
================================================
================================================
================================================
Splitting Up the Patch Into Subpatches:
- Smaller patches are often desired.
- Prerequisite bugfixes found during development will be
split off.
//HERE: Reorganize:
Application Options:
1. Build it as one big monolithic patch. It will still be developed
in the lean order, but trying to organize the patch in that way
is not practical, unless pieces of the patch are regularly applied
to the official source.
2. Build as one big patch, but prior to application, attempt to
seperate it as much as possible into distinct subpatches for
easier chewing.
//HERE: What subpatches might be possible.
3. Submit incremental patches regularly, which someone will apply
nearly as often as I generate them.
//HERE: incremental patches that might be submitted.
How to split up a megapatch:
- The main patch would need to include the low level search
algorithm; read/write routines for various protocols/file
formats; and enhancements to the update.c and commit.c
[This would be the bulk of the changes regardless...]
- "cvs mergeHistory" and other new subcommands could probably
be seperate, if desired. [Though it doesn't seem likely you
would want to apply the main patch but not this one...]
- Other loosely related changes would also be seperate.
[depending on how loosely and/or how embedded they are
in the same parts of the code as the main patch...]
A tentative development strategy is listed below.
If regular small merges into the source tree can be arranged,
incremental patches might be applied regularly during
this plan:
- Make any fixes to make sure that it can read/write RCS files with
arbitrary newphrases without messing them up. Also do some
tests of RCS itself... If problems are found, come up with
transition strategies when access may be made when
working with old versions of CVS and/or RCS...
- Add an initial UI facility to add/remove merge history entries
directly to the RCS file (local only, for now).
Put some effort into a good interface up front, but it is
subject to change during development.
- Add in sandbox admin file capabilities to temporarily remember merge
history entries, and make "commit" copy those entries into
the RCS file. (Initial testing will depend on manually adding
those entries to the sandbox admin files.) [Initially only support
direct repository access.]
- Extend commit to handle merge histroy over the client/server
protocol.
- When a merge is done, have "cvs update" record a merge history
entry in the sandbox admin files.
- Have "cvs update -j" (single -j) use a merge history aware
algorithm for deciding the common ancestor to use.
- Possibly experiment with different algorithms, maybe
even allowing plugin algorithms.
- Go through the new UIs, clean them up, and finalize them.
If not already done, support:
- Directly changing merge history immediately.
- Scheduling merge history changes for the next commit.
- Arguments to update to support optional merge history
attributes.
- Arguments to update to control algorithm to use for searching
for common ancestor: (at least 2 algorithms: the new default
merge-history-aware algorithm, and the old (current) algorithm)
Finish up the test cases and documentation. And do any final
cleanup of the code changes.
- Look into optional, loosely related enhancements (other merge
history mechanisms, UI for encoding/decoding strings, etc).
This is tentative. Test cases should be developed fairly soon
(facilitate development). Documentation may take a bit longer
then test cases (initially somewhat fluid interface, and docs aren't
much use during initial development), but should not be
delayed too long.
My impression is that some open source owners prefer to merge
things using this strategy. But it definately takes regular and consistent
attention by someone with commit access to the tree, plus at least
some degree of faith in the long term strategy:
merging things that aren't immediately useful (having commit copy
history entries from the sandbox to the RCS file is not useful
when there is not yet an automated way to get those entries into
the sandbox in the first place...)
HERE: somewhere:
HERE: If tag not found internally, search externally referenced (by
merge history) items.
HERE: Extended tags reference external versions?
================================================
================================================
================================================
GARBAGE OBSOLETE
### I don't like this because it means either redundant info
### (a "to" value vs the delta number) and the corresponding
### potential for inconsistencies, or it means that one attribute
### of the a merge record comes from outside the record.
#<delta> ::= <num>
# # [snip] ...
# next { <num> };
# merges <mergeInfo> { : <mergeInfo> }* ;
# { <newphrase> }*
#########################
OR:
# (One newphrase per merge) But the existing grammer doesn't
# use multiple same-named phrases at all...
<admin> ::=
# [snip] ...
{ merge { <nameValue> }+ ; }*
<nameValue> ::= <id> : <value>
<value> ::= <id> | <num> | <string>
The reluctance to incorporate patches may be overreaction to
past problems: Burned by the PreservePermissions stuff, and as far
as I can tell, nothing major has been merged in since then (just small
bugfixes). As direct experience, I've helped with the
"advisory lock patch" (HERE: Link). As far as I know it
meets all the requirements mentioned in HACKING, but no
one is jumping to incorporate it.