Monday, 28 December 2015

Git - Basics

Status, Add and Commit
In Git a file can be in one of the following three states.
  1. Working Directory
  2. Staging Index
  3. Repository
git status
You can view the status of all the files in any of the first two states using git status command.
  • git status
  • git status -s
  • git diff
  • git diff --staged or git diff --cached
There is $ git status command to view what is tracked/staged or is in working directory. There is a flag --short or -s too. The image describes how to read the short output.


git add
This command can perform one of the following actions.
  1. Start tracking a file 
  2. Add a file to staging area
  3. Mark a conflicted file resolved
$ git add <file_name>

Notes
  1. Tracked files are the ones which are in previous snapshot.
  2. If you add a file and then modify it; the modifications will be in working directory only. You have to execute $ git add again to make the changes part of same commit. 
git commit
When you make a commit Git checksums each subdirectory and stores those tree objects in Git repository. It stores a commit object that contains
  1. SHA-1 value for the commit
  2. a pointer to the snapshot of the content you staged
  3. author’s name and email, 
  4. the message that you typed, and 
  5. pointers to the commit or commits that directly came before this commit (its parent or parents)
The pointer to previous commit can point to -
  • zero parents for the initial commit, 
  • one parent for a normal commit, and 
  • multiple parents for a commit that results from a merge of two or more branches
When you have contents staged and execute $ git commit, it will open the editor to enter a message a commit the changes.

You can specify message inline by using
$git commit -m "Your commit message here"

To add all the tracked files in working directory into staging and commit at the same time, use
$git commit -a

To get details of all the changes automatically and make it part of commit message use,
$git commit -v

Best practices for writing commit message -
  • good descriptive commit messages - e.g. not "Fixed typo" but "Corrects spelling of Jhon"
  • start with short single-line summary with less than 50 characters
  • optionally you can add a blank line and a more complete description
  • keep each line in description less than 72 characters
  • write commit messages in present tense, not in past tense e.g. "Fix bug" or "Fixes bug" and not "Fixed Bug"
  • label the commit as what it does rather than what you did in that commit
  • add ticket number from issue tracking system
Removing Files

To remove a file from git you need to perform following two actions.
  1. Remove it from tracked files
  2. Delete from working directory
This is what $ git rm <file_name> command does. As this will delete the file from working directory too, you will not find the file anymore.

If you want git to stop tracking a file, but to keep it in working directory -
$ git rm --cached <file-name>

As git does its own file name expansion therefore escape characters are necessary infront of special characters. E.g. $ git rm log/\*.log Note the backslash (\) in front of the *.

Moving Files

If you rename a file directly git will treat it as old named file deleted and new name file created. Both will be untracked. E.g.

$ mv homepage.html new_home.html

$ git status -s
 D homepage.html
?? new_home.html

And if you do same using $ git mv it will correctly identify that file is renamed and it will stage the changes too.

$ git mv header.html new_home.html

$ git status -s
R  header.html -> new_home.html

Tagging

Git gives you the ability to tag important points in history. E.g when you release first version of the application, you can tag that commit on master branch as v1.0

$ git tag -a v1.0 -m 'my version 1.0' 

There are two types tags which you can create.
1. Lightweight
2. Annotated

Lightweight Tags
A lightweight tag is a checksum stored in a file with no other information. It is just a pointer to specific commit which doesn't change.

$ git tag v0.1-lw <optional_sha-1_value>

Now to list that tags,
$ git tag
v0.1-lw

And to see what the tag is pointing to,
$ git show v0.1-lw
commit d821d77b0435a79f249dc8cb0214434c74b4b56d
Author: Bob <bob@techmightsolutions.com>
Date:   Sun Dec 27 22:48:14 2015 +0530

    Adds header to website

Annotated Tags
Annotated tags are stored as full objects in Git database. It is always recommended to have annotated flag as -
  • they are checksummed
  • have tagger's name, email, date and message
  • can be signed and verified by GNU Privacy Guard (GPG)
