Merge with mpm
authorBrendan Cully <brendan@kublai.com>
Wed, 25 Oct 2006 15:10:30 -0700
changeset 3538 54246ac4b652
parent 3537 060aefba4459 (current diff)
parent 3514 355f2a85ea23 (diff)
child 3539 a6dd7ab568cc
Merge with mpm
comparison.txt
notes.txt
rewrite-log
--- a/README	Wed Oct 25 15:08:40 2006 -0700
+++ b/README	Wed Oct 25 15:10:30 2006 -0700
@@ -37,7 +37,6 @@
  $ cd project
                        # copy files in, edit them
  $ hg add              # add all unknown files
- $ hg remove --after   # remove deleted files
  $ hg commit           # commit all changes, edit changelog entry
 
  Mercurial will look for a file named .hgignore in the root of your
@@ -46,36 +45,30 @@
 
 Branching and merging:
 
- $ hg clone linux linux-work    # create a new branch
- $ cd linux-work
+ $ hg clone project project-work    # create a new branch
+ $ cd project-work
  $ <make changes>
  $ hg commit
- $ cd ../linux
- $ hg pull ../linux-work     # pull changesets from linux-work
- $ hg merge                  # merge the new tip from linux-work into
+ $ cd ../project
+ $ hg pull ../project-work   # pull changesets from project-work
+ $ hg merge                  # merge the new tip from project-work into
                              # our working directory
  $ hg commit                 # commit the result of the merge
 
 Importing patches:
 
- Fast:
+ Simple:
  $ patch < ../p/foo.patch
  $ hg commit -A
 
- Faster:
- $ patch < ../p/foo.patch
- $ hg commit `lsdiff -p1 ../p/foo.patch`
-
- Fastest:
+ Fast:
  $ cat ../p/patchlist | xargs hg import -p1 -b ../p
 
 Exporting a patch:
 
  (make changes)
  $ hg commit
- $ hg tip
- 28237:747a537bd090880c29eae861df4d81b245aa0190
- $ hg export 28237 > foo.patch    # export changeset 28237
+ $ hg export tip > foo.patch    # export latest change
 
 Network support:
 
