See Tom's tutorial if you're new to arch. Once you've become familiar with that, you can refer to this page for a quick reminder of how something works.
These recipes assume you've called tla my-id "Your Name <you@your.com>" already. They start basic and become more advanced near the bottom.
Contents
- Quickies
- Create an archive
- Create a package
- Normal editing cycle
- What Has Changed?
- Create a branch
- Switch to a branch
- Publish your archive
- Export a tree
- Get a local copy of another archive
- Handling conflicts
- Grab and build tla itself
- Maintain your own version of another project
- Fixing your own mistakes
- Merge one project into another
- Make a local branch of a tree offline
- Backing out a changeset
- Deleting Revisions
Quickies
- List the contents of someone else's archive
tla abrowse -A some@one.elses--archive
- Find the archive and version of a local tree
tla tree-version
- Find the tree you most recently tagged from
tla ancestry
maybe?
- Remove all arch-related files from a tree
find . \( -name "{arch}" -o -name ".arch-ids" -o -name ".arch-inventory" \) -print0 | xargs -0 rm -rf
- De-register an archive
tla register-archive -d myarchive
- Generate an empty log file
tla make-log
See LogFile elsewhere.
- Read the log file of a revision, in a tree
tla cat-log revision
where revision is something like base-0 or patch-3
- Read the log file of a revision, outside a tree
tla cat-archive-log category--branch--version--revision
- Read the log file of a revision, using a revision library
tla library-log category--branch--version--revision
Create an archive
This is the arch equivalent of creating a CVS repository. In the example below, your archive will be named my@id.net--projects and stored in ~/arch/example. Calling my-default-archive causes it to be used as the default for all further examples (otherwise you'd have to supply -A to each command).
$ mkdir ~/arch $ tla make-archive my@id.net--example ~/arch/example $ tla my-default-archive my@id.net--example
Use tla archives to verify that it exists. You can move your archive using normal filesystem commands if you then call tla register-archive -f new/location. Try not to! Anybody else who is using your archive will have to call register-archive again as well.
Create a package
This is the loose equivalent of creating a CVS module (collection of source code files). It assumes that you are starting from scratch. The project is called myproject, you will work on branch "main" and the initial version is 0.1.
$ tla archive-setup myproject--main--0.1 $ mkdir myprojectdir $ cd myprojectdir $ tla init-tree myproject--main--0.1 $ vi nothing.c $ tla add nothing.c $ tla import
Normal editing cycle
It's probably best to call tla make-log immediately after committing. This way you can maintain/ edit the commit message for your _next_ changeset while you do your work.
$ tla add new-file $ vi $(tla make-log) $ tla mv oldname newname $ vi ./++log... $ tla commit
In tla 1.2, there is a tla rm equivalent of tla mv. For previous versions, though, you need to rm file then tla delete file manually.
Quick commits
Sometimes, you've made such a small change that a full log is overkill, or you've merged from another tree and only want to provide a one-line summary. To help with this, tla commit provides the --summary option:
john@shell% tla commit -s 'print hello 5 times instead of 1'
M ./hello.py
* update pristine tree (john@doe.com--myarchive/hello--dev--1.0--base-0
=> hello--dev--1.0--patch-1)
* commited john@doe.com--myarchive/hello--dev--1.0--patch-1
If you've merged anything, this will also include the output of Tla Reference/log-for-merge in the patch log.
What Has Changed?
Find the current status of my project-tree:
tla changes; tla tree-lint; tla missing
It isn't strictly a "what changed" list, it also shows files that Arch doesn't know how to classify.
See each subtopic below:
What Files Have I Changed?
Before committing your changeset (Glossary#changeset) you may want to look over it, to make sure that it is correct, that you haven't left any testing code in, and to help you write the summary for commit.
To do this for the entire project-tree, Arch provides a command called changes (Tla Reference/changes)
john@shell% tla changes M ./hello.py
This tells you that hello.py has been modified (M).
What Are My Edits to those Files?
In order to properly look over the change, you may want to see the difference between the version in the archive and your changes. To do this for the entire project-tree, you can use the --diffs argument to Tla Reference/changes:
john@shell% tla changes --diffs M ./hello.py * modified files --- orig/hello.py +++ mod/hello.py @@ -1,3 +1,4 @@ #!/usr/bin/env python -print "hello" +for i in range(5): + print "hello"
This indicates that one line has been removed, and two added.
To get the diff for a single file, use tla file-diffs (Tla Reference/file-diffs).
Note that these commands used a cached copy of the latest archive version, called a pristine tree (pristine, because it is an unmodified version of the latest revision). This is especially useful for disconnected operation - you don't have access to the archive to be able to see what you've changed.
What files Haven't I Told Arch about?
Files you haven't told Arch about yet:
tla tree-lint
This will list all various problems, including files that are not permitted in the tree, and files that would be source if they had an ID. Use the .arch-inventory file (in each directory) to explicitly classify files as junk, etc. (See Configuring Inventory Categories.) Use tla add Tla Reference/add) to add files to the archive.
What files are different in the archive?
You can find out the revisions (patches) you don't have yet, though this doesn't tell you which files have been changed by someone else:
tla missing
How do you find which files have been changed by someone else?
How do I ignore whitespace in diffs?
Q: "tla changes --diff" and "tla file-diff" give a patch, which includes white-space changes. I want to see meaningful differences, so I like to ignore those white-space changes (like re-tabbing, etc.). How do I see get a diff ignoring white-space?
A: Use version tla 1.3.4+, the "diff" command Tla Reference/diff which via the -D option accepts custom diff options as used by the stand alone diff tool:
tla diff -D -b -- file.c tla diff -D -b -D -w -D -B
the second line passes the '-b -w -B' options to diff.
A: Get the patch for the file-of-interest, create a temporary old-version, diff ignoring whitespace:
tla file-diff myFile.txt > tmp.patch patch -R -o tmp.old myFile.txt tmp.patch diff -w tmp.old myFile.txt (and remove the tmp files when done)
Create a branch
To create a new branch from the current tree's revision, you can use
$ tla tag --setup $(tla logs -f | tail -n 1) project-name--branch-name--1.0
Note: the argument to tail -n 1 is the digit ONE, not the letter L.
Subcommand $(tla logs -f | tail -n 1) gets the last (via tail) full patch name, i.e. something of the form author@host.ext--archive/project--branch--version--revision. This practically lets you specify the last patch in the old branch/revision as the starting point for your new branch/revision.
Switch to a branch
To switch to --- or join --- a new branch new-branch you can do:
export branch=project-name--new-branch--1.0 &&
tla apply-delta $(tla logs -f | tail -n 1) \
$(tla revisions -f $branch | tail -n 1) &&
tla set-tree-version $branch
Note: the argument to tail -n 1 is the digit ONE, not the letter L. If you do much programming, you may want to use a font makes a clear distinction between 1 and l, 0 and O.
Subcommand $(tla logs -f | tail -n 1) gets the last (via tail) fully-qualified revision name for the current directory, something of the form author@host.ext--archive/project--branch--version--patchlevel. This practically lets you specify the last revision you committed in the old branch/revision as the starting point for the deltas to be applied.
Subcommand $(tla revisions -f $branch | tail -n 1) does a similar job for the target branch. But instead of using the last revision you committed in the tree, it uses the latest revision in the archive.
Note: in simple cases (such as updating an anonymous working copy across branches), you can just
tla star-merge $branch tla set-tree-version $branch
Publish your archive
There comes a time when you'll want to make your archive available to others. There's a multitude of ways of doing this. One of the most common is to sftp it up to a dedicated server.
First you must prepare your archive for mirroring. You can omit --listing if you're sure that nobody will ever access this mirror using HTTP (all other protocols provide directory listings and therefore don't need .listing files). The /home/sbronson/public_html directory must already exist and 2004 must not. make-archive does not populate the archive so you still need to call archive-mirror.
$ tla make-archive --listing --mirror sb@rinspin.com--2004 \
sftp://sbronson@sourcecontrol.net/home/sbronson/public_html/2004
If you check tla archives you'll notice that a sb@rinspin.com--2004-MIRROR archive has been registered. Every time you want to send your local changes up to the mirror you can just run the archive-mirror command.
tla archive-mirror sb@rinspin.com--2004
Export a tree
These scripts should be run from the root of the tree.
Equivalent of "cvs export my-module"
The simple way, which works if you do not have any source file whose name contains whitespace or, generally, any character that is subject to pika escaping:
tla inventory -sB | tar -cf - --no-recursion -T- | (mkdir my-package; cd my-package; tar xf -)
The more complicated way, that handles files with spaces and even newlines in the name, but is much slower
mkdir ../my-package tla inventory -sB | while read esc do echo -ne "$(tla escape --unescaped $esc)\0" done | cpio -pl0 ../my-package
Create a tarball from the archive
The simple way, which works if you do not have any source file whose name contains whitespace or, generally, any character that is subject to pika escaping:
tla get myproject--stable myproject tla inventory -sB myproject | tar -czf myproject-a.b.c.tar.gz --no-recursion -T-
To create a tarball which may contain spaces and other pika-escaped chars in file names:
tla get myproject--stable myproject tla inventory -sB myproject | while read esc do tla escape --unescaped $esc ; echo done | tar -czf myproject-a.b.c.tar.gz --no-recursion -T-
To create a tarball which may contain newlines in file names, you cannot use tar directly because it cannot accept a null-delimited ../list of file names::
tla get myproject--stable myproject.orig mkdir ../myproject cd myproject.orig tla inventory -sB | while read esc do echo -ne "$(tla escape --unescaped $esc)\0" done | cpio -pl0 ../myproject cd .. tar czf myproject-a.b.c.tar.gz myproject
Get a local copy of another archive
Arch users frequently publish their archives on the net. It is very easy to pull down a copy of someone else's archive, so you can work with it on your own machine. All you need to do is register the location of the archive with tla:
tla register-archive http://quackerhead.com/~duff/{archive}/cduffy@spamcop.net--2003-quackerhead/
Normally, you should only specify the archive location. tla will auto-detect its name. Once the archive is registered, you can simply grab a copy like this:
cd ~/src tla get cduffy@spamcop.net--2003/cscvs--experimental--1.1 cscvs
This will download the experimental 1.1 version of cscvs from the specified archive, and store it in the cscvs directory. From this point you can build the source, compile, patch and hack on the code.
Handling conflicts
You can use the --three-way or -t option to star-merge to save merge conflicts as diff3 conflict markers, in way similar to what CVS does.
More generally, some editors have facilities to Process *.rej files. This is more general because star-merge is only applicable when merging revisions which share a common ancestor.
Grab and build tla itself
This demonstrates how tla uses configurations to collect a number of different versions (like hackerlab) and build them into one big project.
We will use an out-of-tree build (the object files will not be stored alongside the source files) in the =build directory. Calling it =build tells arch that it's a precious file: it's not source but it cannot be deleted.
$ tla register-archive http://mirrors.sourcecontrol.net/lord@emf.net--2004 $ tla get lord@emf.net--2004/dists--devo tla-1.1 $ cd tla-1.1 $ tla build-config configs/emf.net/devo.tla $ mkdir =build $ cd \=build $ ../src/configure $ make
If make succeeds, the new tla binary is in tla/tla/tla.
tla build-config takes a configuration file that specifies what trees to check out in the specified directories. devo.tla is a configuration file that specifies the latest tla sources. Other configuration files appear to specify specific tla revisions (in emf.net-tla) and other projects entirely.
Maintain your own version of another project
Let's say that you'd like to add your frob script to the contrib tree. The contrib tree is currently maintained in the jblack@inframix.com--2004 archive.
Tag the official version in your archive
You will maintain your changes in your own archive in a version named tlacontrib--frob--1.2.
$ tla register-archive http://arch.linuxguru.net/~jblack/{archives}/2004
$ tla archive-setup tlacontrib--frob--1.2
$ tla tag jblack@inframix.com--2004/tlacontrib--devo--1.2 tlacontrib--frob--1.2
$ tla get tlacontrib--frob--1.2 bashcmpl
It caches the base-0 revision automatically (not the same base-0 as in the original archive, but the current patch level!), so that tla doesn't have to go back to jblack's archive every time it needs to create a full souce tree. It uses more disk space, but it makes network errors less catastrophic. You can avoid it with the --no-cacherev option to tla's tag command. Use it at your own discretion.
Make your changes locally
You can now perform the typical edit/commit cycle on your version until you're happy with it.
Discover if the remote archive has changes
It's a very real possibility that development on jblack's version is continuing while you edit your version locally.
Use tla missing to discover if the remote repository has changes.
$ cd ~/wd/tlacontrib--frob $ tla missing jblack@inframix.com--2004/tlacontrib--devo--1.2 patch-6
This means that you are missing patch-6 from jblack's version.
Merge remote changes into your archive
To keep merge conflicts to a minimum, you should ensure that your tree is as up-to-date as possible before contributing your changes. There are a number of techniques to bring your local archive up-to-date with respect to the remote one while preserving your changes. The simplest to use is probably star-merge.
$ tla star-merge jblack@inframix.com--2004/tlacontrib--devo--1.2
You may also need to use replay, possibly even with --skip-present. The specifics are too complex to explain here. See Merging with Arch.
$ tla replay --skip-present -A jblack@inframix.com--2004 tlacontrib--devo--1.2 $ vi $(tla make-log) $ tla commit
The replay may have generated conflicts so beware.
Contribute your changes
Now that you're done, how do you push your changes to jblack? Typically, you publish your archive somewhere where he can get to it (see "Publishing your archive" above). Once he's able to access it, send an email asking him to merge your changes back into his tree. In this particular case you should CC the gnu-arch-users@gnu.org mailing list as well.
Let's say you make some changes on your local branch that are specific to you (patch-20). Then you do some more work that is very useful to jblack (patch-21). Jblack takes this work and integrates it into his archive (note: jblack is not taking patch-20): (Is the following block of code executed by jblack? I presume so.)
# Apply the changes $ tla replay tlacontrib--frob--1.2--patch-21 # Add all patch-logs from your tlacontrib branch, # so patches that won't be applied aren't considered "missing" $ tla sync-tree tlacontrib--frob--1.2--patch-21
Then you want to integrate jblack's most recent changes into your code. You do this by:
$ tla star-merge jblack@inframix.com--2004/tlacontrib--devo--1.2
Fixing your own mistakes
Undoing changes to a single file
You've accidentally modified a file. After running tla file-diffs hello.c, and carefully checking that you wanted to discard all the changes, you can run
tla file-diffs hello.c | patch -R
Or, if the file has been deleted (and its id didn't come from a tagline),
touch hello.c tla file-diffs hello.c | patch -R
If you're in a different directory from the file you're patching, use
tla file-diffs hellodir/hello.c | patch -R hellodir/hello.c
(-p1 will only work in the tree-root.)
For an undelete that works with all id methods, try
#find the current tree revision currev=$(tla logs -f|tail -n1) #ensure the desired revision is present tla library-add $currev #copy the library version of the desired revision cp $(tla library-file hello.c $currev) .
Note that this will undo only content modification, not renames, permissions changes, ...
More complex undo can be done using tla undo.
Undoing metadata changes
If tla changes is showing files with metadata (permissions) changes, and you only want to commit your modifications to the content of the files, what you can do is:
- apply the changes
- undo the changes
- delete the permission changes from the undo changeset
- redo the changes.
$ tla undo -o ,,metadata-fixup $ find ./,,metadata-fixup -type f -name '*.meta-mod' -print0 | xargs -0 rm $ find ./,,metadata-fixup -type f -name '*.meta-orig' -print0 | xargs -0 rm $ find ./,,metadata-fixup -type f -name '=dir-meta-orig' -print0 | xargs -0 rm $ find ./,,metadata-fixup -type f -name '=dir-meta-mod' -print0 | xargs -0 rm $ tla redo ,,metadata-fixup
Fix up changes applied to wrong tree
Say for example that you tla get a source tree from an archive mirror, and start hacking on it. After you have made a bunch of changes, you realize that you cannot commit the changes back, as the originating archive was a mirror. You really should have created a new branch to commit the changes on. You can use the command tla undo to revert the tree back to its original revision, and save the changeset. You can then move this changeset elsewhere, make a branch (or whatever fixup is required). Then you use the tla redo command to reapply the changes to the new source tree, after which you can commit. The command sequence is:
tla undo -o /path/to/other-tree/,hacking cd /path/to/other-tree tla redo ,hacking
Now the changes should be re-applied to the new tree.
If you forgot to make a branch
Say that you checked out someone's project, started making small changes and then saw that it would take more serious hacking (that you perhaps want to contribute back). But you can't commit to the original archive. So you have to create a branch when you already have changes in working tree. Then in your working tree simply do:
tla tag $(tla logs -r -f | head -n 1) your--new--version tla sync-tree your--new--version--base-0 tla set-tree-version your--new--version
If you have aba wrapper from tla-contrib, the branch-this subcommand will do it for you.
Fix merge accidentally combined with unrelated changes
Say you start to merge, and then you accidentally start making unrelated changes to the project tree. How do you separate the two sets of changes?
# undo all your changes $ tla undo # Now do the merge over again $ tla star-merge #or replay, or apply-delta
Now fix up any conflicts, the way you did last time.
# make the merge log $ $EDITOR $(tla log-for-merge >> $(tla make-log)) # commit $ tla commit # For example purposes, we'll say you just committed foo--bar--patch-23 # Undo the revision you just committed $ tla replay --reverse foo--bar--patch-23 # Restore your previous set of changes (which included the merge) $ tla redo # Restore the patch logs from the merge $ tla sync-tree foo--bar--patch--23 # Verify only the non-merge changes are shown: tla changes --diffs
You're out of the woods now. You may need to make a few changes if you solved the conflicts differently, e.g. whitespace differences. You can make further changes or commit.
Undo star-merge
As an alternative to the method above ("Fix merge accidentally combined with unrelated changes") the following (taken from aba's "star-merge-undo" script) is even simpler:
tla undo tla star-merge --changes $tmp/merge-undo tla redo tla apply-changeset --reverse $tmp/merge-undo $(tla tree-root) rm -Rf $tmp/merge-undo
I used this where I had a working tree, in which I had various changes (that I'd forgotten about) and then performed a tla star-merge, which obviously combined my changes with the star-merge. I used the above technique to undo the star-merge.
Fix already committed changes on a wrong branch
This is a generic method of reversing (cancelling) changes that are already present and committed in your source tree. First cancel the changes with replay, then mark them as present with sync-tree:
$ tla replay --reverse patch--to-be--removed $ tla sync-tree patch--to-be--removed $ tla commit -s "cancelled patch--to-be--removed"
Alternatively, you can use the --out-of-date-ok option of commit:
$ tla replay --reverse patch--to-be--removed $ tla commit --out-of-date-ok -s "cancelled patch--to-be--removed"
Merge one project into another
Let's say you created a small project named tla-bash-complete. Things changed however, and now you wish that you had made it a subdirectory in the tlacontrib--devo--1.2 project. You now want to merge all the files and change history from tla-bash-complete into tlacontrib. Easy enough:
$ tla get sb@bogus.example.com/tla-contrib--devo--1.2 tlacontrib
$ (cd tlacontrib && mkdir bash-complete && tla add-id bash-complete)
$ tla get sb@bogus.example.com/tla-bash-complete--sb--1.0 sb
$ cd sb
$ ls
README TODO gen-tla-commands tla-bash-complete
$ cp README TODO gen-tla-commands tla-bash-complete ../tlacontrib/bash-complete
$ cp .arch-ids/README.id \
.arch-ids/TODO.id \
.arch-ids/gen-tla-commands.id \
.arch-ids/tla-bash-complete.id \
../tlacontrib/bash-complete/.arch-ids
$ cd ../tlacontrib
$ tla sync-tree sb@bogus.example.com/tla-bash-complete--sb--1.0
$ tla log-for-merge >> $(tla make-log)
$ tla commit
You need to ensure that the inventory IDs did not change during the copy (use tla inventory --ids, see ID-tagging methods for more). To keep merging simple, you should ensure that you copy ALL files from project A into project B. You can delete any that you don't want in another commit after the merge. One change per commit.
Now, if someone branches from the now obsolete tla-bash-complete--sb--1.0, makes some changes, and asks you to merge them into your tree, you can just "tla star-merge tla-bash-complete--other-person--1.0" into tlacontrib as if it were still the original tree. At first it seems like that shouldn't work at all -- you're trying to merge changes from one project into a totally different project! But, of course, they're not totally different. As long as you were careful to maintain the inventory IDs then, as far as Arch is concerned, they're now equivalent. You can merge changesets from either ancestor into the combined tree as if it was itself
Doing the opposite -- forking one project into two -- should be obvious. Create the new archive and tag it from the original. Then delete all the files you don't want from each archive and then commit. Now you have two separate archives that share a common ancestor.
Make a local branch of a tree offline
Suppose that you used tla get jblack@inframix.com--2004/tlacontrib--devo--1.2 to obtain an archive from web and now you go offline. You have not mirrored the archive and want to make a branch in your local archive.
If you do not want to destroy the tree you just downloaded, make a copy of the tree:
cp -a tlacontrib--devo--1.2 tlacontrib--mycopy--1.2
Switch to the tree directory. Following commands will create a local branch and convert the tree directory to your local branch.
tla archive-setup tlacontrib--mycopy--1.2 tla set-tree-version tlacontrib--mycopy--1.2 tla add-log-version tlacontrib--mycopy--1.2 tla import
If you want to update your local branch, just use tla star-merge jblack@inframix.com--2004/tlacontrib--devo--1.2 and commit.
Eeeeeeeew. Making a branch without using tag? I'm just a newbie, but doesn't this break the connection to the source archive (i.e. no CONTINUATION file)? Is there a way to do this any better? Does having no continuation file have any significant effect? Does it really matter that the patch log entry this new import generates lists all the source files as new files? Is there a way to go in afterwards and make tla think this branch really is a continuation? Why am I so confused?
I think I'm so confused because there are different ways to accomplish things that appear, on the surface, to be the same, but I can't shake the feeling that these different actions have effects that are subtly different and will come back to bite me later. The lack of thorough documentation doesn't help. Like, what is the significance of the different patch log versions in a tree? When is it OK to remove them? What's the difference between a package and a version? Things like that.
Backing out a changeset
If you've committed a change that you decide you don't like, you can back it out by replaying the offending patch in reverse, then syncing your tree to the latest version. In this example, the most recent changeset, patch-10, gets applied in reverse (which has the effect of removing the patch-10 patch log) and then sync-tree restores the patch log.
tla replay --reverse $(tla tree-version)--patch-10 tla sync-tree $(tla tree-version)--patch-10
At that point, a tla changes --diffs should show you the reversed changeset and the file contents are back to how they were in patch-9.
Deleting Revisions
See Changing History