$ git tag -a v0.1 -m "This is alpha version 0.1" <optional_sha-1_value>

$ git tag
v0.1
v0.1-lw

$ git show v0.1
tag v0.1
Tagger: Mary <mary@techmightsolutions.com>
Date:   Mon Dec 28 07:58:15 2015 +0530

This is alpha version 0.1

commit d821d77b0435a79f249dc8cb0214434c74b4b56d
Author: Bob<bob@techmightsolutions.com>
Date:   Sun Dec 27 22:48:14 2015 +0530

    Adds header to website

To share your tags,
$ git push origin --tags

Sunday, 27 December 2015

Git - Working with Branches

A Branch in git is an independent line of development. They are used for a developing a new feature or for doing some experiment. If the feature is developed or the experiment comes out green, then the branch is merged with master (default branch). If experiment fails then the branch can be deleted without impacting the primary line of development.

Use branches often because -
  • They are cheap.
  • They do not take processor power.
  • They do not consume storage space.
  • They are easy to create, delete and work with.
  • They allow you to try new ideas.
  • Switching between branches is very fast.

When you create a branch, a pointer is created which points to the commit from where the branch is created. HEAD always points to the tip of the branch (unless you make it point to some other commit). 

Branch Basics

View Branches
To view list of branches,
$ git branch
  add_content
* master
  seo_title

asterisk(*) tells the current branch you are on.

To view corresponding pointer files,
$ ls -l .git/refs/heads/
total 3
-rw-r--r-- 1 USER 197121 41 Dec 27 17:20 add_content
-rw-r--r-- 1 USER 197121 41 Dec 27 17:24 master
-rw-r--r-- 1 USER 197121 41 Dec 27 17:19 seo_title

If you view content of any of these files, they will point to a commit.
$ cat .git/refs/heads/master
f80d0b2367f10062e07321ff11fb85266d1ebc59

$ git log --oneline -1
f80d0b2 Merge branch 'add_content'

Create/Checkout a Branch
To create a branch,
$ git branch insert_place

You can see that  a pointer file is created,
$ ls -l .git/refs/heads/
total 4
-rw-r--r-- 1 USER 197121 41 Dec 27 17:20 add_content
-rw-r--r-- 1 USER 197121 41 Dec 27 17:40 insert_place
-rw-r--r-- 1 USER 197121 41 Dec 27 17:24 master
-rw-r--r-- 1 USER 197121 41 Dec 27 17:19 seo_title

It has not still switched the branch. You can do this by,
$ git checkout insert_place
Switched to branch 'insert_place'

The two steps of creating and switching branch can be done by using a single command as,
$ git checkout -b insert_place

Also note that working directory should be clean or you should stash your changes before switching branch otherwise git will abort the switching operation.

Rename a Branch
To rename a branch,
$ git branch --move insert_place insert_tourist_places

$ git branch
  add_content
* insert_tourist_places
  master
  seo_title

Delete a Branch
You can not chop the branch you are on. Hence first you have to switch to a different branch before deleting the branch you are on. To delete a branch you can use -d or -D (force delete) flag. 

$ git branch -d <branch_name>

Git will not allow to delete a branch having commits not merged with any other branch. Still if you wish to delete then use -D.

Comparing Branches
To compare changes on two branches,
$ git diff master..insert_tourist_places
diff --git a/home.html b/home.html
index f417b9e..28c2713 100644
--- a/home.html
+++ b/home.html
@@ -2,5 +2,9 @@
        <body>
                India is the best place for tourists on earth.
                People from Mars also visit here frequently.
+               <ul>
+                       <li>India Gate</li>
+                       <li>Red Fort</li>
+               </ul>
        </body>
 </html>

To view all other branches from where the commits have already been merged, 
$ git branch --merged
  add_content
* master
  seo_title

Note that it is not showing insert_tourist_places branch as it is having extra commits which are not on master branch.

Merging Branches & Resolving Conflicts (if any)

