Intro to Git - RobotGirls/FTC-Team-25 GitHub Wiki

Git is a source code management system. Git helps software developers to work together and maintain a complete history of their work.

  • Allows developers to work simultaneously.
  • Does not allow overwriting each other’s changes.
  • Maintains a history of every version.

The most common way to use Git is via a command line program called git, which lets us transform an ordinary Unix directory into a repository (or repo for short) that enables us to track changes to our project.

For common git commands, see Git Quick Reference

Git workflow

Git Flow

Other visualization resources:

Config file

Not sure what command line is? See Intro to Command Line Interface Haven't set up your Git environment yet? See Git Setup

One-time global configuration settings:

$ git config --global user.name "Your Name"
$ git config --global user.email [email protected]
  • These configuration settings allow Git to identify your changes by name and email address, which is especially helpful when collaborating with others. Note that the name and email you use will be viewable in any projects you make public, so don’t expose any information you’d rather keep private.
  • Git stores global configuration settings in a hidden text file located in your home directory. Display hidden files with ls -al. Inspect the file ~/.gitconfig with vi.

Clone and work on a repo

Let's clone a repository for practice space

$ cd ~/Desktop/FIRST (or use your gofirst alias)
$ git clone https://github.com/java-rnrr/java-tutorials.git
$ cd java-tutorials

Recall that you can use tab completion when changing directories, so in real life I would probably type something like cd ja<TAB>

[java-tutorials (master)]$ git checkout -b dev
[java-tutorials (dev)]$ cp HelloWorld.java HelloRobotGirls.java

[java-tutorials (dev)]$ git status
On branch master

Untracked files:
  (use "git add <file>..." to include in what will be committed)

  HelloRobotGirls.java

nothing added to commit but untracked files present (use "git add" to track)

We see here that the HelloRobotGirls.java file is “untracked”, which means Git doesn’t yet know about it. We can add it using the git add command:

There are two ways to do this:

  • Method 1:
[java-tutorials (dev)]$ git add HelloRobotGirls.java

Here we are only adding a single file named HelloRobotGirls.java

  • Method 2:
[java-tutorials (dev)]$ git add -A

Here the -A option tells Git to add all untracked files, even though in this case there’s only one.

We can see the result of git add by running git status again:

[java-tutorials (dev)]$ git status
On branch master

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

  new file:   HelloRobotGirls.java

As implied by the word “unstage”, the status of the file has been promoted from untracked to staged, which means the file is ready to be added to the repository. Untracked/unstaged and staged are two of the four states commonly used by Git, as shown in the image below.

Technically, untracked and unstaged are different states, but the distinction is rarely important because git add tracks and stages files at the same time.

The main Git status sequence for a changing file: Git Flow

After adding changes in the staging area, we can make them part of the local repository by committing them using git commit. Most uses of git commit use the command-line option -m to include a message indicating the purpose of the commit.

[java-tutorials (dev)]$ git commit -m "Add HelloRobotGirls file"
[master (root-commit) 879392a] Initialize repository
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 HelloRobotGirls.java

(I’ve shown my output here for completeness, but your details will vary.)

By design, Git requires every commit to include a commit message describing the purpose of the commit. Typically, this takes the form of a single line, usually limited to around 72 characters, with an optional longer message if desired.

Although conventions for commit messages vary (as humorously depicted in the xkcd comic strip “Git Commit”), the style adopted in this tutorial is to write commit messages in the present tense using the imperative mood, as in “Initialize repository” rather than “Initializes repository” or “Initialized repository”. The reason for this convention is that Git models commits as a series of text transformations, and in this context it makes sense to describe what each commit does instead of what it did. Moreover, this usage agrees with the convention followed by the commit messages generated by Git commands themselves (e.g., “merge” rather than “merges” or “merged”).

At this point, we can use git log to see a record of our commit:

[java-tutorials (dev)]$ git log
commit 879392a6bd8dd505f21876869de99d73f40299cc
Author: Jezmin Pelayo <[email protected]>
Date:   Thu Jun 20 20:00:34 2019 -0800

    Add HelloRobotGirls file

The commit is identified by a hash, which is a unique string of letters and numbers that Git uses to label the commit and which lets Git retrieve the commit’s changes. In my case, the hash appears as 879392a6bd8dd505f21876869de99d73f40299cc but since each hash is unique, your result will differ. The hash is often referred to as a “SHA” (pronounced shah) because of the acronym for the Secure Hash Algorithm used to generate it.

Exercises

  • Using the touch command, create empty files called foo and bar in your repository directory.
  • By using git add foo, add foo to the staging area. Confirm with git status that it worked.
  • Using git commit -m and an appropriate message, add foo to the repository.
  • By using git add bar, add bar to staging area. Confirm with git status that it worked.
  • Now run git commit without the -m option. Use your VI knowledge to add the message “Add bar”, save, and quit.
  • Using git log, confirm that the commits made in the previous exercises worked correctly.

Viewing the diff