--- a/comparison.txt	Wed Oct 25 15:08:40 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-                    Mercurial      git                     BK (*)
-storage             revlog delta   compressed revisions    SCCS weave
-storage naming      by filename    by revision hash        by filename
-merge               file DAGs      changeset DAG           file DAGs?
-consistency         SHA1           SHA1                    CRC
-signable?           yes            yes                     no
-
-retrieve file tip   O(1)           O(1)                    O(revs)
-add rev             O(1)           O(1)                    O(revs)
-find prev file rev  O(1)           O(changesets)           O(revs)
-annotate file       O(revs)        O(changesets)           O(revs)
-find file changeset O(1)           O(changesets)           ?
-
-checkout            O(files)       O(files)                O(revs)?
-commit              O(changes)     O(changes)              ?
-                    6 patches/s    6 patches/s             slow
-diff working dir    O(changes)     O(changes)              ?
-                    < 1s           < 1s                    ?
-tree diff revs      O(changes)     O(changes)              ?
-                    < 1s           < 1s                    ?
-hardlink clone      O(files)       O(revisions)            O(files)
-
-find remote csets   O(log new)     rsync: O(revisions)     ?
-                                   git-http: O(changesets)
-pull remote csets   O(patch)       O(modified files)       O(patch)
-
-repo growth         O(patch)       O(revisions)            O(patch)
- kernel history     300M           3.5G?                   250M?
-lines of code       2500           6500 (+ cogito)         ??
-
-* I've never used BK so this is just guesses
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/rewrite-log	Wed Oct 25 15:10:30 2006 -0700
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+import sys, os
+from mercurial import hg
+
+f = sys.argv[1]
+
+r1 = hg.revlog(open, f + ".i", f + ".d")
+r2 = hg.revlog(open, f + ".i2", f + ".d2")
+
+tr = hg.transaction(open, "journal")
+
+for i in xrange(r1.count()):
+    n = r1.node(i)
+    p1, p2 = r1.parents(n)
+    l = r1.linkrev(n)
+    t = r1.revision(n)
+    n2 = r2.addrevision(t, tr, l, p1, p2)
+tr.close()
+
+os.rename(f + ".i", f + ".i.old")
+os.rename(f + ".d", f + ".d.old")
+os.rename(f + ".i2", f + ".i")
+os.rename(f + ".d2", f + ".d")
--- a/notes.txt	Wed Oct 25 15:08:40 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,146 +0,0 @@
-Some notes about Mercurial's design
-
-Revlogs:
-
-The fundamental storage type in Mercurial is a "revlog". A revlog is
-the set of all revisions to a file. Each revision is either stored
-compressed in its entirety or as a compressed binary delta against the
-previous version. The decision of when to store a full version is made
-based on how much data would be needed to reconstruct the file. This
-lets us ensure that we never need to read huge amounts of data to
-reconstruct a file, regardless of how many revisions of it we store.
-
-In fact, we should always be able to do it with a single read,
-provided we know when and where to read. This is where the index comes
-in. Each revlog has an index containing a special hash (nodeid) of the
-text, hashes for its parents, and where and how much of the revlog
-data we need to read to reconstruct it. Thus, with one read of the
-index and one read of the data, we can reconstruct any version in time
-proportional to the file size.
-
-Similarly, revlogs and their indices are append-only. This means that
-adding a new version is also O(1) seeks.
-
-Generally revlogs are used to represent revisions of files, but they
-also are used to represent manifests and changesets.
-
-Manifests:
-
-A manifest is simply a list of all files in a given revision of a
-project along with the nodeids of the corresponding file revisions. So
-grabbing a given version of the project means simply looking up its
-manifest and reconstruction all the file revisions pointed to by it.
-
-Changesets:
-
-A changeset is a list of all files changed in a check-in along with a
-change description and some metadata like user and date. It also
-contains a nodeid to the relevent revision of the manifest. Changesets
-and manifests are one-to-one, but contain different data for
-convenience.
-
-Nodeids:
-
-Nodeids are unique ids that are used to represent the contents of a
-file AND its position in the project history. That is, if you change a
-file and then change it back, the result will have a different nodeid
-because it has different history. This is accomplished by including
-the parents of a given revision's nodeids with the revision's text
-when calculating the hash.
-
-Graph merging:
-
-Nodeids are implemented as they are to simplify merging. Merging a
-pair of directed acyclic graphs (aka "the family tree" of the file
-history) requires some method of determining if nodes in different
-graphs correspond. Simply comparing the contents of the node (by
-comparing text of given revisions or their hashes) can get confused by
-identical revisions in the tree.
-
-The nodeid approach makes it trivial - the hash uniquely describes a
-revision's contents and its graph position relative to the root, so
-merge is simply checking whether each nodeid in graph A is in the hash
-table of graph B. If not, we pull them in, adding them sequentially to
-the revlog.
-
-Branching and merging:
-
-Everything in Mercurial is potentially a branch and every user
-effectively works in their own branch. When you do a checkout,
-Mercurial remembers what the parent changeset was and uses it for the
-next check in.
-
-To do a merge of branches in Mercurial, you check out the heads of the
-two branches into the same working directory which causes a merge to
-be performed, and then check in the result once you're happy with it.
-The resulting checkin will have two parents.
-
-It decides when a merge is necessary by first determining if there are
-any uncommitted changes in the working directory. This effectively
-makes the working directory a branch off the checked in version it's
-based on. Then it also determines if the working directory is a direct
-ancestor or descendent of the second version we're attempting to
-checkout. If neither is true, we simply replace the working directory
-version with the new version. Otherwise we perform a merge between the
-two versions.
-
-Merging files and manifests:
-
-We begin by comparing two versions manifests and deciding which files
-need to be added, deleted, and merged.
-
-Then for each file, we perform a graph merge and resolve as above.
-It's important to merge files using per-file DAGs rather than just
-changeset level DAGs as this diagram illustrates:
-
-M   M1   M2
-
-AB
- |`-------v     M2 clones M
-aB       AB     file A is change in mainline
- |`---v  AB'    file B is changed in M2
- |   aB / |     M1 clones M
- |   ab/  |     M1 changes B
- |   ab'  |     M1 merges from M2, changes to B conflict
- |    |  A'B'   M2 changes A
-  `---+--.|
-      |  a'B'   M2 merges from mainline, changes to A conflict
-      `--.|
-         ???    depending on which ancestor we choose, we will have
-	        to redo A hand-merge, B hand-merge, or both
-                but if we look at the files independently, everything
-		is fine
-
-The result is a merged version in the working directory, waiting for
-check-in.
-
-Rollback:
-
-When performing a commit or a merge, we order things so that the
-changeset entry gets added last. We keep a transaction log of the name
-of each file touched and its length prior to the transaction. On
-abort, we simply truncate each file to its prior length. This is one
-of the nice properties of the append-only structure of the revlogs.
-We can also reuse this journal for "rollback".
-
-Merging between repositories:
-
-One of the key features of Mercurial is the ability to merge between
-independent repositories in a decentralized fashion. Each repository
-can act as a read-only server or a client. Clients operating by
-pulling all branches that it hasn't seen from the server and adding
-them into its graph. This is done in two steps: searching for new
-"roots" and pulling a "changegroup"
-
-Searching for new "roots" begins by finding all new heads and
-searching backwards from those heads to the first unknown nodes in
-their respective branches. These nodes are the 'roots' that are used
-to calculate the 'changegroup': the set of all changesets starting at
-those roots. Mercurial takes pains to make this search efficient in
-both bandwidth and round-trips.
-
-Once the roots are found, the changegroup can be transferred as a
-single streaming transfer. This is organized as an ordered set of
-deltas for changesets, manifests, and files. Large chunks of deltas
-can be directly added to the repository without unpacking so it's
-fairly fast.
--- a/rewrite-log	Wed Oct 25 15:08:40 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-#!/usr/bin/env python
-import sys, os
-from mercurial import hg
-
-f = sys.argv[1]
-
-r1 = hg.revlog(open, f + ".i", f + ".d")
-r2 = hg.revlog(open, f + ".i2", f + ".d2")
-
-tr = hg.transaction(open, "journal")
-
-for i in xrange(r1.count()):
-    n = r1.node(i)
-    p1, p2 = r1.parents(n)
-    l = r1.linkrev(n)
-    t = r1.revision(n)
-    n2 = r2.addrevision(t, tr, l, p1, p2)
-tr.close()
-
-os.rename(f + ".i", f + ".i.old")
-os.rename(f + ".d", f + ".d.old")
-os.rename(f + ".i2", f + ".i")
-os.rename(f + ".d2", f + ".d")