Once a feature development completes or an experiment turns out successful, you would like to merge the changes to the master branch. First you need to checkout master branch & then execute

$ git merge <feature_branch>

There are two types of merges that can happen. (Click Here for Details)
  1. Fast Forward Merge
  2. 3-Way Merge
Fast-Forward Merge
This happens when the HEAD pointer of master branch can be taken to the tip of feature_branch in a linear fashion. Following digram illustrates this.


This will not make any new commits in the history & in future you won't be able to identify that a feature branch has been merged. To stop fast forward and make it a verbose commit, even if fast forward is possible,

$ git merge --no-ff <feature_branch>

To tell git do the merge only if you can do it in fast forward fashion,

$ git merge --ff-only <feature_branch>

3-Way Merge
This happens when a fast-forward is not possible. When a 3-way merge occurs, an explicit commit is made which merges the 2 commits of merging branches. Following diagram illustrates 3-way merge.



Resolving Conflicts

Conflict occurs when there are two different version of changes on same lines or on same set of lines. If changes are on different lines then git will merge both the changes and create one composite document.

There are three approaches to resolve merge conflict.

  1. Abort Merge $ git merge --abort
  2. Resolve manually
  3. User a merge tool

The best way to avoid conflicts is merge often.
Consider the following structure of branches.

Description - I am having a master branch. From that I have created website branch. And from website I have created  seo_title, hotfix_correct_title and visiting_places branch. Now let's do merging and resolve conflicts if it occurs.

$ git log --oneline website
d821d77 Adds header to website
9bffbda Adds home page
9f76373 Adds Index file
3a86518 Initial Checkin

Merging hotfix_correct_title to website -
This is going to be a fast forward merge. But I want to have a verbose commit, therefore

$ git merge --no-ff hotfix_correct_title
Merge made by the 'recursive' strategy.
 header.html | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

$ git branch -d hotfix_correct_title

Merging visiting_places to website -
This will be a 3 way merge as the master branch has already moved. Following diagram illustrates the current branch state.


$ git merge visiting_places
Merge made by the 'recursive' strategy.
 home.html | 5 +++++
 1 file changed, 5 insertions(+)

$ git branch -d visiting_places

And the branch structure is as follows.

Merging seo_title to website -
This merge will create conflict because header.html file has already been changed at the time of hotfix and merged with master.

$ git merge seo_title
Auto-merging header.html
CONFLICT (content): Merge conflict in header.html
Automatic merge failed; fix conflicts and then commit the result.

Now you are not really on website branch; rather you are on - (website|MERGING)

$  git status
On branch website
You have unmerged paths.
  (fix conflicts and run "git commit")

Unmerged paths:
  (use "git add <file>..." to mark resolution)

        both modified:   header.html

Here if there are many conflicts or you are not sure how to resolve,
$ git merge --abort

But if you want to continue then you have to resolve the conflict manually, add and commit it. 

When you open header.html it will be as follows.

<html>
        <body>
<<<<<<< HEAD
                <h1>Incredible India - Heaven on Mars</h1>
                India offers a different aspect of her personality – exotic, extravagant, elegant, eclectic -- to each traveller to the country.
=======
                <h1>India - Heaven on planet Earth</h1>
>>>>>>> seo_title
        </body>
</html>

It is showing the changes in current branch from <<< HEAD to === and changes in seo_title branch from === to >>> seo_title.

Ok so I see that I have changed Mars to Earth. This change I wish to retain from seo_title. Other changes are good on website branch. Manually do the changes to look your file as follows.

<html>
        <body>
                <h1>Incredible India - Heaven on Earth</h1>
                India offers a different aspect of her personality – exotic, extravagant, elegant, eclectic -- to each traveller to the country.
        </body>
</html>

Save & quit. Then

$ git add header.html

$ git commit
[website 4b0deff] Merge branch 'seo_title' into website

$ git branch -d seo_title
Deleted branch seo_title (was 185c63d)


OR you can view the same branch structure via command line.

