April 22, 2014

First look at Git - A quick refence to git commands!

This article has quick reference to key commands in Git ..

  • A commit in Git records the snapshot of your project. Each commit will have references to previous commits and thus the history is preserved.
    >> git commit

  • Branches in Git are incredibly light weight and are mere references to the commit; there is no storage overhead. Hence Git Enthusiasts chat the mantra, “branch early, and branch often”.
    >> git branch [name]   - create a branch
    >> gti checkout [name] – switch to branch
    >> gti checkout [name]; git commit – switch to branch and commit to the newly created branch

  • Merging – is the process of combining work between branches.
    >> git merge [name]  -> merge the branch [name] to the checked out branch

  • Rebasing is the second way of combining work between branches, which essentially takes a set of commits, “copies” them and moves it to selected branch.
    >> git rebase [name] -> rebase the checked out branch to the branch [name]
  • Head is the symbolic name for the currently checked out commit
  • Detaching HEAD just means attaching it to a commit instead of a branch
    >> git checkout master -> HEAD is master branch
    >> git checkout C1   -> Head is commit C1
  • Git Hashes
    Most DVCS tools, including Git, Mercurial, and Veracity, use cryptographic hashes. There are many algorithms for computing Git hash and Git uses
    SHA-1 (Secure Hash Algorithm)
     Git uses hashes in two important ways.
  • When you commit a file into your repository, Git calculates and remembers the hash of the contents of the file. When you later retrieve the file, Git can verify that the hash of the data being retrieved exactly matches the hash that was computed when it was stored. In this fashion, the hash serves as an integrity checksum, ensuring that the data has not been corrupted or altered.

  • Git also uses hash digests as database keys for looking up files and data.
  • Relative Reference
    In Git, each commit is referenced by unique hash and specifying the git by hash is not the most convenient way. Hence we have relative reference, where you start from somewhere memorable like a branch or a commit.
Let’s see how caret (^) & tilde (~) help us achieve that
Use ^ to move upward one character at a time
>> git checkout master^  -> moves the reference (HEAD) to one level up
>> git checkout HEAD^ -> moves the reference to one level up
So at this point, we have moved the reference to two commits up.
Use ~<num> to move number of times upwards
>> git checkout HEAD~
  • Branch forcing
You can reassign a branch a commit with –f (by force) option
>> git branch –f master HEAD~5
  • Reversing Changes in Git
Git Reset   >> git reset HEAD~1 -> moves the head revision one level up on our local repository. However this does not change on the remote branch in DVCS.
Git Revert >> git revert HEAD-> reverse the changes on the local repository and share the changes with others. This creates a new commit whereas git reset does not.
  • Git Cherry-pick
>> git cherry-pick <commit 1> <commit 2> <…>

>> git cherry-pick C3 C4 C8   -> copies the commits C3, C4 & C8 to the checked out branch. Note: each commit may be from same or different branches
  •  Git interactive rebase
Git cherry-pick can be used only when you know git hash (C3, C4 & C8 in the above example). Git interactive rebase comes into picture when you do not know the git hash.
>> git rebase -i  HEAD~4 - -aboveAll  -> once you enter the command, git list the hashes corresponding to 4 revision, which you re-order or remove and proceed.

>> git commit - -amend
  • Git Tags
Git Tags are used to permanently mark historical points (i.e. certain commits like major releases / big merges) in the project history as “milestones” that can be later referenced like a branch. They are ready-only. You cannot checkout from a tag and modify.
>> git tag <tag name> <commit number>

>> git tag v1 c1
  • Git Describe
>> git describe <ref>  -> where ref resolves to a commit, if not specified, git assumes the latest checked out commit or HEAD.
The output of the above command is
Where tag is the closest ancestor tag in history, numCommits is how many commits away that tag is, and <hash> is the hash of the commit being described.                                     
  •  Multiple Parents
