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…
- Create a new branch (like you would a saved game).
- Start gitK - so you can see the current state of the branch visually.
- Make your change (perform the operation).
- Before you refresh gitK, try to guess at what the change will look like.
- 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.
Checkout feature/api_doc.
Update feature/api_doc (Pull) to ensure that you’re in synch with origin.
Create a new branch (e.g., git branch -b Verify_Code_Sample_Update)
In Eclipse, switch to the Git Repository view.
Right-click the repository that you want to create the new branch in.
Click Switch To > New Branch.
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.
- Visit the project repository on GitHub.
- “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.
- “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:
- Switch to the branch (Checkout) that you want to receive the new content.
- Update your local copy of that branch (fetch).
- 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).
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).
- For the record, here’s the download page: http://git-scm.com/downloads
- At some point later, you might want to try the GitHub Windows Client.
- Project on GitHub: https://github.com/msysgit/msysgit
- Setup Help: http://help.github.com/win-set-up-git/
Procedure¶
Install the Latest Stable Release.
Download and run¶
- Click the “Download for Windows” in the image of the monitor on the right (http://git-scm.com/download/win).
- I chose the 64-bit version.
- In the Download Toast Window, click Run.
In the git setup wizard¶
- Install to: C:\Program Files\Git
- 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¶
- Add a new directory named “src” to your Git root directory (C:\Users\Chris). I.e., C:\Users\Chris\src
- Create a new environment variable that points to it:
GITSOURCE = %HOME%\src
Right-click the icon for Git Bash, and open it’s properties page.
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
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.
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
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
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/
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
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.
Checkout your new feature/api_doc branch.
git checkout feature/api_doc
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
Checkout your new working branch.
git checkout initial
Author new content. I.e., Add, revise, and/or delete content.
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
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:
- Push the content upstream.
- Send a Pull Request (e-mail) to the Release Management team.
How to?¶
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.
- Open a Git bash prompt. You can simply click the shortcut on your Taskbar (or “C:Program Files (x86)Gitbinsh.exe” –login -i).
- 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¶
Using your web browser, navigate to the project site on GitHub (for example, https://github.com/3rdParty/java_3rdParty.git), and click “Fork.”
Navigate to your new forked version (https://github.com/%USERNAME%/java_3rdParty/).
Clone the new forked version (i.e., make a local working copy of it). To Clone from the Python Bash (the preferred method).
- Launch MINGW32 (click the icon in the Task Bar).
- 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.
- cd to the new enlistment directory (e.g., java_3rdParty).
- 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).
- Fetch from both origin and upstream. This brings in new branch ‘master’ -> upstream/master.
git fetch --all
- Create a new local branch called develop, and check it out.
git checkout -b develop
Switched to a new branch 'develop'
- 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¶
- git clone https://github.com/%USERNAME%/python_3rdParty_sdk.git.
- cd python_3rdParty.
- git remote add upstream https://github.com/3rdParty/python_3rdParty.git.
- git fetch –all. This fetches from both origin and upstream. This brings in new branch ‘master’ -> upstream/master.
- git checkout -b develop. This create a new branch called ‘develop’, based on a snapshot of ‘master’.
- git checkout -b feature/doc_update.
- 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.
- 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.
- Accept revisions into the original file
In the bottom pane, accept each one in succession, and/or edit the content to your liking.
- When you’re done with that file, click File > Exit
This kicks you back to the Git BASH.
- 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.
- 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.
- From the git bash, enter the following command:
git push --tags
- 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
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¶
- git clone git@git.c11.3rdParty.com:mobile_assets.git.
- git fetch –all.
- git checkout develop.
- git checkout -b feature/doc_update.
- 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
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
- 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
- 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¶
- Establish a VPN connection, and then synchronize your repo (git fetch).
- 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] |
|
git add -i |
|
git branch |
|
git branch -a |
|
git branch [branch] |
|
git branch -d [branch] |
|
git branch –contains |
|
git branch –merged |
|
git branch –no-merged |
|
git branch –set-upstream-to origin/[branch] |
|
git branch -v |
|
git branch -vv |
|
git cat-file -p HEAD |
|
git checkout – <file> |
|
git checkout [branch] |
|
git checkout -b [branch] |
|
git checkout -b [branch] [remote]/[branch] |
|
git checkout –track [remote]/[branch] |
|
git checkout –track origin/[branch] |
|
git clone <URL>- |
|
git commit –amend |
|
git commit -m ‘message text’ |
|
git config –list |
|
git diff |
|
git diff HEAD |
|
git diff –cached |
|
git diff –check |
|
git diff –staged |
|
git fetch [remote] |
|
git fetch –all |
|
git grep -n [search term] |
|
git grep –count [search term] |
|
git help <verb> |
|
git init |
|
git log |
|
git log –graph |
|
git log -p -2 |
|
git log –pretty=oneline |
|
git log –since=2.weeks |
|
git log –stat |
|
git log [branch1]..[branch2] |
|
git log [remote]/[branch].. |
|
git log refA refB ^refC |
|
git log [branch1]…[branch2] |
|
git log -S [search term] |
|
git log -L :[function name]:[file name] |
|
git ls-files -m |
|
git ls-tree -r HEAD |
|
git merge @{upstream} |
|
git merge [branch] |
|
git merge –abort” |
|
git mergetool |
|
git mv <file_from> <file_to> |
|
git pull [remote] |
|
git push [remote] [branch name] |
|
git push [remote] –delete [branch] |
|
git push [remote] [tag name] |
|
git push [remote] –tags |
|
git push –set-upstream [remote] [branch] |
|
git remote show [remote] |
|
git remote |
|
git reset <file> |
|
git reset [commit] |
|
git reset HEAD~ |
|
git reset –hard HEAD~ |
|
git reset –mixed HEAD~ |
|
git reset –soft HEAD~ |
|
git rev-parse branch |
|
git rm <file> |
|
git show |
|
git show HEAD@{n} |
|
git show [branch]@{yesterday} |
|
git show HEAD@{2.months.ago} |
|
git show HEAD^ |
|
git show d921970^2 |
|
git show HEAD~n |
|
git stash |
|
git stash list |
|
git stash apply |
|
git stash apply index |
|
git stash drop stash@{n} |
|
git stash pop |
|
git status |
|
git status -s |
|
git tag v1.4 |
|
git tag |
|
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?