If I merge website with master now, it will be a fast forward merge.
$ git merge website
Updating 3a86518..4b0deff
Fast-forward
 header.html |  6 ++++++
 home.html   | 14 ++++++++++++++
 index.html  |  6 ++++++
 3 files changed, 26 insertions(+)
 create mode 100644 header.html
 create mode 100644 home.html
 create mode 100644 index.html

Friday, 25 December 2015

Git - HEAD and reset modes

HEAD

What is HEAD in a git repository? - It is a pointer to a commit. 

How can I check that?
$ cat .git/HEAD
ref: refs/heads/core-3

This tells HEAD is pointing to core-3 branch. In git branch is also a pointer. For all the branches you can get files created in .git/refs/heads storing commit SHA-1 values.

$ ls -l .git/refs/heads/
total 4
-rw-r--r-- 1 USER 197121 41 Dec 25 10:12 core
-rw-r--r-- 1 USER 197121 41 Dec 25 10:43 core-2
-rw-r--r-- 1 USER 197121 41 Dec 25 16:10 core-3
-rw-r--r-- 1 USER 197121 41 Dec 20 15:29 master

$ cat .git/refs/heads/master
3a86518414ad9fd99164ef5ad1abbba8190f9dda

And if you will view log it will be top most commit. The --decorate flag also tells position of each pointer.

$ git log --oneline --decorate
33fc97f (HEAD -> core-3) Reverts commit -> "Add item 1 and 4 into sidebar"
6ee1d05 Add item 2 and 3 in sidebar
ead6c93 Add item 1 and 4 into sidebar
ac79e95 Reverts commit -> "Adds bottom_bar, edits homepage and delees index"
e671180 Adds bottom_bar, edits homepage and deletes index
1e98c30 Adds commit to sidebar
cb23721 Adds index page of website.
cae4680 Add websites's Home page.
8816355 Adds body tag in header.html
94f8df4 Adds html with header.html
3a86518 (origin/master, master) Initial Checkin

How can I navigate from HEAD?
You can only navigate backwards from HEAD.
  • To access previous commit - HEAD^
  • To access previous to previous commit - HEAD^^ or HEAD~2
$ git checkout HEAD~5

But if you have SHA-1 value then you can directly take HEAD pointer to that commit using,
$ git checkout <SHA-1_value>

Rewriting History

Git allows you to rewrite history. It is more like a tape on which you can go back and record something else.

Where can it be used? - Consider you did certain commits and you realized that the commit stagings were incorrect. It need be merged or broken into more commits, in such a scenario you need to go back in history and redo the commits as you like. This is where you can use $ git reset.

BE CAUTIOUS while doing this, as you may loose your changes if you don't understand the repercussions.

SOFT Mode

In soft mode, when you do a reset to any previous commit then delta change (post previous commit to current commit) are shown in staging. Then you can do re-commits with modification.

E.g.

$ git log --oneline
0 = 33fc97f Reverts commit -> "Add item 1 and 4 into sidebar"
1 = 6ee1d05 Add item 2 and 3 in sidebar
2 = ead6c93 Add item 1 and 4 into sidebar
3 = ac79e95 Reverts commit -> "Adds bottom_bar, edits homepage and deletes index"
4 = e671180 Adds bottom_bar, edits homepage and deletes index
5 = 1e98c30 Adds commit to sidebar
6 = cb23721 Adds index page of website.
7 = cae4680 Add websites's Home page.
8 = 8816355 Adds body tag in header.html
9 = 94f8df4 Adds html with header.html
10 = 3a86518 Initial Checkin

$ git reset HEAD~7 --soft

$ git log --oneline
cae4680 Add websites's Home page.
8816355 Adds body tag in header.html
94f8df4 Adds html with header.html
3a86518 Initial Checkin

$ git status
On branch core-3
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   index.html
        new file:   sidebar.html

MIXED Mode

In mixed mode, when you do a reset to any previous commit then delta change (post previous commit to current commit) are shown in working directory. Then you can do re-commits with modification and staging.

