Git Cookbook

What is Git?

Simply - Git is a utility program for managing versions of your source code files

Git is a version control system. If you didn’t already know this, version control systems are programs used in software development projects that provide a convenient way to backup a development team’s work in progress.

Note

In development projects involving multiple developers, Git provides a way for the developers to develop their individual contributions independently, and then when the code is ready, to merge their bits into the code base.

Learning resources

The following table contains links to the learning resources that I used to write this cookbook.

Resource Description
Git for Ages Four and Up To speed up your climb up the learning curve, you’ve got to see this video.
The Pro Git Book A comprehensive Git reference manual.
Think like a Git A good conceptual discussion.
The official Git documentation Straight from the horse’s mouth.
EGit/Git For Eclipse Users If you’ve installed EGit for Eclipse, then I recommend that you take a look at this help topic.

Git is a distributed version control system

Source Depot and Subversion are centralized version control systems. At the heart of these systems is a central database (or repository). All merges occur at the central database. Git doesn’t work like that. Everyone working on a project using Git takes a copy (an enlistment in the parlance of Git) of the entire repository, and there isn’t a central database. But there is a remote repository that serves as the master or funnel point. By default, this is called origin. Everyone working on the same project synchronizes their local enlistment with the origin repository. That way everyone keeps up to date with everyone else’s work.

Git isn’t based on the file system

Unlike all other version control systems, Git isn’t file system-based. The Git system is abstracted on top of the file system. To use Git successfully, you have to understand the nature of Git, and the way that Git works. The road to getting there isn’t easy because it requires comprehending a paradigm shift. To an extent, you must unlearn what you understand about source control systems per se. So, to be successful, you must - free your mind!

Eclipse cheat sheets

In Eclipse, if you click Help > Search, the Help tab appears and it has an input field for searching the local help system. If you type git into it and press Return, a list of candidate topic links appears. The first one is “Cloning a Git Repository”. Click it, and the “Cheat Sheets” tab appears. This is interesting. This seems to be a help system that is tied to a Wizard-driven interface, which makes it into a cool tutorial/walk-through system.

Concepts that shift the CVS paradigm

Let me explain Git in terms of an example

Imagine you’re playing a video game (say, a first person shooter) in which you save the game after every accomplishment. This allows you to exit the game and then return to it at the point where you left off (like a bookmark in a book your reading). In terms of your achievements, this preserves your level of progress (so you don’t have to fight a particular battle again); you resume right where you left off. Think of each save as committing a snapshot of your current progress. In terms of Git, snapshots of your work are saved to Git as commits. So Git is a database application that contains shnapshots of the state of your progress in a software developmet project.

You wouldn’t want to do this in a game, but imagine if you could pick up the game from any one of your saves (commits). This isn’t how game saves usually work, but if it were, then there’d be a number of ways it could be achieved. One way would be to simply timestamp each save, and then present you with a list with each one named with its time stamp. The difference between each successive save would then be the cumulative progress you made between the two saves. I.e., between the current save and the last save, or the last save and the one before it.

This might not be useful in a video game, but it would be quite useful in a software development project. In a development project, you risk introducing bugs as you make progress - so it’s essential that you always have the option to revert back to an earlier state; one in which everything worked.

The Git repository

Git manages repositories as a data structure layered on top of the file system. In Git, you think about changesets, also known as commits. A changeset means conceptually differnt things on different levels (and this trips-up newbs). A change set is a:

  • Concise list of the changes between one revision and the next.
  • Commit.
  • Snapshot.
  • Hash.
  • Reference ID.
  • Pointer.
  • Tree.
  • Node in a graph.

A Git repository is an object-oriented database. The schema of its data structure is that of an Acyclic Directed Graph. The Objects in the database are the nodes in the graph (trees, folders, tags). Each node is a change-set. It’s a snap-shot of the current state of a branch, and it is called a “Commit,” and the edges are pointers to the previous node.

Commits are objects that contain pointers to the previous commit (parent - child relationship). Merges are commits that point to two or more parent commits.

Git commands

Git cammands do one of three things:

  • Add files and directories to the staging area.

  • Build commits (a new node in the graph).

  • Move labels from one node to another.

    • E.g., git checkout feature.
    • When you type “git commit”, you’re just moving the label for that branch to the node Git created when you staged content (HEAD now point to INDEX).

Git refers to a label as a reference. References make commits reachable (like address pointers). Local branch references move when you perform commands like “git commit”, “git merge”, “git rebase”, “git reset”. Remote branch references move when you perform commands like “git push”. Think of a branch as a time-line (alternate universes).

Experimentation strategy

Before you try something…

  1. Create a new branch (like you would a saved game).
  2. Start gitK - so you can see the current state of the branch visually.
  3. Make your change (perform the operation).
  4. Before you refresh gitK, try to guess at what the change will look like.
  5. Run gitK and check the result.

The problems you’re likely to encounter at first

You’ll make notes about what Git is, how it works, and how to use it. But as you build your knowledge, parts of it will evolve-as you have epiphanies.

You’ll execut Git commands, thinking that because they have the name names as the old system, that they do pretty much the same things - but they actually do quite different things. And Git commands produce different results depending on the context.

For example, you’ll spend three months thinking that git checkout is just like a Source Depot checkout, without really knowing what git checkout does. Here’s the difference:

You can switch to any branch just by changing the commit that HEAD points to. In Git, you use the “Checkout” command to switch branches (which is confusing for CVCS users, because it doesn’t mean what you think).

You’ll try to branch the Source Depot way, and you’ll get confused because it produces inexplicable results, and it didn’t work so well because you really should have been branching the Git way - by cloning repositories, not by trying to do the things that work in Source Depot.

In GitHub (an online Git host), the term “Fork” is used to refer to a clone of a repository - cloned under your account on GitHub. This is confusing because you’re apt to think of a fork as just another branch. You use Fork when you work on a project that you don’t have permission to write to. To Push your changes up to Origin, you issue a Pull Request (which gets someone with write permissions to integrate your changes into the mainline).

The advantages of switching to Git

  • Merging branches is much simpler in Git. You can think of branches as alternate timelines (or alternate universes).
  • It’s much easier to keep stable work and work in progress, separate.
  • Git separates the act of committing new code from the act of inflicting it on everybody else. I.e., you can commit your changes locally, but the rest of the team won’t see them until you Push your changes up to Origin.
  • If you’re used to having one big gigantic repository for the whole company, where some people check out and work on just the subdirectories that they care about, this isn’t a very good way to work with Git—you’re better off having lots of smaller repositories for each project.
  • There is no central repository, only an agreed-upon funnel-point (a remote repository named Origin).
  • Git doesn’t use the concept of Revisions. Instead, it uses the concept of Changesets (also known as commits).
  • A commit is a snapshot of the state of a branch. as it existed at a particular point in time.
  • Like a commit, a branch is a version of a repository, but it contains an alternate lineage of commits that differ from that of master (it diverges from master).
  • A commit is identified by a hash of its contents, and the resulting hash code (a forty digit hex value) becomes the symbolic reference - its “Reference ID”.
  • So for example, when you edit a sentence in a text file within a particular branch, not only have you altered that one file, you’ve also altered the entire branch.
  • When you Commit the change, a new hash code is generated (based on the new hash of the branch snapshot), and that hash code becomes the unique identifier for that set of changes (well, one change in this case). A changeset generally contains more than just one change to one file. In practice, you hold-off on “Committing” until you’re done making a series of related changes. E.g., updating all topic source files with the revised ordering of JSON nodes with the JSON dictionary returned in responses (in the Examples section of each topic).
  • Commits also contain a back-pointer to the previous commit. Such recursive linking turns your set of commits into a linked list (a directed graph). Viewed as such, this link information represents the lineage of your branch. It allows you to see the entire history of your branchy all the way back to its beginning (where it diverged, and ultimately - when it was cloned).
  • It also allows you to identify where in the lineage a particular change was introduced, and it allows you to revert back to any branch state.
  • Git allows you to use a short form of the hash to specify a commit. The convention is to use the first six digits, but you can use less if you project is small. E.g., you can use 48b217 to refer to 48b2179994d494485b79504e8b5a6b23ce24a026.
  • The “current version” of your repository is always the latest commit (the one that the HEAD reference points to), and the hash of it is always placed at the end (the tip) of the linked list.
  • HEAD is a symbolic reference to (the Reference ID of) the commit at the end of the branch. It identifies what the current repository is pointing to. It marks the branch that is advanced with the next commit.
  • The command ‘git branch’ displays a list of branches in your repository, and it marks the current branch with an asterisk next to its name.
  • Creating new branches in Git is much simpler than in centralized version control systems. Branching is encouraged in Git - because it’s built on a very simple concept. To create a new branch in Git, you simply add a new branch label to the commit that HEAD point to.
  • You can switch to any branch just by changing the commit that HEAD points to, to point to the commit with that branch label. In Git, you use the git checkout command to switch branches (which is confusing for CVCS users because checkout doesn’t mean what they’re used to).
  • In Git, you’re encouraged to create branches way more often than in centralized VCSs. As a result, you can think of Git branches as throwaway changesets.
  • The default branch is called master.
  • You synchronize your repository with a remote repository using git push and git pull. You use push to update the remote repository with your latest bits, and you use pull to update your repository with the remote repository’s changes. Either way, when you’re done, both repositories contain the same thing (assuming you pulled first).

