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
<tag>_<numCommits>_g<hash>
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.

February 8, 2014

SCM - Branching Guidelines for Agile Development

This article discusses the principles and policies around the branching guideliness with examples for Agile Software Development.

Branch Policy

Independent of the tool used for source control management, Mainline or Trunk will be the stable main source tree, ready for release at any time.

Branching as part of source control management is intended for code-separation or code-isolation and it becomes inevitable under the following scenarios
  •  Release Branch for Major or Minor Releases
  •  Maintenance Branch for Patches / Hotfixes
  •  Feature Branch in case of Feature Driven Development (FDD)
  •  Team Branch in case of Agile Development or FDD where you branch to isolate sub-teams. 
Each team will have a development branch where they will do the day to day work.

 

Each team can promote or merge their finished stories to the mainline branch.
 
When all storied or features are done for a release, then create label (TFS) or TAG in SVN with the release name.
 
Ideally we would create the following branches for efficient code-isolation



  • Trunk or Mainline– Stable Code line
  • Dev – Feature or Team branch under development
  • Release –  From which the code is deployed to production
    • Maitenance - Fixes for code-breaks, if any, in production. This will be usually under the corresponding release branch.

    Branch Owner
    Each branch will have an appointed branch owner who will be responsible for enforcing branch policy and will be responsible for merging and resolving conflicts.
     
     
    Trunk or Mainline Branch

    The Trunk and Mainline branch is from where the releases are made. This line should never break otherwise the whole idea of having Team or Feature specific branch will go in vain.

    Trunk or Mainline Policy

     The name of the Branch will be either Trunk or Mainline

     1.    Can be released at any time
    At any moment, the product owner can decide that we should make a new production release directly from the tip of the mainline. A release branch can be created to proceed with the production release.
    2.    Want to release ASAP          We shouldn't check in or merge a finished story to Trunk unless it has to go live (or at  least wouldn't mind if it goes live).  

    Team Branches

    Team branch is for checking in stories which are in progress. This branch is also used to run integration tests before checking in stories to the Trunk and can be used by the Agile or Attached QA to verify the completed stories before it goes to Trunk. The name of the branch will be  Team_A, Team_B etc.

    Team Branch Policy
        1.    Code compiles & builds.
    2.    All unit tests pass.

    The terms Promote and Rebase are tied to the source control tools like Seapine Surround and TFS but where as SVN and Git uses Merge (upward or downward) extensively.

    Rebasing
    This is the process of propagating changes from the Trunk to the team development branches. This has to done often, minimum once a day, preferably when the developer starts his day.

    Rebasing Policy
    1.    Every day when a team gets to work, someone (generally the branch owner) in the team is responsible for merging the latest version from Trunk to the team dev branch.
    2.    If the team discovers a code conflict it has to be resolved it immediately - that's top priority!
    3.    If the team needs help from other teams or whoever wrote the code that conflicts the team has to go fetch them and work together to sort it out.
    4.    The important thing is that team is responsible for getting the problem sorted out, and that we need to sort it out on the team dev branch and not on the Trunk.
    5.    Conflict should be resolved in the branch which is least stable.
    6.    Rebasing can be done as frequently as possible and not necessarily once a day. But the minimum should be once a day.
     
     


     
     
     
     
     
     
     
     
    Promoting
     
    The stories that are completed in the team dev branch and ready for production is merged upwards to the Trunk and is termed as Promoting.
     
    Promoting Policy
     
    1.    When stories are completed and ready to go to production, they will have to be promoted to the Trunk branch from the Team branch.
    2.    Ideally there should be no selective promotion which essentially means that the complete changes in Team Dev branch should be promoted and after the promotion is done the Team Dev branch and the Trunk should be equal.
    3.    "Ready to Promote" is the Team's decision when they feel that the stories are ready.
    4.    The promotion has to be done by the branch owner or under his or her supervision.
    5.    The promotion should be done as and when a story is completed and should not be deferred to end of the sprint.
    6.    Just before the promotion is done a rebase should be done to identify and relsove the conflict, if any.
     

    Release Branch

    Release branch (say Release 1.1.0 in the below image) is created when the product is ready for release.



    After the release, based on the Product Road Map, the Product Owner may choose to release Service Pack Release or work on the bug fixes for critical issues, if any, reported by the customer. In the above image, any issues reported on 1.1.0 will be fixed in that branch and release to customer. After releasing the HotFix 1 for the patch, Release 1.1.1 branch is created. In some cases, if more than 1 HotFix needs to be worked on independently at the sametime, the developer can create HotFix specific branch (similar to Team Dev branch) and merge it to the respective release branch before taking it to production. 
    

    January 28, 2014

    Authentication Token is required to trigger the Jenkins Jobs Remotely

    This article focuses on triggering the Jenkins Job remotely in 1.499 and the issue faced when upgraded to 1.546.

    With Jenkins 1.499, GET method was used to invoke the URL http://JenkinsURL/job/JOBNAME/buildWithParameters?param1=value1&param2=value2

    With the latest version of Jenkins (say 1.546), the trouble started while triggering the Jenkins jobs remotely as Jenkins is looking for POST rather than GET method and giving below error message,


    Further research fetched some light through the below  URL that an authentication token that needs to be passed to the Jenkins job as shown in the below screen shot and it has helped to resolve the issue.


     
    So the updated URL with Authentication Token for POST method is  http://JenkinsURL/job/JOBNAME/buildWithParameters?param1=value1&param2=value2&token=build

    January 15, 2014

    Multijob Plugin throws NoClassDefFoundError without Parameter Plugin

    If you install a multi-job plugin 1.7 on Jenkins 1.499 without Parameter plugin, you will get NoClassDefFoundError (as mentioned below), while creating a multi-job and saving it.

    So while installing any plugin, make sure to install all the required dependant plugins.

    Status Code: 500

    Exception: java.lang.NoClassDefFoundError: hudson/plugins/parameterizedtrigger/AbstractBuildParameters$DontTriggerException
    Stacktrace:

    javax.servlet.ServletException: java.lang.NoClassDefFoundError: hudson/plugins/parameterizedtrigger/AbstractBuildParameters$DontTriggerException

            at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:615)
            at org.kohsuke.stapler.Stapler.invoke(Stapler.java:658)
            at org.kohsuke.stapler.MetaClass$6.doDispatch(MetaClass.java:241)
            at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:53)
            at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:573)
            at org.kohsuke.stapler.Stapler.invoke(Stapler.java:658)
            at org.kohsuke.stapler.Stapler.invoke(Stapler.java:487)
            at org.kohsuke.stapler.Stapler.service(Stapler.java:164)
            at javax.servlet.http.HttpServlet.service(HttpServlet.java:45)
            at winstone.ServletConfiguration.execute(ServletConfiguration.java:248)
            at winstone.RequestDispatcher.forward(RequestDispatcher.java:333)
            at winstone.RequestDispatcher.doFilter(RequestDispatcher.java:376)
            at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:95)
            at hudson.plugins.greenballs.GreenBallFilter.doFilter(GreenBallFilter.java:58)
            at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:98)
            at hudson.util.PluginServletFilter.doFilter(PluginServletFilter.java:87)
            at winstone.FilterConfiguration.execute(FilterConfiguration.java:194)
            at winstone.RequestDispatcher.doFilter(RequestDispatcher.java:366)
            at hudson.security.csrf.CrumbFilter.doFilter(CrumbFilter.java:47)
            at winstone.FilterConfiguration.execute(FilterConfiguration.java:194)
            at winstone.RequestDispatcher.doFilter(RequestDispatcher.java:366)
            at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:84)
            at hudson.security.ChainedServletFilter.doFilter(ChainedServletFilter.java:76)
            at hudson.security.HudsonFilter.doFilter(HudsonFilter.java:164)
            at winstone.FilterConfiguration.execute(FilterConfiguration.java:194)
            at winstone.RequestDispatcher.doFilter(RequestDispatcher.java:366)
            at org.kohsuke.stapler.compression.CompressionFilter.doFilter(CompressionFilter.java:50)
            at winstone.FilterConfiguration.execute(FilterConfiguration.java:194)
            at winstone.RequestDispatcher.doFilter(RequestDispatcher.java:366)
            at hudson.util.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:81)
            at winstone.FilterConfiguration.execute(FilterConfiguration.java:194)
            at winstone.RequestDispatcher.doFilter(RequestDispatcher.java:366)
            at winstone.RequestDispatcher.forward(RequestDispatcher.java:331)
            at winstone.RequestHandlerThread.processRequest(RequestHandlerThread.java:215)
            at winstone.RequestHandlerThread.run(RequestHandlerThread.java:138)
            at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
            at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
            at java.util.concurrent.FutureTask.run(Unknown Source)
            at winstone.BoundedExecutorService$1.run(BoundedExecutorService.java:77)
            at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
            at java.lang.Thread.run(Unknown Source)
    Caused by: java.lang.NoClassDefFoundError: hudson/plugins/parameterizedtrigger/AbstractBuildParameters$DontTriggerException
            at java.lang.Class.getDeclaredFields0(Native Method)
            at java.lang.Class.privateGetDeclaredFields(Unknown Source)
            at java.lang.Class.privateGetPublicFields(Unknown Source)
            at java.lang.Class.getFields(Unknown Source)
            at org.kohsuke.stapler.ClassDescriptor.<init>(ClassDescriptor.java:71)
            at org.kohsuke.stapler.RequestImpl$TypePair.convertJSON(RequestImpl.java:561)
            at org.kohsuke.stapler.RequestImpl$TypePair.convertJSON(RequestImpl.java:618)
            at org.kohsuke.stapler.RequestImpl.bindJSON(RequestImpl.java:377)
            at org.kohsuke.stapler.RequestImpl$TypePair.convertJSON(RequestImpl.java:574)
            at org.kohsuke.stapler.RequestImpl.bindJSON(RequestImpl.java:377)
            at org.kohsuke.stapler.RequestImpl.bindJSON(RequestImpl.java:373)
            at com.tikal.jenkins.plugins.multijob.MultiJobBuilder$DescriptorImpl.newInstance(MultiJobBuilder.java:231)
            at com.tikal.jenkins.plugins.multijob.MultiJobBuilder$DescriptorImpl.newInstance(MultiJobBuilder.java:214)
            at hudson.model.Descriptor.newInstancesFromHeteroList(Descriptor.java:939)
            at hudson.model.Descriptor.newInstancesFromHeteroList(Descriptor.java:926)
            at hudson.util.DescribableList.rebuildHetero(DescribableList.java:203)
            at hudson.model.Project.submit(Project.java:200)
            at hudson.model.Job.doConfigSubmit(Job.java:1046)
            at hudson.model.AbstractProject.doConfigSubmit(AbstractProject.java:723)
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
            at java.lang.reflect.Method.invoke(Unknown Source)
            at org.kohsuke.stapler.Function$InstanceFunction.invoke(Function.java:288)
            at org.kohsuke.stapler.Function.bindAndInvoke(Function.java:151)
            at org.kohsuke.stapler.Function.bindAndInvokeAndServeResponse(Function.java:90)
            at org.kohsuke.stapler.MetaClass$1.doDispatch(MetaClass.java:111)
            at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:53)
            at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:573)
            ... 41 more

    Caused by: java.lang.ClassNotFoundException: hudson.plugins.parameterizedtrigger.AbstractBuildParameters$DontTriggerException
            at java.net.URLClassLoader$1.run(Unknown Source)
            at java.security.AccessController.doPrivileged(Native Method)
            at java.net.URLClassLoader.findClass(Unknown Source)
            at java.lang.ClassLoader.loadClass(Unknown Source)
            at java.lang.ClassLoader.loadClass(Unknown Source)
            ... 70 more

    Related Article: Multijob Plugin Null Pointer Exception.