E.g.

$ git log --oneline
33fc97f Reverts commit -> "Add item 1 and 4 into sidebar"
6ee1d05 Add item 2 and 3 in sidebar
ead6c93 Add item 1 and 4 into sidebar
ac79e95 Reverts commit -> "Adds bottom_bar, edits homepage and deltes index"
e671180 Adds bottom_bar, edits homepage and deltes index
1e98c30 Adds commit to sidebar
cb23721 Adds index page of website.
cae4680 Add websites's Home page.
8816355 Adds body tag in header.html
94f8df4 Adds html with header.html
3a86518 Initial Checkin

$ git reset HEAD~7 --mixed

$ git log --oneline
cae4680 Add websites's Home page.
8816355 Adds body tag in header.html
94f8df4 Adds html with header.html
3a86518 Initial Checkin

$ git status
On branch core-5
Untracked files:
  (use "git add <file>..." to include in what will be committed)

        index.html
        sidebar.html

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

This is default mode. If you just execute $ git reset HEAD~7 it will consider --mixed mode.

HARD Mode

This is dangerous if you don't understand. When you do a hard reset to any previous commit then delta changes (post previous commit to current commit) are completely removed from the repository. You will neither find them in working nor in staging.

E.g.

$ git log --oneline
33fc97f Reverts commit -> "Add item 1 and 4 into sidebar"
6ee1d05 Add item 2 and 3 in sidebar
ead6c93 Add item 1 and 4 into sidebar
ac79e95 Reverts commit -> "Adds bottom_bar, edits homepage and deltes index"
e671180 Adds bottom_bar, edits homepage and deltes index
1e98c30 Adds commit to sidebar
cb23721 Adds index page of website.
cae4680 Add websites's Home page.
8816355 Adds body tag in header.html
94f8df4 Adds html with header.html
3a86518 Initial Checkin

$ git reset HEAD~7 --hard
HEAD is now at cae4680 Add websites's Home page.

$ git log --oneline
cae4680 Add websites's Home page.
8816355 Adds body tag in header.html
94f8df4 Adds html with header.html
3a86518 Initial Checkin

$ git status
On branch core-8
nothing to commit, working directory clean

If you want to set the working and staging area as it was after last commit -
$ git reset HEAD -- hard

Git - Undoing at different levels

New/Tracked/Staged Files

Scenario 1
Remove all the files from working directory which are not tracked.

Solution
First do dry run to see what all files will be removed.
$ git clean -n
Would remove a.log
Would remove b.log
Would remove c.log

And if you are ready execute following.
$ git clean -f
Removing a.log
Removing b.log
Removing c.log

Note: If in between dry run and actual execution, if you add any file to staging then it will not be removed.

Scenario 2
I was adding files to staging area for preparing a commit. But by mistake I added a file which should not be part of this commit. How to revert a file from staging to working directory?

Solution
Hint: If you execute $git status, it provides you with command to do this.
$ git status
On branch core
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)


        modified:   header.html


Execute following to bring header.html back from staging to working.
$ git reset HEAD -- header.html
Unstaged changes after reset:
M       header.html

Scenario 3
I changed a tracked file. Git started showing it as modified in working directory. But now I want to revert those changes in that particular file.

Solution
$ git checkout -- <file_name>

Scenario 4 [Retrieving old versions]
I changed a file and committed. I did series of changes and committed each time. Now I want to revert its state to 2 commits back from current commit.

Solution
$ git checkout HEAD~2 -- <file_name>

or

$ git checkout <sha-1_value> -- <file_name>

Note: Post checkout changes will be staged.

To undo this action and just get back to the state in which the file is in last commit,
$ git checkout HEAD -- header.html

Amending Last Commit

Scenario 1
I have committed header.html. But I missed index.html file which should also be part of that commit. How can I add index.html to my last commit and change commit message as well?

Solution
See how the git log looks -
$ git log --oneline
0ec1496 Adds heading 1 in header.html
8816355 Adds body tag in header.html
94f8df4 Adds html with header.html
3a86518 Initial Checkin

