Perforce Revision Control @(http://www.cs.usfca.edu/~parrt, Terence Parr) #### Introduction @(http://www.perforce.com/perforce/doc.031/manuals/p4guide/01_overview.html, Perforce) is a simple yet extremely powerful revision control system (_RCS_), whose purpose is to manage multiple people working on the same set of files. An RCS tracks all changes to a file so you can back up to prior versions. It also acts as a versioned back up scheme. Perforce uses a client-server architecture. You notify perforce when you want to add or edit files on your local disk and then, after doing your changes, you submit them to the central repository. At that time, another team member can sync his/her local disk to the updated repository. Programmers still work independently, but you share files via the central repository. Importantly, this "submit" is done as a single transaction. That means that if the submit fails for lack of net connection in the middle of the submit, perforce will roll back the submit command. You can try again later without worrying about doubly submitting files. #### Tasks ### Get a file into the system << $ cd ~/depot/test ~/USF/depot/test $ ls A.java B.java templates ~/USF/depot/test $ p4 add A.java //depot/test/A.java#1 - opened for add ~/USF/depot/test $ p4 add *.java //depot/test/A.java#1 - currently opened for add //depot/test/B.java#1 - opened for add ~/USF/depot/test $ p4 add templates/*.st //depot/test/templates/link.st#1 - opened for add //depot/test/templates/page.st#1 - opened for add >> At this point, you hvae 2 Java files and two template files in the _change list_. The depot won't commit these changes until you submit. When you type {p4 submit}, an editor pops up with the submit description file like this: << # A Perforce Change Specification. # ... Change: new Client: parrt.localhost User: parrt Status: new Description: add test files Files: //depot/test/A.java # add //depot/test/B.java # add //depot/test/templates/link.st # add //depot/test/templates/page.st # add >> You fill in the description and save/exit the file/editor. You'll see: << Change 6 created with 4 open file(s). Submitting change 6. Locking 4 files ... add //depot/test/A.java#1 add //depot/test/B.java#1 add //depot/test/templates/link.st#1 add //depot/test/templates/page.st#1 Change 6 submitted. >> ### Edit / submit file(s) File {A.java} just has a comment let's say: << /** A */ >> If you want to edit {A.java}, say this: << ~/USF/depot/test $ p4 edit A.java //depot/test/A.java#1 - opened for edit >> then edit {A.java} to be: << /** A */ public class A { } >> You can see what changes you've made since the last commited change: << ~/USF/depot/test $ p4 diff A.java ==== //depot/test/A.java#1 - /Users/parrt/USF/depot/test/A.java ==== 1a2,3 > public class A { > } >> To commit your changes, type this: << ~/USF/depot/test $ p4 submit >> You'll see an editor open with: << ... Description: Files: //depot/test/A.java # edit >> After saving/exiting, you'll see: << Change 7 created with 1 open file(s). Submitting change 7. Locking 1 files ... edit //depot/test/A.java#2 Change 7 submitted. >> ### Get change history for a file << ~/USF/depot/test $ p4 changes A.java Change 7 on 2003/10/21 by parrt@parrt.localhost 'added code ' Change 6 on 2003/10/21 by parrt@parrt.localhost 'add test files ' >> Using {p4 changes -u parrt A.java} limits listed changes to only those done by parrt. ### Delete a file Deleting a file is like an edit and can be reverted before committing it. << ~/USF/depot/test $ ls A.java B.java templates ~/USF/depot/test $ p4 delete B.java //depot/test/B.java#1 - opened for delete ~/USF/depot/test $ ls A.java templates ~/USF/depot/test $ p4 revert B.java //depot/test/B.java#1 - was delete, reverted ~/USF/depot/test $ ls A.java B.java templates >> To commit, use {p4 submit} as always. You can always bring the file back later. ### Rename or move a file Copy to new file, add that file, delete old one. This is the simplest way. << ~/USF/depot/test $ cp B.java C.java ~/USF/depot/test $ p4 add C.java //depot/test/C.java#1 - opened for add ~/USF/depot/test $ p4 delete B.java //depot/test/B.java#1 - opened for delete ~/USF/depot/test $ p4 submit Change 8 created with 2 open file(s). Submitting change 8. Locking 2 files ... delete //depot/test/B.java#2 add //depot/test/C.java#1 Change 8 submitted. ~/USF/depot/test $ ls A.java C.java templates >> ### Making sure your local disk is up-to-date << ~/USF/depot/test $ p4 sync File(s) up-to-date. >> Going to another box though with a depot->client mapping, you'll see: << [parrt@nexus depot]$ p4 info User name: parrt Client name: parrt.nfs Client host: nexus.cs.usfca.edu Client root: /home/parrt/depot ... [parrt@nexus depot]$ p4 sync //depot/test/A.java#2 - added as /home/parrt/depot/test/A.java //depot/test/C.java#1 - added as /home/parrt/depot/test/C.java //depot/test/templates/link.st#1 - added as /home/parrt/depot/test/templates/link.st //depot/test/templates/page.st#1 - added as /home/parrt/depot/test/templates/page.st >> ### Cutting a release You'll probably want to make a release for each 2 week project presentation so you know exactly what state your project was it at those stages. You'll use {p4 label}. See @(http://www.perforce.com/perforce/doc.031/manuals/p4guide/08_labels.html#1042406, Labels). ### File collisions Please read @(http://www.perforce.com/perforce/doc.031/manuals/p4guide/05_conflicts.html#1041981, Resolving File Conflicts). #### Processes ### Directory structure Underneath your {/home/user/depot} directory team members may set up whatever they want as far as structure. I suggest something like this: << src webmail managers PersistenceManager.java UserManager.java pages PageDispatcher.java mail MessagePage.java MessageListPage.java misc LoginPage.java support web images yourlogo.gif background.gif error.jsp scripts backup.sh logprocessing.sh lib templates page.st link.st pages home.page.st mail message.st summary.st misc login.st >> If you currently have all your code under the {/home/user/resin} directory, I suggest strongly that you move it. The only code related to the server is {webmail.PageDispatcher} and you should move your code to a nice directory structure like the above. Resin only needs to see things in your {CLASSPATH}. You'll also need to set resin's document root to be {/home/user/depot/web} or something so your images and other web-related files can be seen. ### When to submit to the depot The central respository is the place where you store a mostly working version of your code as you both make changes. Without doing real development branches, you must be careful about what you submit. You can't just change any file you want and submit as it might not even compile with the rest of the code. I suggest that, at minimum, you only submit code to the depot that compiles. What if your partner has modified file B.java in a way that will break A.java, which you are modifying? You must pull the updated B.java onto your computer and make A and B work together before submitting. In other words, you should always do a {p4 sync} and try to compile before submitting. The sequence goes like this: [ *user x* | *user y* ---- {p4 edit A.java} | {p4 edit B.java} ---- edits A.java | edits B.java ---- still editing | {p4 sync} (nothing from depot has changed) ---- still editing | {p4 submit B.java} (B.java changes in depot) ---- {p4 sync} (pulls in new B.java) | ... ---- {javac *.java} (compile errors; fixes A.java to suit B.java) | ... ---- {p4 submit A.java} | ... ] After a submit, the code will always at least compile. It would also be great if you tested your code before submitting so that your partner is not stuck solving your bugs and not doing his/her own work. #### Command summary [ *command* | *description* ---- {p4 help commands} | list all commands ---- {p4 help} _command_ | get help on _command_ ---- {p4 info} | Are my P4 parameters set properly? Is server up? ---- {p4 add file} | Announce intention to add a file to the depot ---- {p4 submit} | Submit all changes (add,edit,delete) to depot ---- {p4 submit dir/...} | Submit all changes (add,edit,delete) to depot from {dir} on down ---- {p4 sync} | Make my disk look like the depot (pulls in changes from your team members) ---- {p4 sync dir/...} | Make my disk look like the depot from {dir} on down team members ---- {p4 revert file} | Throw away changes you have made to that file ---- {p4 changes file} | describe changes made to this file ---- {p4 resolve -as} | if nothing conflicts, this "safe" resolve just works You will have to do "p4 resolve" after this to do conflicts that -as couldn't handle automatically. ---- {p4 resolve} | find out what didn't resolve ] #### Client Management ### How perforces know what the depot<->local-disk mapping is I have set up a user account in the perforce depot and a client for each user called _user_{.nfs}. The _user_ is your _user_@cs.usfca.edu name. Your client looks like: << Client: .nfs Owner: Root: /home//depot/main View: //depot/cs601/group/main/... //.nfs/... >> which means that the {groupN/main} directory for cs601 in the central repository is mapped to your {/home/user/depot/main} directory. The reason for the {main} subdirectory will become clear when we discuss branching. (by the way, that is the @(http://www.stringtemplate.org, StringTemplate) I used to generate all of your clients automatically .) I have set up the protections as follows: << write group group1 * //depot/cs601/group1/... write group group2 * //depot/cs601/group2/... write group group3 * //depot/cs601/group3/... write group group4 * //depot/cs601/group4/... write group group5 * //depot/cs601/group5/... write group group6 * //depot/cs601/group6/... write group group7 * //depot/cs601/group7/... write group group8 * //depot/cs601/group8/... write group group9 * //depot/cs601/group9/... write group group10 * //depot/cs601/group10/... write group group11 * //depot/cs601/group11/... write group group12 * //depot/cs601/group12/... write group group13 * //depot/cs601/group13/... >> meaning for example, that {group3} members only has access to {//depot/cs601/group3} and below. _Please set your password by using_ {p4 user} _command!_ ### How perforce knows which depot to talk to You must have file {/home/}_user_{/depot/.p4} with the following info: << P4CLIENT=user.nfs P4USER=user P4PASSWD= P4PORT=phantom:1666 >> For perforce to know to look in this "hidden" file (due to the prefix of a dot), you must have << export P4CONFIG='.p4' >> in your .bash\_profile or whatever. With this set up, then you cannot accidentally add files outside of {/home/}_user_{/depot/...} directory subtree.