CS46B Lab 6

Copyright © Cay S. Horstmann 2010, 2012 Creative Commons License
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License.

Objectives

Learning Outcomes

Estimated time: Two lab sessions

A. Installation—Do this BEFORE the lab

  1. Install Mercurial, following these directions:

    To test that your installation was successful, open a terminal window and type

    hg --version

    If you get a version number and copyright notice, the installation was successful.

  2. You need to tell Mercurial who you are. With a text editor (not Notepad), create a file ~/.hgrc (that is a file with the five-character name .hgrc in the home directory ~). Be sure to remember the dot at the start of the file name.

    Windows users: Remember that ~ is c:\cygwin\home\yourname in the Windows file system.

    Windows users: Don't type ~ in EmacsW32. It interprets it as the Emacs home directory.

    Add these lines:

    [ui]
    username=Your name <username@mailserver.com>
    merge=internal:merge

    (of course, replacing Your name with your name and username@mailserver.com with your email address).

  3. Make a public SSH key. First check whether you already have one.
    ls ~/.ssh

    If you get a directory listing showing (among others) a file id_rsa.pub, then skip to step 5.

    Otherwise run

    ssh-keygen -t rsa -C "Your name <username@mailserver.com>"

    (of course, replacing Your name with your name and username@mailserver.com with your email address). When prompted for a passphrase, you can enter a passphrase, which is more secure, but you have to enter it whenever you use the key. Or just hit Enter to skip this.

    Do not change the name of the key that is being generated. It should be id_rsa.

  4. Type
    cat ~/.ssh/id_rsa.pub

    Copy the text (starting with ssh-rsa and ending with Your name <username@mailserver.com> and paste it into an email message to your instructor. This key is needed to allow you access to the Mercurial server (in Step E).

  5. Bring a USB stick to the lab.

B. Creating a Local Repository

A version control system remembers the changes that you made to the files in a project. This is useful (even essential) for two reasons:

The database that contains the changes to a project is called a repository. When you interact with a version control system, you contribute your changes to a repository, fetch the latest changes that are contributed by others, or occasionally undo some changes.

Many version control systems are in common use. In this lab, you will learn about a modern version control system called Mercurial. Mercurial is particularly well suited for learning about version control systems. It is so easy to use that it is painless to set up a local repository on your hard disk, but it scales to extremely large projects. For example, the source code for the Java development kit is contained in a very large Mercurial repository.

  1. You can continue with the code from Lab 5, or start over with this code—download, unzip, rename the directory to lab6, and import it into NetBeans.

    Open a terminal window and use the cd command to change to the directory containing the project. (That is, the directory containing the src and nbproject subdirectories.)

    Using a text editor (not Notepad!), create a file .hgignore in that directory with the following contents.

    syntax: glob
    build
    dist
    nbproject
    build.xml
    manifest.mf

    Now run

    hg init
    hg status

    What output do you get?

    Windows users: If you get errors about unavailable resources, try the "rebaseall" procedure described in this thread. Or switch to using the Linux virtual machine and repeat the steps starting from part A.

  2. The hg command interacts with a Mercurial repository. (Hg is the chemical symbol for the element Mercury.)

    The hg init command initializes a repository. You issue it once when you start a project, or when you decide to add version control to an existing project.

    The hg status command shows the current status of the files in your project. At the beginning, you get a listing such as

    ? .hgignore
    ? src/AddressBook.java
    ? src/AddressBookDemo.java
    ? src/ArrayListAddressBook.java
    ? src/ConsoleInOut.java
    ? src/InOut.java
    ? src/Item.java
    ? src/WindowInOut.java

    The ? indicates that these files are unmanaged. Tell Mercurial that you want to add them:

    hg add

    This command adds all files in all subdirectories that are not excluded in the .hgignore file.

    Now run hg status again. What output do you get?

    Occasionally, you need to remove files and tell Mercurial that you don't want them to be a part of your project anymore. Then you use the hg remove command. The moral is: Mercurial doesn't automatically manage every file in your project directory. You tell it which ones you want to save.

  3. The A next to each file means that these files will be added when you make the next “commit” to the repository. Do it now:
    hg commit -m "initial checkin"

    The -m option is required. Put a brief message describing the reason for the commit. (You usually commit after adding a feature or fixing a bug.)

    Some people like to put longer commit comments, describing the commited change in detail. That is best done from an IDE—see Part C.

    Now run hg status again. What output do you get?

  4. When hg status has nothing to report, then all files are up-to-date.

    Edit the file src/AddressBook.java in NetBeans. Make some change; for example, remove the first javadoc comment. Save the file.

    Now run hg status again. What output do you get?

  5. The M indicates that the file has been changed and is different from the version in the repository.

    Run hg commit again. Now the repository contains both the original version and your latest changes.

    To see the difference between them, run

    hg serve

    and point your web browser to http://localhost:8000.

    What happens?

    Windows users: If you don't see the repo, your firewall probably blocks port 8000. If you don't know how to control your Windows firewall, switch to using the Linux virtual machine and repeat the steps starting from part A.

  6. Click around until you can see the old version of the src/AddressBook.java file.

    How can you get it without the line numbers?

    If you ever need the old file back, you can copy/paste it from the browser, or you can use the Mercurial revert command. That is more convenient inside NetBeans—see section C.

    You have just seen one reason to use a version control system: To get an old version of a file back. It's as if your file system had an undo button!

    (But remember, you must enable the undo by periodically running hg commit. You can only revert to committed versions.)

    Hit Ctrl + C to stop the hg serve process.

  7. Finally, let's find out where Mercurial stores the repository. Run
    find 

    You will see the src subdirectory containing your files, and next to it, a .hg directory containing the repository data.

C. Using Mercurial in NetBeans

Windows users need to install a separate Mercurial implementation from http://bitbucket.org/tortoisehg/thg-winbuild/downloads/ before this part of the lab. Just download and run the installer. (Unfortunately, NetBeans does not work with the Mercurial program in Cygwin.)

  1. In NetBeans, right-click on the project name in the Projects tab and check that there is a menu option Mercurial.

    If not, try these things:

    If all else fails, ask your lab assistant or instructor for help.

  2. In NetBeans, make a change in PhoneDirectory.java (such as adding your name to @author). Save your file and look at the Projects tab.

    What do you notice about the file name?

  3. Now right-click on the project and select Mercurial -> Commit. You will get a dialog such as this one.

    It lists the file(s) that have changed and you can type a commit message that is as detailed as you like.

    Type an appropriate message and click Commit.

    When you add files, they show up in green. NetBeans automatically issues an hg add before committing them.

  4. That's the most common step of working with Mercurial in NetBeans. Do your work and whenever you want to save a snapshot (which should be every few hours), right-click the project (not just a single file) and select Commit.

    Once in a while, you may want to know how one of your local files differs from the repository.

    Make a change to InOut.java, such as adding a comment explaining the purpose of the interface. Then right-click on the file in the Projects tab and select Mercurial -> Diff. You will see a graphical display of the differences.

  5. Right-click on InOut.java and select Mercurial -> Show History. You'll get a display of all versions of the file, together with the differences between successive versions.

    How do you get back an older version?

    (Try it out. First commit the current version, just in case you mess up, then try reverting to an older one.)

    As a rule of thumb, it is a good idea to use the command line for “big ticket” commands, such as hg init and hg clone. (Lots of things can go wrong with these, and the IDE often hides the error messages, making it hard to diagnose what is going on.) Common commands such as hg commit and hg revert are most convenient in the IDE.

D. Collaborating with Others

  1. Insert a USB stick.

    If you use the Linux virtual machine, you need to click on the USB icon at the bottom of the VirtualBox page and select your USB device.

    Type

    hg clone . /path/to/USBStick/lab6

    (assuming you are still in the lab6 project directory; otherwise type hg clone /path/to/courseDirectory/lab6 /path/to/USBStick/lab6).

    The path to the USB stick depends on your operating system.

    Then verify that a lab6 directory has been created on the USB stick.

    This directory is now a “clone” of your project.

  2. One way of sharing a repository is to put the “master” on a USB stick. Mercurial is a “peer to peer” version control system and does not have an intrinsic concept of a master repository, but you and your fellow developers can agree on a master repository. You “push” your changes to the master and “pull“ the changes that your fellow developers made from the master.

    First, your fellow developers need a copy of the master.

    Inserts the USB stick into your buddy's laptop.

    Clone the repository onto that laptop:

    hg clone /path/toUSBStickOnBuddyLaptop/lab6 /path/to/buddysCourseDirectory/lab6

    Your buddy starts NetBeans and makes a Java project with the files in /path/to/buddysCourseDirectory/lab6.

  3. In Netbeans, you edit WindowInOut.java. Add a Javadoc comment @author Your Name.
  4. In Netbeans, your buddy edits ConsoleInOut.java and adds a Javadoc comment @author Your Buddy's Name.
  5. In Netbeans, you commit the file WindowInOut.java to your local repository.
  6. In Netbeans, your buddy commits the file ConsoleInOut.java to the local repository.
  7. Your buddy (who still has the USB stick) runs
    cd /path/to/buddysLabDirectory/lab6
    hg push /path/toUSBStickOnBuddyLaptop/lab6

    Now your buddy's changes are on the USB stick.

    Windows users: If you get errors about ”waiting for lock”, try removing a lock file, as described in this thread. Or switch to using the Linux virtual machine and repeat the steps starting from part A.

  8. You put the USB stick in your laptop and run
    hg pull /path/to/USBStick/lab6

    What happens?

  9. Now you have two change sets:

    But the second set isn't yet applied to your files. Type

    hg update

    to update your files.

    Now run hg status again. What output do you get?

  10. The hg update command modified a file, but that change isn't yet permanent.

    What command do you use to tell the repository that you accept the change?

  11. Now you have your buddy's changes. Then type
    hg push /path/to/USBStick/lab6

    Now your changes are on the USB stick.

    How does your buddy get your changes?

    This scenario illustrates an important rule: Always pull before you push. If you push your changes without first pulling other changes, the shared repository (and not just yours) will contain multiple change sets (or multiple “heads” in Mercurial speak). Multiple heads aren't good, and it is harder to fix them on the shared repository than yours.

    Whatever you do, do not use the -f or --force option. Then you are guaranteed to create multiple heads, and everyone will hate you. Here's what Joel Spolsky has to say about that:

  12. What happens if you both update the same file? Your buddy edits AddressBook.java and adds a line @authorYour Buddy's name, followed by
    hg commit "Added @author tag"
    hg pull /path/toUSBStickOnBuddyLaptop/lab6
    hg update
    hg push /path/toUSBStickOnBuddyLaptop/lab6

    You take the stick back, edit AddressBook.java and add a line @author Your name, followed by

    hg commit "Added @author tag"
    hg pull /path/toUSBStick/lab6

    What happens?

  13. Now there are change sets that cannot be resolved automatically with an hg update. Instead, a human needs need to make a decision how the change sets should be merged. Run
    hg merge

    Then look inside AddressBook.java.

    What happens?

  14. The <<< === >>> symbols are “conflict markers” that point you to the part of the code that you need to fix.

    Edit the file so that it becomes

       @author Your name, your buddy's name

    What do you do to save your changes to the shared repository?

    Conflict markers sound scary, but experience has shown that they are quite rare in practice. Most of the time, team members don't edit the same part of a file, and merging works without generating conflicts. And when conflicts occur, they are usually easy to resolve.

E. Using a Repository on a Server

  1. Using a USB stick is good for learning how a shared repository works because it makes the location of the repository visually explicit. But it would not be very conve nient when you collaborate with multiple people. Most teams use a repository on a server.

    In this part, you will retrieve a repository from a server, make some changes, and save your changes on the server.

    You can only do this part if you have sent your public key to your instructor and it has been installed in the server.

    Issue this command to get the repository:

    cd /path/to/courseDirectory/lab6
    hg clone ssh://hg@cs13.cs.sjsu.edu:62222/sandbox

    Where is the repository clone located?

    You should not get a password prompt. If you do, that means that the SSH authentication has failed. Here are debugging tips. (Skip them if you were able to clone the repo.) First be sure that your lab instructor has placed your public SSH key on the server. Then run

    ls -al ~/.ssh

    The .ssh directory should have permission drwx------ and the file id_rsa should have permission -rw-------.

    Run

    cat ~/.ssh/id_rsa.pub

    and have the lab instructor check that this file is present on the server.

    Run

    ssh -v -p 62222 hg@cs13.cs.sjsu.edu

    and have the lab instructor check for any anomalies in the debug messages.

  2. Using your text editor, make a file sandbox/yourname.txt (using your name, of course, not yourname, unless you have the misfortune of having the name “Yourname”). Put in some text about yourself, something like
    Hi, my name is Yourname Jones--which isn't a fun name to have.
    That's why friends call me Why Jay.
    I live in Drawbridge and am a computer science student at SJSU.

    Don't copy this—put some information about yourself.

    Save the file.

    Now

    What commands did you use?

    It is quite likely that you need to pull and update before you can push.

  3. Now pull the changes from ssh://hg@cs13.cs.sjsu.edu:62222/sandbox.

    What other files did you get?

    You now know enough about Mercurial to manage your personal projects and small team projects. Once you are more comfortable with the basics, check out the tutorial at http://hginit.com/ that gives a very nice background explanation in the inner workings of Mercurial.