Add index.html (& other such files which you think should be part of last commit) to staging. Then
$ git commit --amend

This will open editor where you can also change the message and write-quit. Then see log again -
$ git log --oneline
0c31ce8 Adds heading 1 in header.html Also adds index.html
8816355 Adds body tag in header.html
94f8df4 Adds html with header.html
3a86518 Initial Checkin

Scenario 2
I just want to change message of previous commit.

Solution
Make sure that there is nothing in staging. Then execute following and change message.
$ git commit --amend

Reverting Commit

You can revert changes made by any commit but it is recorded in the history. It will

  • delete any file(s) if added
  • add any file(s) if deleted
  • restore any file(s) if modified in that commit.

Let's see it in action.

Scenario 1
Revert a commit

Solution
$ git log --oneline
1e98c30 Adds commit to sidebar
cb23721 Adds index page of website.
cae4680 Add websites's Home page.
8816355 Adds body tag in header.html
94f8df4 Adds html with header.html
3a86518 Initial Checkin

Add bottom_bar.html, modify homepage.html and delete index.html
Finally commit all your changes in one.

$ git log --oneline
e671180 Adds bottom_bar, edits homepage and deletes index
1e98c30 Adds commit to sidebar
cb23721 Adds index page of website.
cae4680 Add websites's Home page.
8816355 Adds body tag in header.html
94f8df4 Adds html with header.html
3a86518 Initial Checkin

Now do a git revert -

$ git revert HEAD
[core-3 ac79e95] Reverts commit -> "Adds bottom_bar, edits homepage and deletes index"
 3 files changed, 5 insertions(+), 3 deletions(-)
 delete mode 100644 bottom_bar.html
 create mode 100644 index.html

You will notice -
  • delete any file(s) if added - bottom_bar got deleted
  • add any file(s) if deleted - index.html created as it was deleted
  • restore any file(s) if modified in that commit - homepage.html is restored
And when you see history, it will show which commit was reverted.

$ git log --oneline
ac79e95 Reverts commit -> "Adds bottom_bar, edits homepage and deletes index"
e671180 Adds bottom_bar, edits homepage and deletes index
1e98c30 Adds commit to sidebar
cb23721 Adds index page of website.
cae4680 Add websites's Home page.
8816355 Adds body tag in header.html
94f8df4 Adds html with header.html
3a86518 Initial Checkin

Scenario 2
Abort a revert in progress waiting for a conflict to be resolved

Solution
Consider following file -
$ cat sidebar.html
<html>
        <body>
                <ul>
                        <li> Home </li>
                        <li> Contact Us </li>
                </ul>
        </body>
</html>

Commit log -

$ git log --oneline
ac79e95 Reverts commit -> "Adds bottom_bar, edits homepage and deltes index"
e671180 Adds bottom_bar, edits homepage and deltes index
1e98c30 Adds commit to sidebar
cb23721 Adds index page of website.
cae4680 Add websites's Home page.
8816355 Adds body tag in header.html
94f8df4 Adds html with header.html
3a86518 Initial Checkin

I add item 1 & item 4 and commits. Then I add item 2 & item 3 and commits. Commit log is as follows.

$ git log --oneline
6ee1d05 Add item 2 and 3 in sidebar
ead6c93 Add item 1 and 4 into sidebar
ac79e95 Reverts commit -> "Adds bottom_bar, edits homepage and deltes index"
e671180 Adds bottom_bar, edits homepage and deltes index
1e98c30 Adds commit to sidebar
cb23721 Adds index page of website.
cae4680 Add websites's Home page.
8816355 Adds body tag in header.html
94f8df4 Adds html with header.html
3a86518 Initial Checkin

Now I want commit one up the header to be reverted.

$ git revert HEAD^
error: could not revert ead6c93... Add item 1 and 4 into sidebar
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'

There is error as it is not able to revert sidebar to ead6c93 version as the file is also edited in 6ee1d05.