It’s often useful to be able to view the changes represented by a potential commit before making it. To see how this works, let’s add a little bit more content to HelloRobotGirls.java.

Add the following line to HelloRobotGirls.java:

System.out.println("Hello, Robot Girls");

Git has a function, git diff, which by default just shows the difference between the last commit and unstaged changes in the current project:

[java-tutorials (dev)]$ git diff
diff --git a/HelloRobotGirls.java b/HelloRobotGirls.java
index e69de29..4b5fa63 100644
--- a/HelloRobotGirls.java
+++ b/HelloRobotGirls.java
@@ -0,0 +1 @@
System.out.println("Hello, Robot Girls");

We can commit this change by passing the -a option (for “all”) to git commit, which arranges to commit all the changes in currently existing files.

[java-tutorials (dev)]$ git commit -a -m "Add second print line to HelloRobotGirls.java"
[master 03aff34] Add second print line to HelloRobotGirls.java
 1 file changed, 1 insertion(+)

Note that the -a option includes changes only to files already added to the repository, so when there are new files it’s important to run git add -A to make sure they’re added properly. It’s easy to get in the habit of running git commit -a and forget to add new files explicitly.

Having added and committed the changes, there’s now no diff:

[java-tutorials (dev)]$ git diff
[java-tutorials (dev)]$

(In fact, simply adding the changes is sufficient; running git add -A would also lead to there being no diff. To see the difference between staged changes and the previous version of the repo, use git diff --staged.)

We can confirm that the change went through by running git log:

[java-tutorials (dev)]$ git log
commit 03aff34ec4f9690228e057a4252bcca169a868b4
Author: Jezmin Pelayo <[email protected]>
Date:   Thu Jun 20 20:03:34 2019 -0800

    Add second print line to HelloRobotGirls.java

[java-tutorials (dev)]$ git log
commit 879392a6bd8dd505f21876869de99d73f40299cc
Author: Jezmin Pelayo <[email protected]>
Date:   Thu Jun 20 20:00:34 2019 -0800

    Add HelloRobotGirls file

Exercises

  • Use touch to create an empty file called baz. What happens if you run git commit -am "Add baz"?
  • Add baz to the staging area using git add -A, then commit with the message "Add bazz".
  • Realizing there’s a typo in your commit message, change bazz to baz using git commit --amend.
  • Run git log to get the SHA of the last commit, then view the diff using git show <SHA> to verify that the message was amended properly.

We’ve now seen all of the major elements involved in the simplest Git workflow, so in this section and the next we’ll review what we’ve done and see how everything fits together. We’ll err on the side of making more frequent commits, representing relatively modest changes. It’s an excellent foundation, and it will give you a solid base on which to build your own workflow and development practices.

Dealing with commit issues

One common issue when learning Git involves figuring out when to make a commit. Unfortunately, there’s no simple answer, and real-life usage varies considerably (as illustrated in the xkcd comic strip “Git Commit”).

My best advice is to make a commit whenever you’ve reached a natural stopping point, or when you’ve made enough changes that you’re starting to worry about losing them. In practice, this can lead to inconsistent results, and it’s common to work for a while and make a large commit and then make a minor unrelated change with a small commit. This mismatch between commit sizes can seem a little weird, but it’s a difficult situation to avoid.

[java-tutorials (dev)]$ vi HelloRobotGirls.java

At this point, we’re ready to make as many changes as we want to our program. Use your knowledge of VI to print various lines to console. You can compile and test your program by running the following:

$ javac HelloRobotGirls.java
$ java HelloRobotGirls

As before, we’ll run git status and git diff to learn more about what we’re going to commit to Git, though with experience you’ll come to run these commands only when necessary. The status simply indicates that HelloRobotGirls.java has been modified:

[java-tutorials (dev)]$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

  modified:   HelloRobotGirls.java

no changes added to commit (use "git add" and/or "git commit -a")

Meanwhile, the diff shows that one line has been deleted (indicated with -) and another added (indicated with +):

[java-tutorials (dev)]$ git diff

At this point, we’re ready to commit our changes. We have used both the -a and -m options to commit all pending changes while adding a commit message, but in fact the two can be combined as -am.

[java-tutorials (dev)]$ git commit -am "Commit message"

The git log command shows only the commit messages, which makes for a compact display but isn’t particularly detailed. Verify by running git log -p that the -p option shows the full diffs represented by each commit.

$ git log -p

Other definitions

  • The remote git repository you cloned from is by default called "origin"
    • When a repo is cloned, it has a default remote called origin that points to your fork on GitHub (for example, https://github.com/odacindy/terkel), not the original repo it was forked from (which was from github.com/cmacfarl/terkel)
    • You use upstream to fetch from the original repo to keep your local copy in sync with the project you want to contribute to
  • HEAD is the snapshot of your last commit. HEAD can point to any commit, it does not need to be the last commit in any branch.
    • When HEAD points to a commit that is not the last commit in a branch, that is a "detached HEAD".
⚠️ **GitHub.com Fallback** ⚠️