%W% %K%

VA’s use of BK is falling apart because BK doesn’t support bringing in patches from the outside. The fact of life is that not everyone will use BK so we need to be able to deal with that.

What VA would like, I believe, is this:

Linux LOD - this contains nothing but the tarballs from Linus. This means we need to support repeated imports.

The ability to start new LODs at any point on the Linux LOD (this is for external patches which come in from the outside). They’d probably love it to death if you could take a patch and give it a range of revs and say "find the place where this patch applies the “best”" but that maybe going too far.

The ability to slurp the end of an LOD into another LOD and merge.

PATCH ISSUES

a) deletes & renames. Need a modified version of patch which does not delete files, it tells BK to delete them. Also needs to tell BK when it creates new files. We need a post processor which goes over the set of deletes and creates and detects renames.

[ZW] A decent first approximation is to co -l every s.file in the tree, apply the patch as normal, then recursively ci every modified file. If a file disappeared, that’s a delete. If a file appeared, that’s a create. A rename shows up as a delete plus a create, which is no worse than CVS. A slight improvement is to compare the list of deletes to the list of creates and try to detect renames - I wrote code several months ago that does this fairly well. A performance tweak is to preparse the patch and only checkout the files it touches.

Importing a tarball into an existing tree works exactly the same except that you replace the gfiles with the ones from the tarball. get -g can be used in this case to speed things up.

b) big chunks which fail - postpone this for now.

[ZW] Shouldn’t have to worry about this given a pristine LOD.

c) --norejects (also --search) options to patch. Suppose that we had a wrapper around patch which could take a patch file and wander through the tree looking for the versions of files which take the whole patch cleanly.

WORKING PRACTICE

a) Setup the pristine LOD for just releases from the maintainer (Linux LOD). Call this repository /proj/linux, lod name is "linux". If we have a mode on the repository, this repository is marked "No patch rejects".

b) Get a private repository for local stuff, setup a new lod, linux-va. bk clone linux walt bk newlod linux-va # starts a new LOD from whatever is TOT

c) New release comes from Linus. bk clone /proj/linux /proj/import # safety first, kids cd /proj/import bk import tarball --norejects -Slinux-2.3.134 linux-2.3.134.tgz This says "take this tarball, apply to top of trunk of the Linux LOD, tagging it with linux-2.3.134". .rej not allowed in this case.

[ZW] You can’t detect rejects with a tarball; you can with a patch.

d) Make sure it worked: bk export /proj/import /tmp/export mkdir /tmp/compare cd /tmp/compare untar linux-2.3.134.tgz cd /tmp diff -r export compare # Flame dev@bitkeeper.com when there is output from the diff command

f) Update the linux tree cd /proj/import bk push # it knows that /proj/linux is the parent

d) Bring new stuff into walt’s tree cd /proj/walt bk pull All this does, however, is add it the linux LOD stuff to Walt’s graph, it doesn’t merge.

e) Bring the linux changes into Walt’s LOD bk include -LLinux What this does is pretty much what a resync would do: 1) for each file which is unmodified in Walt’s LOD, just add the changes 2) for each file which is modified in Walt’s LOD, treat it like a conflict, and run the resolve process. 3) for each file which has moved in the linux LOD, move it in Walt’s LOD unless Walt’s LOD also moved, in which case prompt w/ conflict. 4) Create a changeset recording the merge.

[ZW] All this seems sane to me. There’s a lot of steps, though. I take it include is the general command to merge from one LOD to another?

BK ISSUES

bk diffs -u needs to generate exactly what diff would generate, we apparently get the headers wrong.

[ZW] This is a horrible can of worms. If you restrict yourself to gnu patch and gnu diffutils, there’s still four or five subtly different versions of each in widespread use. You don’t even want to consider supporting the diff and patch shipped with most commercial Unixes.

That said, we’re not that bad. There’s six rules for getting mostly-predictable behavior:

  1. Put exactly one line that cannot possibly be part of a patch chunk or header in between file diffs. The content is immaterial, it just has to match /[-+@ IP]/.

  2. Never generate Index: or Prereq: headers.

  3. The pathnames on the --- and + lines must be identical.

  4. The date stamp on the + line must be strictly after the date stamp on the --- line. (Except when deleting files - see below).

  5. The date stamps on each line must be ctime() format, and must both be in the same time zone.

  6. There can be no text between the pathname and the timestamp.

We get only #6 wrong.

===== resync.perl 1.51 vs edited =====
--- resync.perl 1.51    Thu Oct 21 14:30:21 1999
+++ resync.perl Thu Oct 21 14:18:03 1999

should be

===== resync.perl 1.51 vs edited =====
--- resync.perl Thu Oct 21 14:30:21 1999	1.51
+++ resync.perl Thu Oct 21 14:18:03 1999

We may also want to handle creating and deleting files with diffs. patch creates a file when it sees a diff like this:

===========================
--- new-file	     Wed Dec 31 16:00:00 1969
+++ new-file	     Thu Oct 21 14:45:16 1999
@@ -0,0 +1,4 @@
+ each
+ line in the
+ new
+ file

and deletes one when it sees a diff like this:

===========================
--- new-file	     Thu Oct 21 14:45:16 1999
+++ new-file	     Wed Dec 31 16:00:00 1969
@@ -1,4 +0,0 @@
- each
- line in the
- old
- file

Wed Dec 31 16:00:00 1969 is ctime() of the epoch. A delete is the only time the + timestamp can be before the --- timestamp.