2. Review of Essential Git Commands

This worksheet reviews the Git commands that you will need to use in this module. You can work through these exercises as an alternative to revisiting the Git training materials from Professional Computing last semester.

If you need some background on version control and Git, you may find it helpful to first watch the introductory videos What is Version Control? and What is Git?, available on the Git documentation page.

For more detail on Git, see Scott Chacon’s Pro Git book. For an in-depth comparison of centralised and distributed version control systems, see Eric Sink’s Version Control By Example.

You may also find it useful to print out gitcheat.pdf (a cheat sheet of Git commands) and have this beside you while you work.

Note

The exercises below assume the use of the Linux command line. Adjust them accordingly if you are using a different environment.

Also, DO NOT use your COMP1721 repository (the one configured in Setting up Version Control) for these exercises! Create a separate temporary repository instead, as instructed below, and then remove it when you’re done.

2.1. Configuration

  1. If you’ve not already done so, configure your Git identity by entering commands like the following in a terminal window:

    git config --global user.name "Jane Smith"
    git config --global user.email jane@example.com
    

    Substitute your real name and university email address for the examples given here. Make sure that you use the --global option in both of these commands (and in the two mentioned below).

  2. Configure the Git user interface for colour display like so:

    git config --global color.ui auto
    
  3. Configure the text editor that Git uses for commit messages. For example, if you prefer to use the Atom editor (one of several editors available on SoC Linux machines), do this:

    git config --global core.editor "atom --wait"
    

    Modify this as necessary to suit your favourite editor; gedit, vim and emacs are all available on SoC Linux machines, for example. If the command to run the editor includes spaces and command line options, enclose the whole command in quotes.

    Warning

    If you don’t set a value for core.editor, Git will check to see if the EDITOR environment variable has been set; if so, it will use the value of this variable as the command to invoke the editor. If no editor has been specified using environment variables, Git will fall back on using vi, a standard editor on UNIX-like systems.

  4. Check your settings by entering the following command:

    git config --list
    