Note

For this reason, always pull before you push.

  • If you clone an existing repository, then a remote named Origin is automatically set up for you. You keep up-to-date with what’s happening on the remote repository by executing git pull origin. “Origin” is the name of the default remote, but you can have many remotes per repository. E.g.,
git remote add github http://github.com/alblue/babel.git
git push github
  • Git allows you to “Commit” files, much like any other VCS. Each commit can be a single file, or many files; and a message goes along with it.
  • Unlike other VCS’s, Git has a separate concept of a staging area, or Index. When you want to track a file (i.e., add it to the repository), you stage it (i.e., add it to the index). In other words, when you stage a file (or files), you can then commit them to the respository. The index contains a set of files to be committed. You can think of it as an active changeset; as you’re working on multiple files, you want only some changes to be committed as a unit. First, you git add the files to the Index, then you git commit subsequently.
  • git add - to add untracked files for change tracking, and to update already staged files.
  • git commit - commits the staged files. Creates a commit object, and adds it to the graph.
  • You have to git add a file in order for it to be tracked. After you add it to the staging area, you can keep working on it - you just have to continually save it to the file system. When you’re finished with the file, you can then commit it. Once committed, you can then push it up to the origin repository.
  • When you run git fetch, you get the newest commits from Origin, but they are not merged into your current branch. Just the remote refs are updated. I.e., all of the remote branches are updated in your local repository.
  • git fetch followed by git merge = git pull
  • A fast-forward is the simplest kind of merge (i.e., with no conflicts). It just brings your branch up-to-date with the same branch on a remote repository (origin). All it does is download the changesets that exist on the remote, that don’t exist in your repository, and then it updates your “HEAD” to point to the new branch tip.
  • Rebasing simplifies the repoisitory tree structre. It replays a series of commits upon a specified commit. ‘git rebase’ - Reapplies a series of changes from a branch to a different branch, and resets the head of that branch to the result.

Rebasing replants your tree - but do it on local branches only!

Points of note

Git’s unusual relationship with the file system

Git plays a kind of slight-of-hand with the contents of your local file system. The contents of all of the branches in a Git repo appear to occupy the same place on your local disk. No other CVS does this, so it’s a paradigm shift that you need to comprehend to really understand the nature of Git. E.g., You check-out a particular branch, and then cd to one of its directories. You open a file in that directory (called index.rst say), and it contains one sentence of text. Next, you checkout another branch, and open the same file, in the same directory. This time however, the file contains an entire paragraph of text (for example) - same place on the hard drive, but different contents.

Git repository

A Git repository contains all of the information needed to transform its working directory file structure into a snapshot of any commit in any branch. Take a look in any repository’s “.git” directory - especially the “objects” directory, to see the bits that Git assembles it from. By convention, I store my repositories in %USERPROFILE% in a directory called src (%USERPROFILE%src).

Git branch

A branch holds a set of incremental changes to files and folders in a repository (snapshots, HSAs). Internally, Git represents branchs as tree objects. Branches are identified by a reference on the last commit. At any time, the state of the files that you’re working on belong to a snapshot called “the Working Directory”. As your work progresses, you frequently save your work in progress (using the file system save feature). Each time you save your work, Git updates a branch snapshot called “index”. If you have staged changes, and you create a new branch and then switch to it, the state of the staging area isn’t changed. You can use the index like any ref. I.e., you can diff between index and the last commit.

Git changeset

Leverage Git branching to help you manage documentation updates

In the project I was workikng on, my mainline on Origin was a branch called feature/api_doc. I’d merge my completed work into this branch, and then push it to origin.

Note

Don’t use feature/api_doc for your work in progress.

Instead, create a new branch for the new work (e.g., named after the new feature), and complete the work in that branch, and then merge the new branch into feature/api_doc - after you’ve completed the update (which includes draft, technical review, update content per technical review, second review, etc.). Then you Push your merge commit up to origin, and then send a pull request to the lead dev to have your new content merged into mainline.

Base the new branch on feature/api_doc.

  1. Checkout feature/api_doc.

  2. Update feature/api_doc (Pull) to ensure that you’re in synch with origin.

  3. Create a new branch (e.g., git branch -b Verify_Code_Sample_Update)

    1. In Eclipse, switch to the Git Repository view.

    2. Right-click the repository that you want to create the new branch in.

    3. Click Switch To > New Branch.

    4. Enter a name for the new branch (e.g., Verify_Code_Sample_Update).

      No Pull Strategy.

      Checkout new branch.

      When you commit content to this branch, Git manages a reference (SHA) to it named: refs/heads/Verify_Code_Sample_Update.

Git actions

To contribute to a project hosted on GitHub

This procedure assumes that you cannot make commits to the origin repo. I.e, that you must issue a Pull Request from the Admin of the Origin repo.

  1. Visit the project repository on GitHub.
  2. “Fork” it. This creates your own copy of it on GitHub - under your GitHub account. This copy is “downstream” from the original project repository, which is in turn, “upstream” in relation to this copy.
  3. “Clone” a copy of your GitHub-hosted version of this repository. This creates a local working copy of the repository on your hard drive. In relation to this working copy of the repository, your GitHub-hosted copy is a remote (which you can refer to as “origin” (refs/remote/origin/)). The original repo that you forked from is now Upstream from Origin. To get your revisions into the upstream repo, you must issue a pull request.

Note

You end up with two enlistments: one under your account on GitHub, and another on your local hard drive.

To clone a repository

In Source Depot, this would be called “branching”. In Git, Cloning is much simpler, and yet, more powerful. Cloning produces a “working copy” of a project repository on your local hard drive. This is where you add/edit/delete source files.

To merge a branch

This updates the current branch with the difference in content (Git repository directory structure, directory contents, files, and file contents) between itself and another branch in the same repository.

To perform a merge:

  1. Switch to the branch (Checkout) that you want to receive the new content.
  2. Update your local copy of that branch (fetch).
  3. Run the merge.

In the simplest case, there are no conflicts (e.g., you’re just adding content).

For example, consider the case where the other branch contains the exact same files, except one of them contains an extra class definition. After merging them, the current branch would also contain the new class defintion (as well as any new content that is not in the second branch).

To update your repository

Fetch

Get the remote data, and add it to my repo as another branch (i.e., as a remote branch).

Note: Remote branches don’t appear locally, automatically. To actually get a local copy, you need to perform:

git checkout remote/<branchname>

Pull

Fetches the remote data, and merges it in with the contents of the current branch (performs two steps in one).

What to download & install?

It seems like there are several different Git applications available, but after digging deeper into this issue, I discovered that the “two best choices” - are actually the same thing. If you click “Download” on both of these web sites,

You get the exact same file (and you get it from the same web server).