$ git status
On branch core-3
You are currently reverting commit ead6c93.
  (fix conflicts and run "git revert --continue")
  (use "git revert --abort" to cancel the revert operation)

Unmerged paths:
  (use "git reset HEAD <file>..." to unstage)
  (use "git add <file>..." to mark resolution)

        both modified:   sidebar.html

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

Now you need to resolve this conflict or abort the revert operation.

$ git revert --abort

Scenario 3
Resolving a conflict and continue with revert.

Solution
Consider Scenario 2 only just that we will resolve the conflict and continue with revert. Resolve the conflict in sidebar.html file.

$ cat sidebar.html
<html>
        <body>
                <ul>
                        <li> Home </li>
                        <li> Item 2 </li>
                        <li> Item 3 </li>
                        <li> Contact Us </li>
                </ul>
        </body>
</html>

Add it to staging
$ git add sidebar.html

Continue revert operation (it will open editor to enter commit message)

$ git revert --continue
[core-3 33fc97f] Reverts commit -> "Add item 1 and 4 into sidebar"
 1 file changed, 2 deletions(-)

And finally see your commit log.
$ git log --oneline
33fc97f Reverts commit -> "Add item 1 and 4 into sidebar"
6ee1d05 Add item 2 and 3 in sidebar
ead6c93 Add item 1 and 4 into sidebar
ac79e95 Reverts commit -> "Adds bottom_bar, edits homepage and deltes index"
e671180 Adds bottom_bar, edits homepage and deltes index
1e98c30 Adds commit to sidebar
cb23721 Adds index page of website.
cae4680 Add websites's Home page.
8816355 Adds body tag in header.html
94f8df4 Adds html with header.html
3a86518 Initial Checkin

There is more to it - how can you rewrite history? Click here to know more. 

Monday, 21 December 2015

Git - Configuration & Aliases

$ git config allows to get & set configuration variables that controls how git looks and operates from system level to individual repository clone. The variables can be stored in 3 different locations.

1. /etc/gitconfig file: Contains values for every user on the system and all their repositories. If you pass the option --system to git config, it reads and writes from this file specifically. Attempt to access this file on windows resulted in following error.

$ git config --system --list
fatal: unable to read config file 'C:\Program Files\Git\mingw64/etc/gitconfig': No such file or directory

2. ~/.gitconfig or ~/.config/git/config file: Specific to your user. You can make Git read and write to this file specifically by passing the --global option.

3. config file in the Git directory (that is, .git/config) of whatever repository you’re currently using: Specific to that single repository.

Each level overrides the value of previous level, so values in .git/config trump those in /etc/gitconfig.

Set your Identity

Your identity will be used in commit messages. To set identity,
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com

This will add following entry in ~/.gitconfig file.
[user]
        email = johndoe@example.com
        name = "John Doe"
Notice that user becomes section title and all the attribute values are added under user section.

Git will use this value from all repositories if it is not locally overridden.

Set Editor

$ git config --global core.editor vi

Checking the Settings

To view only local settings -
$ git config --local --list

To view global settings -
$ git config --global --list

To view system settings -
$ git config --system --list

To view all the settings merged into one with their final values -
$ git config --list

Get Help

To get help on any of the git commands -
$ git help <verb>
$ git <verb> --help
$ man git-<verb>

Set Alias

There are certain commands which are extensively used. They can be aliased as follows.
$ git config --global alias.st status

.. And then execute as -
$ git st

Following is a nice alias to set -
$ git config --global alias.hist 'log --pretty=format:"%h %ad | %s%d [%an]" --graph --date=short'
$ git hist
* 3a86518 2015-12-20 | Initial Checkin (HEAD -> master, origin/master) [Sibtain]

You can setup following aliases.
[alias]
  co = checkout
  ci = commit
  st = status
  br = branch
  hist = log --pretty=format:\"%h %ad | %s%d [%an]\" --graph --date=short

Reference Link - http://githowto.com/aliases

