This handout describes how to perform common Java development tasks on the command line. If you prefer to use an IDE (as you probably should), read the instructions on using Eclipse or IntelliJ instead.
Contents:
A few CSE 331 tasks require connecting to a Linux machine and running some commands from the command-line. Understanding the instructions below may require some basic understanding of how to use a shell to perform command-line actions. That is described (in more depth than we need) in CSE390A, which has materials posted online.
Gradle is a tool that can be used to automate many common tasks, such as
compiling, testing, and running code. The instructions for Gradle are stored in
a file named build.gradle
in the root directory of your
repository.
The buildfile specifies a set of tasks that it can perform, such as build and test. The “help” task will output more information about how to use gradle and the options available with this build file.
All of the gradle tasks described below should be performed in the root directory of your local repository, which you set up by cloning your repository from gitlab.
You must compile your source code before running it. The javac
compiler is used to transform Java programs into bytecode form, contained
in a class file. Class files are recognized by their
.class
extension. The bytecode in class files can be executed by
the java
interpreter.
To compile all your source files, type this command on the command-line:
./gradlew classes
This will run a gradlew
script in that directory, which uses the
instructions provided in build.gradle
to compile the appropriate
.java
files in your repository into corresponding
.class
files. Note that if one or more of your files do not
compile, you will receive error messages and no .class
files will
be generated for the files that do not compile properly.
Once you have compiled your source code into class files, you can execute it with the Java interpreter.
Here is how to run Java programs from the command-line:
java -cp build/classes/java/main -ea hwN.theClassYouWantToRun
The -cp
flag tells java
where to find the
.class
files produced by javac
, which contain the
compiled source code. And the -ea
flag enables assertions.
For example, if you wish to run the RandomHello
class from
hw3, you would run:
java -cp build/classes/java/main -ea hw3.RandomHello
Note that you do not include .java
or .class
at
the end of the class name.
JUnit is the testing framework that you will use for writing and running tests.
For more information, visit:
The test
gradle task can be used to run the tests with the
command:
./gradlew test
Oracle's Java Development Kit includes javadoc, a tool that produces specifications from source code annotated with special comments. The comments may include "tags", which are introduced by an at-sign (@). (In addition to the standard javadoc tags, CSE 331 includes some custom tags used only for this course.)
The javadoc
gradle task can be used to run the tests with the
command:
./gradlew javadoc
This will produce HTML documentation, which you can view by opening the file build/docs/javadoc/index.html (Note that running this task will completely overwrite the existing documentation in that folder.)
You may see a BUILD FAIL message. This could be because of serious syntax errors in your files that cause the code not to compile. This may also be the issue if you see a BUILD SUCCESSFUL message but incorrect API in the doc folder. To fix these problems, look at the error messages and fix up the most serious problems reported there. Javadoc can produce documentation for partially implemented files (that is one of its strengths), but it can't compensate for some serious problems in the source code.
After running the ant doc
target, you should
check the output. You may find that you
need to add line breaks (<br>
) or paragraph breaks
(<p>
) to your javadoc comments for readability.
Also, if you omit certain tags, subsequent text may fail to appear in the output. Finally,
since much of the text of javadoc comments is inserted in a HTML document,
you must be careful with text that can be interpreted as HTML markup, such
as the less-than (<) and greater-than (>) characters.
For instance, if you write:
@effects Adds <x> and <y>
then <x> and <y> will be interpreted as HTML tags in the output (and won't be displayed by a browser). It's usually better to just write
@effects Adds x and y
Report any weird behavior or complaints about javadoc
to cse331-staff@cs.washington.edu.
You always edit your own personal copy of files that are under git
control. Before you can make such edits, you must “clone”
your own copy of the repository's master files. This means that you are
copying code from the master branch from another source (GitLab in our case)
into your own local, personal copy. You need to do this step only once
at the beginning of the quarter. If you are tempted to use this command
at other times, you most likely want git's “pull”
command, which incorporates changes from the repository into your existing local copy.
In the case that you plan to work at both UW CSE and home, you will need
to do these setup steps both while logged into a department machines
and from your home computer so you have a local copy on both machines.
The following instructions assume you wish to clone your personal Gitlab
repository that is located at
https://gitlab.cs.washington.edu/cse331-19wi-students/cse331-19wi-YourCSENetID
.
Make sure this URL takes you to your own project!
Execute the following commands at the command line to check out the project to the directory cse331-19wi-YourCSENetID:
git clone git@gitlab.cs.washington.edu:cse331-19wi-students/cse331-19wi-YourCSENetID.git
Note that, when you try to type passwords in the command line, you may be alarmed that you can't see any text entered. To protect your password, your typing simply isn't being shown. Just type your password as normal and press enter.
Git's "pull" command updates your local copy of files to reflect changes made to the repository by other people (or by you when working on a different computer system). The only changes made by people other than you will be made by the CSE 331 staff when we are adding new homeworks to your repositories. If you work at home and at UW CSE, you will need to commit and push on each machine when you are done on one machine and then pull when you start on another machine. That will propogate your changes to local machine.
Git usually does a good job of merging changes made to multiple copies
(say, the copy on your home computer and the copy on attu
) even if
those changes are to different parts of the same file. However, if both people
change the same line of a file, then git cannot decide which version should
take precedence. In this case, git will signal a conflict during git pull, and
you must resolve the conflict manually. This can be an
unpleasant task.
To minimize the possibility of conflicting changes being made simultaneously, you should pull frequently and commit/push frequently.
To update your local copy on the command line, go to the root of your
repository (e.g. ~/cse331-19wi-YourCSENetID
) and run:
git pull origin master
or just
git pull
which defaults to using master
. This command will display a
list of files that have been updated.
After making changes to, adding, or removing files, you must “commit” your changes to git. This step will cause git to record your changes to the repository, so that your changes are backed-up and available to other people working on the repository, or to you when working on a different computer system.
Be aware that in git, committing changes does not change the remote copy of your repository on GitLab. To do this, you must “push“ a single (or series) or commits to the remote repository
In general, you should “pull” any new files or changes before committing your latest code. (And, if the pull results in any conflicts, you should resolve them before committing.) If you forget to pull, git will abort and remind you to pull first.
It is a good idea to commit your changes frequently. It backs up your work, thus enabling you to revert to an earlier version of your code if you find yourself going down a wrong path. Also, when you are working with others, it minimizes conflicts.
To perform a commit on the command line, first, enter the directory in which the file(s) you wish to commit are located. For example:
cd ~/cse331-19wi-YourCSENetID/src/main/java/hwN
Next, to list all the changes you have made since the last git pull, type:
git status
This will print some output saying either you have no changes, or show your staged (to be committed), unstaged (not to be committed), and untracked (files not added to git) files. Untracked files show up when you create a new file in a directory which is under git control. Git will not automatically add these files to the repository to avoid extraneous files from being added.
Below is an example of output you might see in a git status:
Changes to be committed: (use "git reset HEAD..." to unstage) modified: Ball.java Changes not staged for commit: (use "git add ..." to update what will be committed) (use "git checkout -- ..." to discard changes in working directory) modified: Box.java Untracked files: (use "git add ..." to include in what will be committed) NewFile.java
Now you can add a file (or directory) as follows:
git add NewFile.java
Then, you can commit your staged files to the local git repository by running:
git commit -m "a descriptive log message"
Alternatively, you can stage (add) and commit all of your unstaged commits in one command as follows:
git commit -am "a descriptive log message"
If you omit the message flag -m "a descriptive log
message"
from your commit command, git will throw
you into an editor where you can enter a message. Remember, at any time
you can check the git status and see which files are staged, unstaged,
and untracked.
Adding and committing files only stores the changes in the local (working) copy of your repository. To update the remote GitLab copy of your repository and store all of your locally committed changes there, use the push command after you have committed the changes you want to save.
git push
You must be sure to push your changes, or they will not be stored in the remote GitLab copy of the repository and, in particular, will not be available when the CSE331 staff pulls files from your repository for grading.
Git commits exist only in your local copy of your Gitlab Repository. Pushing your changes will update your master repository on Gitlab. Make sure to do this! Grading your homework assignments requires the work you have to done to exist in the original repository. If it does not, when the TAs check out your repo for grading, they will be unable to see the work you have done.
To push your last comitted local changes to the repository on the command
line, go to the root of your repository (e.g.
~/cse331-19wi-YourCSENetID
) and run:
git push origin master
or just
git push
which defaults to using master
.
In git, commits can be “tagged“ with a short phrase without
spaces. This can be used to mark important versions of the repository, like an
alpha-1.0
or release-version
. For CSE 331, tags are
required to mark final versions of assignments that are ready to be
turned in. The correct tag to use for a final version of an assignment in your
repository is hwN-final
, where N
is the homework
number (e.g., hw3-final
).
To tag the most recent committed version at the command line, go to the root
of your repository (e.g. ~/cse331-19wi-YourCSENetID
) and
run:
git tag -a TAG_NAME -m "MESSAGE"
where TAG_NAME
is a name for the tag (usually, something like
hw3-final
in our case) and MESSAGE
is any commment
you want to leave for yourself about the tag (e.g., "final version of hw3").
(It is important to use exactly this command for creating tags. Some of the other commands you can find in the Git documentation create "lightweight" tags that cannot be pushed to the server.)
The command above creates the tag in your local repository, but you also
need to push it to Gitlab. That is particularly important when turning in your
homework because the staff uses the hwN-final
tags to figure out
which version of your code to grade. If your tag is not pushed to Gitlab along
with your code, the staff will not know which is your final version.
You can push tags just by adding the --tags
command to
git push
:
git push origin master --tags
This command should display that the names of the tags that were pushed, so if you create a tag and then push but do not see the tag listed, you may have done something wrong. (You can always double check by cloning another copy of your master repository and seeing if the tag shows up there.)
When you pull changes into your local repository and you have local changes that have not yet been pushed, git tries to merge the changes together. Usually, it succeeds.
The most common case of this is when the staff pushes out new sets of starter files for each homework. After this happens, you may be unable to pull any changes until your local copy is all up to date with the new starter files. This is especially likely if you have made commits that you haven't pushed to GitLab yet.
Usually, git can perform these merges without any difficulties. However,
sometimes git is unable to merge the files together when there are two
different changes to the same line of a file. In this case, git will signal a
conflict during the pull such as Automatic merge failed; fix
conflicts
or you may see the notice that You have unmerged
paths
.
Git conflicts are rare — most students will never encounter one — but if you do get a git conflict, you need to resolve it. This is a very brief primer about resolving conflicts; you can read the git documentation to get the full story. Also, it's better to prevent a merge conflict than to have to resolve it later on.
On the command line, to see the status of all your files, run:
git status
This will tell you, for each file and directory, whether it is currently in a conflicted state or not, i.e., whether that files contains local changes that conflict with the changes it is trying to integrate.
When git detects a file conflict, it changes the file to include both versions of any conflicting portions (yours and the one from the repository), in this format:
<<<<<<< filename YOUR VERSION ======= REPOSITORY'S VERSION >>>>>>> 4e2b407... -- repository version's revision number
For each conflicting file, edit it to choose one of the versions (or to
merge them by hand). Be sure to remove the
<<<<<<<
, =======
, and
>>>>>>>
lines.
(Searching for "<<<
" until you've
resolved all the conflicts is generally a good idea.)
Once you have made these edits, then you can tell git that you have resolved the conflicts by staging the file as you normally would:
git add src/main/java/hw4/test/SpecificationTests.java
Git does not track directories like regular files. It only keeps track of the individual files and creates the directories that they reside in as necessary. So, if you create a directory, with the usual command
mkdir dirname
git will not notice its existence until you add a file from that directory into your commit.
To delete a directory or file from the repository, use the standard
rmdir
or rm
command. To remove a directory and all of
its contents, use:
rm -rf dirname
After adding or deleting a directory, you must perform a commit for the change to be reflected in the repository.
To see the change log, which lists all of the changes that have been comitted, use the command:
git log
To see differences between the working copy and the repository's latest copy:
git diff filename(s)
Omit filename to see differences for all files. Each commit is associated with a long hash value, which you can see in git log as commit 2d03d7...
To see changes compared to a particular commit version, enter:
git diff REVISION filename(s)
Where REVISION
is either a commit hash, like
2d03d7...
or HEAD for the repository's most recent master
version.
You can show an old version of a file under git control with commands like the following:
git show HEAD:MyFile.java git show 7ff8dc80:MyFile.java git show HEAD@{2013-03-14}:MyFile.java
As seen in the first command, HEAD means the most recent commit on your local copy of the repository. The second command uses a commit hash and the third uses a date.
You can also revert to an older version of a file under git control:
git checkout HEAD MyFile.java
This command changes your working copy — that is, your local directory — but it does not change the repository. Do not attempt to edit the old version of the file in your working copy. Doing so will result in nasty merge conflicts and confusion.
To reset all of the files under git control to a previous version, use the following command:
git reset HEAD
Note, checkout
and reset
are complicated and can
have adverse affects on your local repository. You MAY lose data playing
with these commands, and you should only use them with full understanding of
what they do.
You should save a copy of the file (e.g. git stash) somewhere, then git pull your working copy to the current version of the file. Now, edit the current version in whatever way you like, possibly copying some or all of the differences from the old version that you saved. You can discard the old version when you are done; there is no need to check it in into GitLab.