https://github.com/msysgit/msysgit/releases/download/Git-1.9.4-preview20140929/Git-1.9.4-preview20140929.exe

MinGW

MinGW, a contraction of “Minimalist GNU for Windows”, is a minimalist development environment for native Microsoft Windows applications. MinGW provides a complete open source programming tool set that is suitable for the development of native MS-Windows applications, that do not depend on any 3rd-party C-Runtime DLLs. It does depend on a number of DLLs provided by Microsoft themselves, as components of the operating system; most notable among these is MSVCRT.DLL, the Microsoft C runtime library. Additionally, threaded applications must ship with a freely distributable thread support DLL, provided as part of MinGW itself.

MinGW compilers provide access to the functionality of the Microsoft C runtime and some language-specific runtimes. MinGW, being Minimalist, does not, and never will, attempt to provide a POSIX runtime environment for POSIX application deployment on MS-Windows. If you want POSIX application deployment on this platform, please consider Cygwin instead.

MSys

MSys is an environment for Windows offering a Unix-type shell and a Perl interpreter. Because many parts of Git are still not builtins programmed in C, but instead shell and Perl scripts, Git for Windows needs such an environment.

msysGit

For historical reasons, the development of Git for Windows requires a development environment that resembles Unix more than Windows, and this development environment is called msysGit.

Git for Windows

Git for Windows is the installer that most people should download to be able to use Git on Windows.

Git setup

Download and Install the latest version of git. I believe this gives you the hard-core command-line version. This version is the one that also includes the GUI apps that you’re used to - git-gui and gitk (for visualizing the branches in a repo (sort of like looking at a map of the London Tube)).

URLs

Home Page: http://git-scm.com/

There is a download link on the home page - use it to download and install git on your computer. Note: the download link automatically targets your platform (i.e., it’s for Windows if you’re on Windows, Linux if your on Ubuntu, and OS/X if you’re on Yosamite).

Procedure

Install the Latest Stable Release.