Sunday, 20 December 2015

Git - Backgrounder

For a new developer it is mostly a challenge to -

  • keep track of changes in the development life cycle of a software application
  • collaborate with peer developers - how to merge changes
  • do some experiment, test and if it doesn't work - revert changes
  • continuing of main stream development by colleagues while I experiment with some new feature

The trivial approach (I have even used in early days) is to zip the files and name it - mostly a time stamp & then continue the main development. So if something unfortunate happens, I can revert to an old version at the expense of loosing all the delta changes. This is incredibly error prone.

It was very difficult to merge the changes of peers, keep track of change history and who changed what. It was always a challenge to go to each file and undo changes while reverting a failed experiment. And if there is any miss - hours required to detect and bring things back on track.

These pain points (& many such if you can count) are addressed by Source Code Management (SCM) or also called as Version Control System (VCS).

Let's talk about evolution of Version Control Systems. 

1] Local VCS - Programmers long ago developed local VCSs that had a simple database that kept all the changes to files under revision control. E.g. RCS distibuted by Mac OS X. But it doesn't address the collaboration challenge.

2] Centralized VCS - It was developed to address the need to collaborate with developers on other systems. C-VCS have a central server which keeps track of file versions and clients who have checked out. The commits made by clients hit directly to the central server. This is a lot chatty as client commits changes directly on central server. 

The advantage was
  • track of changes from other developers
  • fine-grained control to admins for who can change what

But there are some serious downsides viz.
  • The central server is single point of failure. If server goes down, the development will halt as people will not be able to checkin their changes and collaborate.
  • If the HD of central server database corrupts (with no proper backup) everything is lost, except what we have in dev shadows.

It was & is being used for the projects which are on  C-VCS such as CVS, Subversion & Perforce, but efforts are being made to migrate to DVCS such as git. 

3] Distributed VCS - E.g. Git, Mercurial, Bazaar, Darcas

In D-VCS, client just doesn't checkout files but the fully mirror the repository. The client can now perform all the operations on the local clone of central repo. You can also collaborate with different repositories of the project. Such workflows can't be achieved in a centralized setup.

Git - A Short History

From 1991-2002 the development of Linux Kernal and changes to software were passed around as archived files. In 2002 Linux community started using a proprietary D-VCS BitKeeper. 

In 2005, the relationships between developer community of Linux kernel and commercial company that owns BitKeeper broke down. This prompted Linus Torvald to build their own D-VCS better than BitKeepr based on lessons learned. They goals for new D-VCS were - 
  • Speed
  • Simple Design
  • Strong support for non-linear development
  • Fully distrubuted
  • Ability to handle large projects (like Linux Kernel)

And the answer to all is Git which is developed in 2005 and evolved over a period of time.
  
Git - Versus other VCS

Snapshots, Not Differences

Other VCS maintains data as set of files and history of changes made to each file over time. When you commit, git takes a picture of how all the files look and stores reference to the snapshot. If files haven't changed then from the snapshot there will be a link to previous identical file. So for git it is more like stream of snapshots.

Nearly Every operation is local

Most operations in git requires local files and resources to operate & no information is required from other computer on the network. -- means No Network Latency Overhead ==> SPEED. You can view your history locally.

Integrity

Everything in git is check-summed using SHA-1 hash before it is stored. It is a 40 character hexadecimal string. The first 10 characters of hash value are sufficient to identify a checkin (snapshot) uniquely.

The Three States

[IMP] A git repository has three states. Each file in the repo resides in one of these states. 

 Modified State (Working Directory) - A git file untracked or modified will be in this state. To remove all the files which are in working directory $git clean -f

Stage (Staging Area) - A file added using $git add becomes staged. The staging area holds the files which will be committed together when next commit is made. To unstage a file remove a file from staging area and to put it back in working directory $ git rm --cached <file_name>

Commit (Repository) - $git commit adds staged file into git repository creating a snapshot. 


Click here to setup and perform command line interaction with a git repository.

Do you like this article?