2.2. Creating a Repository

  1. Open a terminal window if you haven’t already done so. Use mkdir to create a directory for this exercise and cd into it. Make sure that this directory is not inside your cloned GitLab repository!

  2. Use mkdir again to create a subdirectory called hello. Then cd into hello and turn it into a Git repository by entering the following command:

    git init
    

    Note that all Git commands begin with git. You can get help on the available commands by entering git help, followed if need be by the Git command you want help on.

  3. If you enter ls -a in the terminal window, you will see that a new hidden directory called .git has been created. This contains the history of the project. Files outside .git are the working tree.

  4. Check the status of your files with this command:

    git status
    

    This should resulting in output like the following:

    On branch master
    
    Initial commit
    
    nothing to commit (create/copy files and use "git add" to track)
    

    (Depending on the version of Git that you are using, you might find that some of the output lines begin with the # character.)

2.3. Ignoring Files

You can tell Git to ignore certain kinds of files; for example, you can tell it to ignore the ‘backup’ files that text editors such as gedit sometimes create, the .pyc files generated when Python imports a module, the .class files generated by the Java compiler, etc.

To do this for your new repository, create a file called .gitignore in the hello directory (don’t forget the ‘dot’ at the start of the name), containing the following:

*~
*.bak
*.class
*.pyc

Note that the .gitignore file will itself be version-controlled 1.

Note

An important first step in any project, after you’ve created a repository, is to create a sensible .gitignore file for it. Not doing this can lead to temporary or generated files being accidentally added to the repository, which can then cause other problems - particularly in team development scenarios.

GitHub maintains a collection of .gitignore templates which may give you a useful starting point for your own projects. Find one that is appropriate for your needs, modify it and then keep it up to date as your project develops.

Alternatively, you can generate a .gitignore file using a service such as https://gitignore.io.

Note that your COMP1721 repository already has a suitable .gitignore file, which you can modify if need be.

2.4. Adding Files

  1. Within the repository, use your favourite text editor to create a file Hello.java, containing the following small Java program:

    class Hello {
      public static void main(String[] args) {
        System.out.println("Hello World!");
      }
    }
    

    Compile the program using the javac command, to generate the Hello.class file.

  2. Now check the status of your files by entering git status. You should see the following output:

    On branch master
    
    Initial commit
    
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
    
           .gitignore
           Hello.java
    
    nothing added to commit but untracked files present (use "git add" to track)
    

    You can generate shorter output using git status -s. Try this now and you should see the following:

    ?? .gitignore
    ?? Hello.java
    

    Both outputs are telling you that these two files are unknown to Git. Notice that Hello.class isn’t listed, because you specified in .gitignore that files ending in .class should be ignored by Git.

  3. The next step is to add files to the staging area, also known in Git terminology as the index. Do this now, like so:

    git add .
    

    Don’t forget the ‘dot’ after add!

    This adds all of the untracked files in or below the current directory. You can also add files individually (e.g., git add Hello.java) or use wildcards to add a set of matching files (e.g., git add *.java).

  4. Check the status once again. You should now see this:

    On branch master
    
    Initial commit
    
    Changes to be committed:
      (use "git rm --cached <file>..." to unstage)
    
           new file:   .gitignore
           new file:   Hello.java
    

    If you use the -s option for abbreviated output, you will see that the two files now have A beside them instead of ??, indicating a status of ‘added’.

2.5. Committing Changes

Note

Git uses a two-step process to get changes into the repository. The first step is to copy changes from the working tree to the staging area using git add. The second step is to commit changes from the staging area to the repository.

  1. Enter the following command:

    git commit -m "Created first version of program."
    

    If you enter git status once more, you should see this:

    On branch master
    nothing to commit, working directory clean
    

    The -m option to commit specifies a ‘commit message’ describing the changes that are being committed.

    If you omit this option, Git will start up your chosen text editor (or the default) and let you use it to enter your message. This can be a better approach for lengthy messages. The commit will take place after you save and quit the editor, unless you leave the message empty - in which case the commit is aborted.

  2. Inspect the project history with the log command, like so:

    git log
    

    This will list the commit ID, your identity and the commit message.

    You can view an abbreviated version of the log with

    git log --oneline
    

2.6. Making Further Changes

  1. Edit Hello.java, changing the word World to Everyone. If you use the status command, you will see the file is now flagged as ‘modified’ and ‘not staged for commit’.

  2. Now try this command:

    git diff
    

    This shows you the changes to the working tree that have been made but have not yet been staged.

  3. Stage your changes with git add Hello.java. The status command should now indicate that the file is modified and staged. The git diff command will now show nothing, because there are no unstaged changes, so try this instead:

    git diff --staged
    

    This will show you the differences between your staged changes and the most recent commit.

  4. Commit your changes with the following command:

    git commit -m "Changed greeting issued by the program."
    
  5. Edit the program once again so that it looks like this:

    class Hello {
      public static void main(String[] args) {
        if (args.length > 0) {
           System.out.println("Hello " + args[0] + "!");
        }
        else {
          System.out.println("Hello Everyone!");
        }
      }
    }
    

    Then use the following command to commit the changes:

    git commit -a -m "Program now greets user by name if required."
    

    Note

    Notice the -a option. This is a useful shortcut that allows you to commit the changes in the working tree without having to stage them first. Note, however, that it will also commit any already-staged changes.

  6. Try git log and git log --oneline again. You should see that the history now has three commits, listed in reverse chronological order.

    The log command has a great many options, which you can explore by doing git help log. Here’s a few for you to try now:

    git log -1

    Displays most recent commit

    git log -2

    Displays last two commits

    git log --skip=1

    Displays all commits except the most recent

    git log --stat

    Includes file change stats with commits

2.7. Removing & Renaming Files

To remove a file from version control, you must both remove it from the working tree and tell Git to stop tracking it. You do this with git rm. As with edits to a file, this merely stages the change; you need to follow it with a commit in order to finalize it. The same considerations apply when renaming or moving a file, only here the command used to stage the change is git mv.

  1. Try this out now by renaming the Java program thus:

    git mv Hello.java HelloWorld.java
    

    Do git status to see the effect of this command.

  2. Finalize the change like so:

    git commit -m "Changed name of program."
    

Warning

Watch out for this! Remember: files are deleted with git rm followed by a commit, moved or renamed with git mv followed by a commit.

The only exceptions to this are files that are being ignored by Git and files that haven’t yet been added to version control.

2.8. Version Control as a Time Machine

Normally, Git’s checkout command is used to switch between branches of development, but you can also use it to synchronize the working tree with any particular commit in the project history, as a way of ‘looking back in time’ to an earlier version of the project.

  1. Use git log --oneline to view the abbreviated IDs of the three commits in your repository. Make a note of the second ID in the list, then use it with the checkout command. For example, if the ID was e7c7f5c, you would need to enter

    git checkout e7c7f5c
    

    Examine Hello.java and note how it has reverted its previous version.

  2. Use git checkout again, this time with the third ID in the list, corresponding to the first commit made into the repository. If you look at Hello.java again, you should see that it has now reverted to its original form.

  3. Resynchronize the working tree with the most recent commit using the following command:

    git checkout master
    

Footnotes

1

Note that Git also provides ways of excluding files that don’t require committing a .gitignore file to a repository - see Pro Git for more information on this.