Like tilde (~), caret can also have number but this is use to go upwards to parents rather than commits.
>> git checkout master^2

>> git checkout HEAD~; git checkout HEAD^2; git checkout HEAD~2  => can be combined into one command say git checkout HEAD~^2~2
  • Git Remotes
Git Remotes are nothing but copies of your own repository on local computer, which have a bunch of great properties out of which backup, sharing and collaborating are predominant.
Commands to create git remotes:
git clone – Traditional git world, git clone is used to make your own local copy from remote but here we are using it to create remote repository out of your local one.
  •  Git Remote Branches
Remote branches are always displayed in the format <remote name>/<branch name>
When you checkout from Git Remote, git commit will not automatically update the remote branch. Instead git just checkouts the code and creates a detached HEAD for you.
Remote branches reflect the state of the remote repositories since you last talked to those remotes.
  •   Git Fetching
 >> git fetch -> helps you to fetch data from a remote repository which are missing in local repository and updates the <remote name>/master to reflect the changes.
It talks to the remote repository through internet (via protocol like http:// or git://).
It is important to note that Git Fetch does not modify the user’s local copy or working copy (i.e. master).
  •  Git Pulling
>> git pull -> is literally git fetch followed by git merge (example: git fetch; git merge <remote name>/master -> Latest code is fetched from the remote master to <remote name>/master on your local and later merged to local master.
  • Git Pushing
>> git push -> is opposite of git pull, is responsible for uploading your changes to a specified remote and updating that remote to incorporate your new commits. It’s basically a command to publish your work.
git push is literally git fetch followed by git rebase.
  • Diverging History
Here are 3 different ways to update your local repository to update the changes from remote before you push your changes to remote
>> git fetch; git rebase <remote name>/master; git push
>> git fetch; git merge o/master; git push
>> git pull - -rebase  -> shorthand for git pull and rebase (whereas git pull is just shorthand for a fetch and a merge)
>> git pull; git push
  • Why rebase & why not merge while updating the remote?
Rebasing makes your commit tree look very clean since everything is in a straight line, hence some developers prefer rebase.
Where Rebasing modifies the (apparent) history of the commit tree but merge preserves the history, hence some developers prefer merge.
  • Remote Tracking
Remote tracking is property which establishes the connection between your remote branch, <remote name>/remote branch, which is set automatically when you clone the git repository.

By default, when you checkout <remote name>/master, git checks out to a local repository with the same name.
You are free to specify a different name with the following command.
>> git checkout -b NotMaster <remote name>/master -> this creates a new branch NotMaster to track <remote name>/master
>> git checkout -b NotMaster <remote name>/master
>> git branch -u <remote name>/master NotMaster -> git branch –u is to set tracking on remote branch
>> git branch -u <remote name>/master NotMaster; git commit; git push.
  •   Git Push Arguments
>> git push <remote name> <place>
>> git push origin master  -> Go to the branch named "master" in my repository, grab all the commits, and then go to the branch "master" on the remote named "origin." Place whatever commits are missing on that branch and then tell me when you're done.
The above example is where both the source and the destination has the same name. Many a times that can be different as well. <place> will be resolved into <source>:<destination> for different source and destination. This is commonly referred to as a colon refspec. Refspec is just a fancy name for a location that git can figure out
>> git push origin master:newBranch -> If the remote branch does not exist, git will create and move changes from source.
  •  Git Fetch Arguments
Git fetch arguments is similar to Git Push Arguments except we are downloading the changes to local.
>> git fetch origin <source>:<destination>
  • Oddities of <source> in git push, git fetch
>> git push origin :<branch name>
>> git fetch origin :bugFix
 Leaving source blank means, sending nothing. In push sending nothing will delete the destination whereas in fetch, sending nothing will create a new branch.
  •  Git Pull Arguments
>> git pull origin master  -> fetches the commits from origin master and merges it to the currently checkout branch
 The above commands are based on my leanings and understanding from the interactive visual training guide.