Download and run

  1. Click the “Download for Windows” in the image of the monitor on the right (http://git-scm.com/download/win).
  2. I chose the 64-bit version.
  3. In the Download Toast Window, click Run.

In the git setup wizard

  1. Install to: C:\Program Files\Git
  2. Select Components: I chose everything (Start Menu Folder: Git).

Adjusting your PATH environment

Choose the default option: Run Git from Git Bash

Configuring the line ending conversions

Choose Checkout Windows-style, commit UNIX line endings.

Environment variables

Source folder

Set the Environment Variable that points to the folder you want to use as the root folder (where Git will save all of your cloned enlistments). E.g.,

GITSOURCE=%USERPROFILE%\src
Default editor

Set the environment variable for your editor (mine is EditPad Pro).

$EDITOR = C:\Program Files\Just Great Software\EditPad Pro 7\EditPadPro7.exe

After you install Git

You must configure your Git installation for first use. For more information, see Getting Started - First-Time Git Setup.

Setup your identity

Configure your username.

git config --global user.name "Chris Boorman"

The file C:UsersChris.gitconfig is created.

git config --global user.email cboorman@gmail.com

Give the executables admin priveledges

Edit the Properties of the following two executible files, and give them Admin Previliges for All Users.

C:\Program Files\Git\bin\sh.exe
C:\Program Files\Git\mingw64\bin\wish.exe

Add the git bash icon to the taskbar

Check to see if there is already an icon for it on your desktop. If there is, then right-click it, and select Display on Taskbar.

Add the git GUI icon to the taskbar

Note: If you already have a git bash open, then simply type “git gui” to start the Git GUI. Type “gitk” to start the Git Branch Visualizer.

Target: “C:\Program Files\Git\bin\wish.exe” “C:\Program Files\Git\libexec\git-core\git-gui”

Start in: %GITSOURCE%

Set the default.push behavior

Note

If you’ve done this before, then you don’t have to do it again.

Set this to simple, which will push the current branch to its upstream counterpart, but only if there is an upstream counterpart.

git config --global push.default simple

Files to store in git

For java 3rd party

C:\Users\Chris\src\java_3rdParty\

Project level files
.classpath
overview.html
.project
ant.properties
README.rest
.gitignore

There are two places that you can store ignore lists.

  • In a file named “.gitignore” in the project’s root directory. This is for files that no one on the team wants tracked.
  • In a file named “exclude” in the project’s $GIT_DIR/info/exclude. This is for files that you want ignored for your own personal files, that you don’t want to share with the rest of the team.
Syntax

In Git, back-slashes (\) are used to escape git’s special symbols (e.g., ! becomes \! for a filename spec that begins with a bang).

In Git, forward-slashes (/) are used to denote a level in a path structure. You don’t have to include the trailing slash in a folder name. Git ignores the directory, and everything it contains. I.e., the rest of the branch.

To exclude all files of a particular type, you must precede the filespec with an asterisk. E.g., “.pyc” won’t work. “*.pyc” will work.

Example
git ls-files --others --exclude-from=.git/info/exclude

Generated Files

doc\\user\\v1\\build

Personal Files

doc\\CJB_Custom_Dictionary.txt

Merge changes from another branch into this branch

git merge --no-ff scrub_verify_code

Push changes from a local branch to the same branch on the remote

git push origin feature/api_doc

Note

You must specify the branch because if you don’t, then Git attempts to push all branches.

Setup beyond compare as the external merge tool

Note: This only works from the Git bash. I was hoping to get it to work from the Git GUI, but I kept getting an error when I right-clicked the diff pane, and select Merge.

Create a new environment varible
MERGEHOME=C:\Program Files (x86)\Beyond Compare 4

Path it:

;%MERGEHOME%\

Note

If you use the Git for Windows’ bash command prompt instead of the default Windows command prompt, then you need to escape the $ character with .

Upadate the global .gitconfig file

Update your user configuration file (%USERPROFILE%.gitconfig) with the following information.

[diff]
tool = bc
[difftool “bc”]
path = C:\Program Files (x86)\Beyond Compare 4\BComp.exe
[merge]
tool = bc
[mergetool “bc”]
cmd = “C:\Program Files (x86)\Beyond Compare 4\BComp.exe” “$LOCAL” “$REMOTE” “$BASE” “$MERGED”

Running a merge using beyond compare

You need to merge when you pull (or merge) the latest version of the master branch into your branch. Git downlads a copy of the remote’s copy of the current branch, and then adds it to your repo. In your repo, it’s just another branch, and it’s named “upstream/master”.

git fetch upstream

Merge

git merge upstream/master

When you execute this command from the Git Bash:

git mergetool

To launch a 3-way merge on a particular file, use the command:

git mergetool foofile.txt
What happens when you run a merge

When you launch the Git Mergetool, the Beyond Compare 4 GUI appears, with the four 3-way merge panes loaded with:

Left Pane
Your version.
Middle Pane
The last version before you made your changes, and before it was changed in the remote.
Right Pane
The version in the remote.
Bottom Pane
Your new version - which will contain the merged content.

To change the root directory of your git installation

  1. Add a new directory named “src” to your Git root directory (C:\Users\Chris). I.e., C:\Users\Chris\src
  2. Create a new environment variable that points to it:
GITSOURCE = %HOME%\src
  1. Right-click the icon for Git Bash, and open it’s properties page.

  2. Set the “Start in value”=%GITSOURCE%

    (%HOMEDRIVE%%HOMEPATH%)

Git Bash Properties

Target: “C:\Program Files (x86)\Git\bin\sh.exe” –login -i”

For the x64 version: “C:\Program Files\Git\git-bash.exe” –cd-to-home

Using the SSH transfer protocol

Setting-up by copying existing keys from another machine

Simply copy the contents of the folder %USERPROFILE%.ssh from your source computer, to the same location on your destination computer. The folder contains five files:

known_hosts
id_rsa.pub
id-rsa
github_rsa.pub
github_rsa

First-time Setup

Note

When you get to step where you are to add your SSH key to GitHub, email your key to the git administrator instead.

Passphrase

Land Cruiser

Your private key

Saved in: C:\Users\Chris.ssh\id_rsa

Your public key

Saved in: C:\Users\Chris.ssh\id_rsa.pub.

Using git with eclipse

Background

I’m using Eclipse on Windows 10.

The Jgit API

Git functionality is programmatically exposed via the JGit API (Java library). To use Git in Eclipse, you install the plugin called EGit, which makes calls to the JGit library.

  • EGit - the EGit plugin is a Team Provider that implements the Git features in Eclipse.
  • JGit - the programming API Java library that implements the Git version control file access routines, network protocols, and core version control algorithms. JGit contains Git porcelain commands in the org.eclipse.jgit.api package.

Goal

To get the curent Git Commit SHA1 from the environment, you are going to have to write code that calls the JGit API.

The HEAD reference is a SHA1 of the current branch.

HEAD = ref: refs/heads/feature/api_doc
= C:\Users\Chris\src\python_rest_api.git\refs\heads\feature\api_doc

But it might not be what you want…

Remember that your work in progress resides in your Working Tree, and isn’t yet associated with a changeset.

As you edit your work, it currently resides in RAM. When you save your work, a snapshot of the current RAM image is copied into a file. When you stage your work, the current state of the file is converted into a git Blob, and is added to the Index to create the next changeset. When you commit your work, the Index becomes the current changeset (and is pointed to by the local HEAD ref).

If you want to find out which Change Set any topic in a doc set belongs to (perhaps by using View Source on the topic you’re currently viewing) - then you don’t want to know the Change Set SHA1 of HEAD if you simply built the docs as a matter of course of writing/editing. You’ll want the SHA1 of the commit that corresponds to the final committ, which you won’t get until you’ve completed the writing work.

JGit cookBook

This project has example code that demonstrates how to develope code using JGit.

Grab it

git clone git://github.com/centic9/jgit-cookbook

Build it and create Eclipse project files

mvn dependency:sources eclipse:eclipse package

Run it

Import the project into an Eclipse workspace and execute the snippets there.

How you can use git

First you need to learn how to use Git, but then you need to find a way to use Git. I.e., Create a workflow that exploits Git’s strengths. This wasn’t obvious to me at first. Heck, I’d never even considered it until someone suggested I read this: A successful Git Branching Model. I’d been struggling with using Git, and I just figured that was a normal part of the learning curve.

Leverage branching

It turns out that you can do some pretty neat things with Git because of the way Git branching works (which is fundamentally different than what you’re used to). I now see branching in Git as its greatest strength. As a technical writer, I use branching in pretty much that same way that the devs use it. The documentation I write is always released in-step with the products (APIs and SDKs) that the docs cover.

Whenever I start a new doc project, I begin by getting an enlistment to the code base.

  1. Open a Git bash session. The Git command prompt automatically positions you in your Git Home directory (e.g., /src).

    "C:\Program Files (x86)\Git\bin\sh.exe" --login -i
    
  2. Get an enlistment to the project source code repository (i.e., Clone it locally). Here’s an example:

    git clone git@git.c11.3rdParty.com:android_mobile_verification.git
    
  3. Change directories; move down from the HOME directory to the project directory. Notice that you currently have the Master branch checked out.

    cd android_mobile_verification/
    
  4. Switch to the develop branch because that’s where all of the new bits are staged for the dev’s code, and for your new doc content.

    git checkout develop
    
  5. Fork off of (i.e., create a new branch off of) develop to use as a baseline branch for doc work that your team can then merge in with their latest code bits. My team and I settled on the convention of the branch name feature/api_doc.

    git branch --track -l feature/api_doc
    

Note

the use of the track option to mark the start-point branch as “upstream” from the new branch. The track needs two dashes. The l switch is used to create the branch’s reflog. This activates recording of all changes made to the branch ref. This allows me to create a paper trail (isolate and capture each change in a uniqe commit) for each and every change that I make to the docs.

  1. Checkout your new feature/api_doc branch.

    git checkout feature/api_doc
    
  2. Fork off of (see Fork a repo) feature/api_doc for authoring content for a specific version of the docs (e.g., maybe the devs added a new feature for the next version of the product). I usually give the new branch a name that indicates the product release number that the new content is for, but if I have no idea what that will be, then I choose something that appropriately indicates the state of the docs.

    git branch --track -l initial
    
  3. Checkout your new working branch.

    git checkout initial
    
  4. Author new content. I.e., Add, revise, and/or delete content.

  5. Merge the content into your baseline branch. As the product evolves, and the devs add new features, this step updates existing content with new content. When I complete the content, and after it’s been reviewd, and I’ve incorporated the revisions, I switch back to the feature/api_doc branch, and then merge the new content into it (i.e., I execute a git merge coming from the branch I was just in). These particular command options ensure that each of the iindividual commit ref log entries from the work I did in the other branch appear in the feature/api_doc as well (otherwise, they appear as just one merge commit).

    
    

    git merge -s recursive -X theirs initial

  6. All that needs to happen now is to make sure that the new content is merged into the devs new code bits. This entails two steps:

    1. Push the content upstream.
    2. Send a Pull Request (e-mail) to the Release Management team.

How to?

How to start the git GUI

Allows you to use mouse clicks to perform git commands.

git gui

How to start gitk

Allows you to visualize the project history as a branch map.

git gitk

How to get an enlistment

When the project is hosted privately on a remote Git server

Important

You must establish a VPN connection to the remote Git server.

  1. Open a Git bash prompt. You can simply click the shortcut on your Taskbar (or “C:Program Files (x86)Gitbinsh.exe” –login -i).
  2. Make sure you’re in your GIT_HOME directory (%USERPROFILE%\src), and then execute the following commands.
git clone git@git.c11.3rdParty.com:python_rest_api.git

cd python_rest_api

git pull

git checkout feature/api_doc

When the project is hosted on GitHub

When a project is hosted on Github, you can’t push your changes to it. Instead, you have to submit a pull request. But you can only do that if you fork the project, and host your fork up on Github. But how can you work on content when you repository isn’t local? The answer is you “Clone in Desktop.” So,

The java 3rd party SDK

  1. Using your web browser, navigate to the project site on GitHub (for example, https://github.com/3rdParty/java_3rdParty.git), and click “Fork.”

  2. Navigate to your new forked version (https://github.com/%USERNAME%/java_3rdParty/).

  3. Clone the new forked version (i.e., make a local working copy of it). To Clone from the Python Bash (the preferred method).

    1. Launch MINGW32 (click the icon in the Task Bar).
    2. Execute: git clone https://github.com/%USERNAME%/java_3rdParty.git. Your forked repo on Github automatically becomes the remote for the cloned repo, called “origin”.

OR

To Clone using GitHub for Windows, you must have previously installed GutHub for Windows: http://windows.github.com/

Note

You’ll receive an e-mail message from github.com The following SSH key was added to your account: GitHub for Windows - Production 9d:86:da:ce:4b:e6:c6:d3:c7:47:57:c1:1b:32:f4:c7 If you believe this key was added in error, you can remove the key and disable access at the following location: https://github.com/settings/ssh

You must configure GutHub for Windows to downlad cloned repositories to your %USERPOFILE%/src/ directory. On your new forked repository web page, and click “Clone in Desktop”. Now you have a local, working copy of the project repository.

  1. cd to the new enlistment directory (e.g., java_3rdParty).
  2. Add the original source repo (under the 3rdParty GitHub account) as a remote named “upstream”.
git remote add upstream https://github.com/3rdParty/java_3rdParty.git

When you execute this command, nothing appears to happen (but something does).

  1. Fetch from both origin and upstream. This brings in new branch ‘master’ -> upstream/master.
git fetch --all
  1. Create a new local branch called develop, and check it out.
git checkout -b develop

Switched to a new branch 'develop'
  1. Create a new local branch called feature/doc_update, and check it out.
git checkout -b feature/doc_update

Your github enlistment for the Java sdk:

git@github.com:%USERNAME%/java_3rdParty.git
Note from Humnberto
Chris,
Please pull the latest version of the master branch into your branch and then repush. Run the following commands from your branch. If you haven’t already, please make sure that your upstream is configured.

https://help.github.com/articles/fork-a-repo

Commands to run after upstream has been configured.

git fetch upstream
git merge upstream/master

The python 3rd party SDK

To clone a Local working enlistment
  1. git clone https://github.com/%USERNAME%/python_3rdParty_sdk.git.
  2. cd python_3rdParty.
  3. git remote add upstream https://github.com/3rdParty/python_3rdParty.git.
  4. git fetch –all. This fetches from both origin and upstream. This brings in new branch ‘master’ -> upstream/master.
  5. git checkout -b develop. This create a new branch called ‘develop’, based on a snapshot of ‘master’.
  6. git checkout -b feature/doc_update.
  7. git push origin feature/doc_update.

How to sync to develop

Assuming that you are currently in your working branch.

git fetch origin

git merge origin/develop

How to resolve a merge conflict

Usually when you run a merge, it results in a fast forward. But sometimes things aren’t so simple.

Here’s a typical scenario where you have to resolve a merge conflict.

First, you perform:

git fetch origin

and then, you perform:

git merge origin/develop

and it results in a merge conflict. Automatic merge failed; fix conflicts and then commit the result.

To Resolve the Conflict

git mergetool

How to create a new branch for tracking new doc work

New/revised content is always/only considered new/revised in reference to the latest content in the feature/api_doc branch (I like to refer to this branch as my “Mainline” branch). As such, always author your new/revised content in a new branch spawned off of the feature/api_doc branch. The neat thing about this approach is that when you’ve completed and vetted your new content, you can update the docs using git merge (you simply check-out the mainline branch, and then merge-in the working branch).

If, while you worked on the new content (in its working branch), the mainline didn’t change, then the difference between the two branches will be just the commits on the working branch.

  • If you merge the new content into feature/api_doc, it produces a Fast Forward. I.e,. feature/api_doc HEAD is advanced by one commit; it is a Merge Commit, and it contains all of the individual commits for incremental updates you made to the content in the working branch.
  • you can switch back to mainline, and then pull the new content just by merging the commits from the spawned branch into feature/api_doc. This type of version tracking allows you to do things like undoing a content revision by simply rolling-back the commit.

If the cloned project has no develop branch

git branch -l develop

git checkout develop

git push origin develop

git checkout -b feature/doc_update

git push origin feature/doc_update

git branch --track -l migrate_comments

git checkout migrate_comments

If you’re not already on the feature/api_doc branch, then switch over to it

git checkout feature/api_doc

Check to make sure the working directory is clean (just in case).

git status

Update your local repository

git fetch

or

git fetch origin

You can omit “origin” if your repo is already setup with a default path-spec. To find out, try running “git fetch” and see what happens.

Spawn a new branch off of feature/api_doc

This git command for this, along with its options, is somewhat complicated. Here’s a breakdown of the pieces.

Set the command options

When creating a new branch, mark the start-point branch as upstream from the new branch. Note that track needs two dashes. I noticed that when I pasted the command line into the BASH, one dash was missing!

--track

Note

At this point, I’m not sure if you need to track the starting branch though. Tracking is useful when the spawned-from branch keeps growing due to other people’s commits. In that case, you, along with each of the other contributers should each keep your working directory up to date with respect to the spawned-from branch. Why? Because the assumption is that everyone contributing to the project always contribute to the current state of it. Think of it as a way to simulate the same experience for each contributor as if they were working on the mainline, alone. In your case, there are no other contributers. As such, the spawned-from branch should never change. That is unless you work on more than one content update at a time.

Ok then: You definately do need to use that tracking feature because you sometimes have to have more than on working branches going at the same time. This has already happened, and you didn’t realize that after you’d merged the first woking branch’s content update into mainline, that you then needed to synchronize the second working branch with it (i.e., that you needed to checkout the second working branch, and then execute a “git pull” from it).

-l

Create the branch’s reflog. This activates recording of all changes made to the branch ref, enabling use of date based sha1 expressions such as “<branchname>@{yesterday}”.

Issue the command

It’s easiest if you simply copy & paste this command line example into a new document in EditPad Pro; and then modify it accordingly.

Note

I chose not to create and switch to the new branch in one operation using “git checkout -b” - because I wasn’t sure if I could still include the options I needed (–track and -l). I’ll experiment with this and see if it’s possible, and if it is, I’ll recommend that approach.

git branch --track -l v1.4x_updates

Branch v1.4x_updates set up to track local branch feature/api_doc.

Checkout the new branch

And start documenting the new feature.

git checkout v1.4x_updates

Switched to branch ‘v1.4x_updates’

Increment the doc build number

%GITSOURCE%\python_rest_api\doc\user\v1\source\conf.py

Add the new content files to the local repo

Use Stage Changed.

How to merge new completed content into your local feature/api_doc branch

Notes

It’s important that you execute a particular kind of merge. I.e., if you run a regular merge, all of your original individual commits will be transformed into one large fast-forward commit. A fast-forward only updates the HEAD pointer; it doesn’t create a commit object.

Note

You can’t just push the new commits into your mainline because the branch names differ. This can happen if another writer spawned and working branch, completed their work, and then merged their new content into your mainline (thus, advancing HEAD by one commit). Alternately, if you currently have another working branch with unfinished work. In both cases, all you have to do is execute git pull before you push, so it’s in synch with your mainline.

To can preserve the history of your revisions, you must specifying command line options:

  • Force “no fast forward” (–no-ff),
  • Show a difference statistic at the end of the merge (–stat),
  • Specify the use of the recursive strategy for the merge (-s recursive),
  • Specify that change priority be given to the new content (from in the source branch) (-X theirs),
  • Add a comment for the commit (-m).
Example

Merging the new content from /v1.4x_doc_update, into your local feature/api_doc branch.

git merge -s recursive -X theirs v1.43_doc_updates

Note

In Git terminology, the original content belongs to yours, and the new content belongs to theirs.

To avoid aborting an auto-merge when it hits a conflict (in particular, one that results from the insertion of a new item into the middle of a reference table), be sure to use the Recursive Merge Strategy, and use it with the theirs option. Why? Because this particular option forces conflicting content to be auto-resolved cleanly by favoring the new content.

Example
git merge -s recursive -X theirs v1.43_doc_updates

For more information, see: https://www.kernel.org/pub/software/scm/git/docs/git-merge.html.

1. Rebuild the docs

In Eclipse, click Run > Run History > 1 Rebuild HTML Docs.

2. Archive this doc build

Copy this version of the docs

Use this time-saving trick: Double-click the link below and Windows Explorer automatically opens, displaying the directory of the current build. Click anywhere in the contents pane, Select All (Ctrl+A), and copy everything to the Clipboard (Ctrl+C).

C:\Users\Chris\src\python_rest_api\doc\user\v1\build\html
Within this directory, create a new directory to hold this doc snapshot

Give it a name that indicates what made this doc version special. E.g., KeyPress.

Paste

Open the new directory, and paste the content of the Clipboard into it.

3. Make sure the working directory is clean

That is, make sure that you have no unstaged changes. In Eclipse, with the project folder selected in the PyDev Package Explorer, open the Git Staging tab, and click Refresh. If you have unstaged changes, stage them, and then commit them; and then go back and start again (from Step 1. Rebuild the docs).

4. Switch to the feature/api_doc branch

In Eclipse, right-click the project folder in the PyDev Package Explorer tab, and then click Team > Switch to > feature/api_doc.

Or from the git bash

Open a Git BASH, navigate to the current project working folder, and execute the following command:

$ git checkout feature/api_doc

5. Make sure your local branch is in synch (is up to date) with the remote repository

Update your local repository. This is a precautionary measure, in case the remote tracking branch has any commits that you don’t have locally. You didn’t do this once, and it caused you problems (which you easily solved by simply pulling - but it took you a while to figure out what the nature of the problems was).

Note

You must have a VPN connection to 3rdParty.

In Eclipse,

Right-click the project folder in the PyDev Package Explorer tab, and then click Team > Fetch from Upstream.

Or from the git bash
git fetch

6. Create the merge command line

Copy the example git command line below, to a new blank file in EditPad Pro, and revise the <comment/> and <branch_name/>, and then copy the line to the clip board.

git merge --stat --no-ff -m "<comment/>" -s recursive -X theirs <branch_name/>

E.g., (copy & paste from EditPad Pro)

git merge --stat --no-ff -m "Added HTTP status code 429 Too Many Requests" -s recursive -X theirs v1.43_updates

7. Execute the merge

At this point in time, I don’t know how to execute this commmand in Eclipse.

From the git bash

Click anywhere inside the Git command window, and then dump the contents of the clipboard onto the command line (Trick: right-click).

Note

The merge might have conflicts. If so, then run git mergetool.

Example
git merge --stat --no-ff -m "Added HTTP status code 429 Too Many Requests" -s recursive -X theirs v1.43_updates

8. How to resolve merge conflicts if any

Prerequesite: You’ve registered Beyond Compare 4 as the merge tool in the Git environment.

  1. Run the merge

From the Git BASH, execute the comnmand: git mergetool, and then press Return. Beyond Compare launches, and displays the original version of the file in the left pane, and the revised version in the right pane. The lines that conflict are highlighted.

  1. Accept revisions into the original file

In the bottom pane, accept each one in succession, and/or edit the content to your liking.

  1. When you’re done with that file, click File > Exit

This kicks you back to the Git BASH.

  1. If there’s another file conflict, just wrince & repeat

Press Return, and step through the conflicts in this file.

Note

At this point, the merge isn’t actually done, despite the fact that you’ve resolved all of the conflicts.

  1. Conclude the merge

Commit the merge object, and include an informative message.

git commit -m "Merged new content for R1.42 (Verify Registration)."

9. Push the new content upstream

That is, update remote refs along with the associated tree objects from your local feature/api_doc to origin feature/api_doc.

  1. From the git bash, enter the following command:
git push --tags
  1. Copy that last line (the one immediately above) so you can use it in the broadcast e-mail.
What to do when there isn’t yet, an upstream branch

You spell it out for Git. I.e., “Create a branch called ‘feature/doc_update’ in the origin repository”.

git push origin feature/doc_update

10. Check the local branch status

Just to make sure the push worked properly.

git status

11. Create a new branch for the next release

You should still have the feature/api_doc checked out, and it should now be up to date with respact to your latest bits. From here, spawn a new branch for your work for the next drop. From the Git BASH, enter the command:

git branch --track -l v1.4x_doc_updates

12. Send the broadcast email

Right after you push your doc updates to the origin repository, send a broadcast e-mail to the team summarizing the changes, asking for (making) a Pull Request, and CC PM (the PM distribution list).

Note

Set the Importance level to High.

In the body of the message, list the doc work items that went into this doc update. You can get this information quite easily in Eclipse. Simply select the Git Reflog tab. The line items of interest are the ones with “commit:” in the Reflog Messages.

E.g.

To: pm@3rdParty.com Importance: High

Subject: Pull Request: REST API Docs v1.51

I pushed a documentation update (To git@git.c11.3rdParty.com:python_rest_api.git 26d53cf..62ed6c1 feature/api_doc -> feature/api_docs ).

This update includes

  • TD-41 Fixed a broken link. “State Abbreviation Code” now links to http://pe.usps.com/text/pub28/28apb.htm.
  • TD-44 Changed Required to Optional, for the ‘ucid’ request parameter.
  • TD-45 Changed the default value for number of verification code digits that 3rdParty automatically generates by default from six, to five.
  • TD-48 Corrected two spelling mistakes.
  • TD-49 Corrected a spelling mistake.
  • TD-57 Added two new error codes:
    • -40008 [Product method] exceeded transaction hard cap; Request denied.
    • -60001 PhoneID Contact data not found).

Would you please pull from feature/api_docs, then rebuild the REST API doc set, and then publish it?

If this content update involved TechDoc bugs (Issues), then reolve them as fixed, and then add an appropriate comment

I incorporated this content update in v 1.51 of the REST API docs.

13. Increment the version number

Checkout the new branch. Open the file: doc/user/v1/source/conf.py. Rebuild the docs. Now the current doc build shows the upcoming release number.

14. Put the latest doc set up on Gullinx

Create a new directory. Copy the contents of C:\Users\Chris\src\python_rest_api\doc\user\v1\buildhtml.

How to pickup bits from another branch

git merge origin/develop

How to create a new branch, both locally, and in origin

  1. git clone git@git.c11.3rdParty.com:mobile_assets.git.
  2. git fetch –all.
  3. git checkout develop.
  4. git checkout -b feature/doc_update.
  5. git push origin feature/doc_update.

How to create a new branch for the mobile end user docs

1. Always use the local feature/api_doc as the starting point

git checkout feature/api_doc

2. Update your local repository

git fetch origin

3. Set the command options

When creating a new branch, set up configuration to mark the start-point branch as “upstream” from the new branch.

--track

Create the branch’s reflog. This activates recording of all changes made to the branch ref, enabling use of date based sha1 expressions such as “<branchname>@{yesterday}”.

-l
The name of the new branch
"MobileUserDocs"

Issue the command

git branch –track -l MobileUserDocs

4. Checkout the new branch

And start working on the AuthID End User documentation.

checkout MobileUserDocs

5. Update your .gitignore file to exclude oXygen’s temp files

doc/user/v1/source/mobile-content/temp

6. Add the new content files to the local repo

Use Stage Changed to get all of the new source files, as well as the 3rdParty.css fileds, the tsmobile.ditamap file, the .project file, and the .gitignore file.

E.g., commit message
First draft of AuthID End User documentation.

How to create a copy of one of the remote branches locally

Just check it out, using its local name.

E.g.,

git checkout release/current

How to recover a file that was deleted by a commit

I’m still not sure how this happened. It could have resulted from switching back and forth between the MobileUserDocs branch and the 2WaySMS branch. You altered your .gitignore to have it ignore

  1. Find the commit that deleted the file.
git rev-list -n 1 HEAD -- <file_path/>

E.g.,

git rev-list -n 1 HEAD -- doc/user/v1/source/mobile-content/topics/procedures.dita
  1. Checkout the file.
git checkout a39f1d72964dfc6240a7c1d9678a4add9b8bdb7d^ -- doc/user/v1/source/mobile-content/topics/procedures.dita

Or in one command

If $file is the file in question.

git checkout $(git rev-list -n 1 HEAD -- "$file")^ -- "$file"

Note

You must include the quotes.

E.g.,

File Name: “doc/user/v1/source/mobile-content/topics/concepts.dita”

git checkout $(git rev-list -n 1 HEAD -- "doc/user/v1/source/mobile-content/topics/concepts.dita")^ -- "doc/user/v1/source/mobile-content/topics/concepts.dita"

How to undo a commit

git reset HEAD~1

How to find out which files are tracked

git ls-files

How to remove content from the doc build

I documented a new feature a month ago, and it’s now live. But now 3rdParty wants me to pull it - because the commercial launch has been delayed.

Since you use a Git branching model to separate your work-in-progress from your published work, and then once you’ve completed the new work, you then merge it into the published doc set, you should be able to solve this issue using Git.

You can remove the Call Forwarding detection content by reversing the commit that represents it. When it’s time to put the content back, you do it by reverting the revert commit. You might think it makes sense to merge the content back in, as you originally did, but Git has captured that “action” as a commit object already (as a dimension, the concept of time takes on properties and behaviors in Git world!).

Here’s my research source: http://git-scm.com/blog/2010/03/02/undoing-merges.html

Notes

In Eclipse > Git Reflog (Java (Writing) perspective).

Looking at the entries in the Reflog Message column, you can easily see where new content was merged into your local main line branch. They’re the “Merge Commits” - the ones with the “merge” icon.

Can you filter-out all of the other commit types? Yes! Simpy type “merge” into the Filter field, and press Enter.

Procedure

  1. Establish a VPN connection, and then synchronize your repo (git fetch).
  2. Locate the merge commit for the new content.

Common git commands

Command Description
add Add file contents to the index
bisect Find by binary search the change that introduced a bug
branch List, create, or delete branches
checkout Checkout a branch or paths to the working tree
clone Clone a repository into a new directory
commit Record changes to the repository
diff Show changes between commits, commit and working tree, etc
fetch Download objects and refs from another repository
grep Print lines matching a pattern
init Create an empty git repository or reinitialize an existing one
log Show commit logs
merge Join two or more development histories together
mv Move or rename a file, a directory, or a symlink
pull Fetch from and merge with another repository or a local branch
push Update remote refs along with associated objects
rebase Forward-port local commits to the updated upstream head
reset Reset current HEAD to the specified state
rm Remove files from the working tree and from the index
show Show various types of objects
status Show the working tree status
tag Create, list, delete or verify a tag object signed with GPG

Ctrl+c to exit a listing.

Questions

Question: How can you list all of your tracking branches - and see each one’s immediate ancestor (i.e., the branch that each one was spun off of)?

Question: When you view a project in Eclipse (any of the Explorers), the Git plugin shows you the branch name along with two pieces of information: an up arrow followed by a number, and a down arrow followed by a number. Presumabely, this indicates the difference in state (the number of commits) between the current branch and the origin. Is there a way to find out what those differences are (in terms of content)?

Question: When you pushed content updates to origin, the operation failed because your repo was behind by a hundred or so commits. This scared you because you suspected something was out of whack - but it turned out not to be the case. Instead, the devs had just added some *.py files to the unit tests. All you had to do was a pull, and then push again - and it worked. You learned this after the fact though (i.e., after pulling - without be sure that that was what you were supposed to do). How could you have found out what the upstream changes were - before pulling (that is, fetching and merging) from origin (to avoid risking messing up your repo)?

Question: I created a local branch called feature/api_doc, spun-off of develop. How can I keep feature/api_doc in synch with origin?develop?

Misc git commands

git fetch origin git checkout feature/api_doc git merge origin/feature/api_doc

If you are in the middle of a merge conflict, do “git reset –hard” then you can pull

git rm -r -f build - to forc removal of files

git commit -m ‘Re-push without html files’

Git checkin sequence

git add source  (from doc/user/v1)

git commit -m 'message'

git pull origin feature/api_doc

(If you have to merge, run ‘git mergetool, which invokes kdiff3, and then commit again, pull again, and push)

git push origin feature/api_doc

git rm –cached filename

Note

Git will not ignore a file that was already tracked before a rule was added to this file to ignore it. In such a case the file must be untracked. rm is for remove - from being tracked by Git. It does not delete the file from your working tree.

Pro Git

Commands

Command Description
git add [file]
  • adds [file] to the index (stages the file).
git add -i
  • runs the interactive staging script.
git branch
  • lists branches.
git branch -a
  • lists all branches (both local and remote).
git branch [branch]
  • creates a new branch.
git branch -d [branch]
  • deletes a branch.
git branch –contains
  • shows which branches contained the named commit (HEAD if not specified).
git branch –merged
  • shows which branches are already merged into the branch you’re currently on.
git branch –no-merged
  • shows all of the branches that contain work that you haven’t yet merged in.
git branch –set-upstream-to origin/[branch]
  • sets this branch to track a remote branch. Remote branch must exist first.
git branch -v
  • shows the last commit on each branch.
git branch -vv
  • shows the tracking branches you have setup.
git cat-file -p HEAD
  • shows details (files) about the HEAD snapshot.
git checkout – <file>
  • unmodifies a modified file. Discards your changes. Reverts your file back to last commit.
git checkout [branch]
  • switches to another branch.
git checkout -b [branch]
  • creates and checks out a new branch.
git checkout -b [branch] [remote]/[branch]
  • creates and checks out a new branch, and also sets up a remote tracking branch.
git checkout –track [remote]/[branch]
  • creates and checks out a new branch, and also sets up a remote tracking branch.
git checkout –track origin/[branch]
  • creates a local tracking branch from a remote branch.
git clone <URL>-
  • clones a repository.
git commit –amend
  • adds more files to the last commit (that you still haven’t pushed).
git commit -m ‘message text’
  • commits staged files.
git config –list
  • lists your Git configuration.
git diff
  • shows changes in the working tree that are not yet staged.
git diff HEAD
  • shows changes in the working tree since your last commit.
git diff –cached
  • shows changes between the index and your last commit.
git diff –check
  • identifies possible white space errors, and lists them.
git diff –staged
  • same as git diff –cached.
git fetch [remote]
  • downloads all of the changes on the server that you don’t yet have.
git fetch –all
  • fetches all remotes.
git grep -n [search term]
  • finds the files that contain the search term. The -n switch prints the line numbers of matches.
git grep –count [search term]
  • finds the files that contain the search term, and how many times in each file.
git help <verb>
  • shows help on a particular command.
git init
  • creates a new, empty git repository.
git log
  • shows the history of commits, in revere chronological order.
git log –graph
  • shows a graphical representation (in ASCII) of your commit history (showing branches).
git log -p -2
  • generates a patch between the last two commits.
git log –pretty=oneline
  • shows commits one line at a time, pretty.
git log –since=2.weeks
  • shows the commits from the last two weeks.,
git log –stat
  • shows details for each commit.
git log [branch1]..[branch2]
  • shows what’s in branch1 that hasn’t yet been merged into branch2.
git log [remote]/[branch]..
  • shows the commits in your current branch, that aren’t in [origin]/[branch].
git log refA refB ^refC
  • shows all commits that are reachable from refA or refB, but not refC.
git log [branch1]…[branch2]
  • shows the commits that are not common to both branches.
git log -S [search term]
  • shows when the search term was introduced.
git log -L :[function name]:[file name]
  • shows the history of a function or line of code.
git ls-files -m
  • show files. In this case (-m) modified files. Also -s for staged files.
git ls-tree -r HEAD
  • lists the files in the HEAD tree, along with each one’s commit ID.
git merge @{upstream}
  • if this is a tracking branch, merges in remote tracking branch.
git merge [branch]
  • merges branch into current branch.
git merge –abort”
  • aborts the current merge.
git mergetool
  • runs a three-way merge (between local, remote, and common ancestor).
git mv <file_from> <file_to>
  • renames a file.
git pull [remote]
  • fetches and merge.
git push [remote] [branch name]
  • pushes to remote branch.
git push [remote] –delete [branch]
  • deletes a remote branch.
git push [remote] [tag name]
  • pushes a particular tag upstream.
git push [remote] –tags
  • pushes all tags.
git push –set-upstream [remote] [branch]
  • pushes the current branch, and creates the same branch on the remote, and tracks it.
git remote show [remote]
  • lists the details about a particular remote.
git remote
  • lists your remotes.
git reset <file>
  • unstages a file (essentially copies <file> from HEAD to index.
git reset [commit]
  • Moves HEAD to point to [commit].
git reset HEAD~
  • Removes the last commit. But also unstages files in the Index.
git reset –hard HEAD~
  • Removes the last commit. Cleans the index and working tree (nothing changed, nothing staged). Note: This is the dangerous version of the reset command - because you’ll lose your work in progress.
git reset –mixed HEAD~
  • Same as git reset HEAD~.
git reset –soft HEAD~
  • Undoes the last commit, without changing the working tree or the index.
git rev-parse branch
  • shows the commit that a particular branch points to.
git rm <file>
  • removes a file from the working tree and the index.
git show
  • shows details of the last commit.
git show HEAD@{n}
  • shows the commit that HEAD pointed to “n” commits ago.
git show [branch]@{yesterday}
  • shows the commit on a particular branch that HEAD pointed to yesterday.
git show HEAD@{2.months.ago}
  • shows the commit that HEAD pointed to two months ago.
git show HEAD^
  • shows the parent of HEAD.
git show d921970^2
  • shows the second parent of the specified commit. This only works for merge commits.
git show HEAD~n
  • shows the nth first parent. Equivalent to HEAD^^^ (for n = 3).
git stash
  • saves your staged and modified files on the stack.
git stash list
  • lists your stashes.
git stash apply
  • applies the last stash on your current index and working directory.
git stash apply index
  • also restages any files that are staged, but updates them with the stash.
git stash drop stash@{n}
  • deletes the specified stash.
git stash pop
  • applies a stash, and then deletes it from the stack.
git status
  • shows the status of your working tree.
git status -s
  • the short version of git status.
git tag v1.4
  • tags HEAD as v1.4.
git tag
  • lists all of the tags.

How to

Q: How can you see the differences in a file, between two commits?

A: In Eclipse, right-click the file in Git repository explorer (in the working tree), and then select “Show in > History”. Then, select the two commits in the History pane (hold Ctrl which selecting commit items), and then right-click and select “Compare with each other.

Git for ages four and up

Here are my notes from watching the video Git for Ages Four and Up. It contains a really good expanation of how Git works under the hood. The speaker (Michael G. Schwern <schwern@pobox.com>) created a new repository, and then created a new file, added some text to it, saved it, closed it, then added it to the Staging Area, and then committed it.

  • git add
    • Adds a file your working directory, to the staging area (the Index), as a BLOB.
  • git commit
    • Creates a “Commit” object from that BLOB.
      • That somehow points to the files that are stored in Git.
        • The commit contains all of the files in the repot - not just the ones that were just staged.
    • And attaches two labels (“References”) to it.
      • HEAD
        • The name of the most recent Commit.
        • Always points to the tip of the branch that you currently have checked-out.
      • MASTER
        • The name of the currently checked-out Branch.
        • The one that advances upon “git commit”.
  • When you create a branch,
    • All Git does is attach a new branch label to the Commit currently pointed to by HEAD.
  • When you perform a “git checkout”,
    • Git merely switches which branch it’s going to advance when you perform a “git commit”.
      • We say the branch becomes active.
    • And it moves HEAD to the commit object that has that branch label.
    • Git populates your Working Directory with a snapshot of the branches tip commit..
  • Commit ID
    • Content + Author + Date + Log + Previous Commit ID.
    • A hexadecimal UUID (Universally Unique Identifier).
    • Is a checksum (Hash)
    • Git calculates this value by running the bits in the BLOB through a function, which produces a thirty eight digit hexadecimal value.
  • Staging Area (Index).
    • Allows you to build up a commit.
    • You can add multiple files to the index, and then commit them (i.e., all files as one commit object).
  • The basic Git workflow.
    • You isolate your work from everyone else’s (spawn a new branch to work in).
    • Do some work (modify one or more files).
    • Update from everyone else (pull from origin).
    • Commit your work to your local enlistment (commit).
    • Finally, you share your work with everyone else (push to origin).
  • Merge.
    • git checkout your local master (feature/api_doc).
      • You’ll be bringing your work back into this branch.
    • Git performed a Fast Forward.
      • Since no merging of content (all modifications added new content).
        • A merge object wasn’t created.
      • All Git did was move the branch label to the commit from the ‘from’ branch.
      • Git also moved the HEAD label, because you have that branch checked out.
  • git reset –hard HEAD^
    • This undoes the last commit.
    • But all it does is move reference labels!
    • Moves the current branch label (Master), back one commit to HEAD-1.
    • –hard does a checkout, so that you end up where you want to be.
  • git log –graph –decorate –all
  • git commit does not mean share (inflict).
    • Commit is a local operation.
  • Merge
    • Git can merge in many different ways.
    • It picks the most convenient way.
    • Fast Forward is the simplest.
  • Working with others.
    • This is where remote repositories comes in.
      • remote commands.
        • Push, Fetch, and Pull.
  • Clone.
    • You normally start working on a clone of an existing repository.
    • When you clone a repository, git attaches labels to the objects in your local repository to mark the tracking branches.
      • origin/MASTER
      • Git clones only origin/MASTER (the default branch).
  • Directed Acyclic Graph.
    • Graph - a collection of nodes and edges.
    • Directed - the edges all point to the previous node.
    • Acyclic - there are no cycles. I.e., the path from one commit to any other is unique.
  • Pull.
    • Is actually a Fetch followed by a Merge.
    • When you’re starting out, it’s often easier to do a pull as two steps (a fetch followed by a merge).
  • We’re going to create a third repository.
    • So we can have someone other than us, doing work.
  • We’ll create a new branch called “bugfix”.
    • And we’ll create a new file in it called “baz”.
  • git push origin bugfix.
    • Sometimes you have a space between “origin” and “bugfix”, and sometimes you have a slash between them.
      • The slash version refers to the label (origin/bugfix) on your repository. This is a reference to a trackikng branch.
      • The space version refers to the remote (origin) branch (bugfix).
  • Push.
    • Does two things.
      • Git checks to see if the remote repository has the commit object your pushing.
        • If it doesn’t, then it checks to see if it has the ancestor commit object(s).
        • If it does, then
          • Git sends over the commit object (plus a branch label, if it’s on a new branch).
        • If it doesn’t, then
          • Git send all of the ancestors + the commit object.
    • This is where the cool thing about IDs comes in (this is why git is so amazingly fast).
      • Every ID is unique.
      • Every commit is unique.
      • Commits never change.
      • This means that every commit can be uniquely identified by its ID.
      • Since IDs contain the ID of the previous commit,
        • Every commit’s history can be uniquely identified by its ID.
        • Two devs push to the same repo without pulling…
          • If I have ae123, and you have ae123,
            • Then we know everything from ae123 on down is exactly the same.
  • Tag
    • Tags are good to use when you continually jump back to a particular snapshot.
    • E.g., git tag v1.0 bfce7
    • All Git does is add a label (reference) to the commit object you want to tag.
      • Excep that tag labels never move.
  • git reflog
    • This is your rescue command.
    • You can use this command when something gets screwed up, to find a particular commit ID.
    • Git shows you the commits you’ve been working on lately.
  • You can combine git add and git commit into one step.
    • E.g., git commit -a foo.
  • Rebase.
    • This is a local operation.
    • Example use: instead of fixing a typo and then committing the file again, you can perform a rebase instead.
    • Git rebase doesn’t rewrite history. It writes new history (you can’t actually change history in Git).
      • Instedad, git creates a whole new line of history.
    • Interactive rebase.
      • Go back two committs.
        • git rebase -i HEAD^^
        • Git says “I’m going to replay these things as if they were patches, one on top of the other.
          • Nothning happened! (because nothing changed).
        • You can “squash” a later commit into a previous commit (so the typo fix you made is written on top of the version with the typo).
          • I.e., you combine two (in this case) commits into a new commit.
          • The original two commits become detached!

Note

Once you have pushed, don’t rebase or you’ll screw up everyone else’s history! So never rebase until after you’ve pulled!

A successful git branching model

This refers to the explanation on the web site A Successful Git Branching Model. It was only after reading this article that Git really started to make sense to me. It’s an application of Git, and it seems that Git only makes semse whithin this context.

  • In this branching model, there are ohly two branches that live forever.
    • master
    • develop
  • origin/master
    • Where the source code of HEAD always reflects a production-ready state.
  • origin/develop
    • Where the source code of HEAD always reflects a state with the latest delivered development changes for the next release.
    • This branch is also known as the Integration branch.
    • This is where automatic nightly builds are built from.
  • When the source code in develop reaches a stable point and is ready to be released, all of the changes are merged back into master, and then tagged with a release number.
    • By definition, each time changes are merged into master, it’s a new production release.

Questions

  • Do you have to leave the branch you’re currently working in, to update?
  • How do you compare the contents of a modified by unstaged file with its staged version?
    • git diff –cached sounded like the right command, but it’s the exact same as git diff –staged, which shows the differ between what’s staged and the last commit.
  • What exactly does git fetch do - if it brings down everything that the remote server has that you don’t have?
    • I.e., If git merge brings those commits into your local branch, then what happens to those commits when you just fetch?
  • Before you push, you have to first bring your repo up to date - git fetch, followed by git merge. Do you have to switch back to the branch you branched off of first?