Difference between revisions of "Using Git"

From Dogtag
Jump to: navigation, search
m (Developing on a Local Branch)
m (Rewinding Commits)
(18 intermediate revisions by the same user not shown)
Line 13: Line 13:
 
  $ git clone https://github.com/dogtagpki/pki.git
 
  $ git clone https://github.com/dogtagpki/pki.git
  
If the repository is to be used for write access (e.g. pushing commits directly, creating tags),
+
If the repository is to be used for write access (e.g. pushing commits directly, creating upstream branches/tags),
 
it should be cloned with authentication using the '''SSH URL''', for example;
 
it should be cloned with authentication using the '''SSH URL''', for example;
  
Line 27: Line 27:
  
 
For development it's recommended to [https://help.github.com/en/articles/fork-a-repo create a fork] of the upstream repository
 
For development it's recommended to [https://help.github.com/en/articles/fork-a-repo create a fork] of the upstream repository
for submitting a [[GitHub Pull Request]].
+
for submitting a [[GitHub Pull Request]] and/or to run [[Travis CI]].
  
 
Once the fork has been created, add it into the local repository,
 
Once the fork has been created, add it into the local repository,
Line 47: Line 47:
 
The preferred way of doing development is to do your work on a local branch.  This makes it easy to isolate fixes you are working on from each other.  It also helps to prevent merge issues when you are ready to push your changes up to the remote repository.  The following example shows the commands a developer would use to fix a bug on a local branch.
 
The preferred way of doing development is to do your work on a local branch.  This makes it easy to isolate fixes you are working on from each other.  It also helps to prevent merge issues when you are ready to push your changes up to the remote repository.  The following example shows the commands a developer would use to fix a bug on a local branch.
  
The first step is to create a local branch.  You should name your branch something descriptive, such as the bug number you are working on, or the name of the feature you are developing.  Here is an example of creating a new local branch:
+
The first step is to create a local branch.  You should name your branch something descriptive, such as the bug number you are working on, or the name of the feature you are developing.  Here is an example of creating a new local branch from master:
  
  $ git checkout -b my_branch
+
$ git checkout master
Switched to a new branch 'my_branch'
+
  $ git checkout -b local_branch
 
 
This command creates a local branch named '''my_branch''' and switches to it.  If you ever want to check and see what branch you are on, you can do that with the following command:
 
  
$ git branch
+
Now that we are in a local branch, make the necessary changes, then make sure the changes are staged for commit.
  master
 
* my_branch
 
 
 
This shows that we have two local branches.  The '''master''' branch is the branch created when we initially cloned the remote repository.  This branch is set to track the development tip.  The '''*''' next to '''my_branch''' means that we are currently on '''my_branch'''.  If you ever want to switch the branch that you are on, that is done with the checkout command. Here is an example that shows switching to the ''master'' branch, then back to '''my_branch''':
 
 
 
$ git checkout master
 
Switched to branch 'master'
 
$ git branch
 
* master
 
  my_branch
 
$ git checkout my_branch
 
Switched to branch 'my_branch'
 
  
Now that we are on our branch, we would change the source code to fix our bug.  This example just makes a simple change to the copyright block in '''pki/README'''.  After updating the source, we can see the changes with the diff command:
+
To stage a new file or the changes in an existing file:
  
  $ git diff
+
  $ git add <file>
diff --git a/pki/README b/pki/README
 
index 2c2c36b..f6b2e83 100644
 
--- a/pki/README
 
+++ b/pki/README
 
@@ -1,5 +1,5 @@
 
  # BEGIN COPYRIGHT BLOCK
 
-# (C) 2008 Red Hat, Inc.
 
+# (C) 2011 Red Hat, Inc.
 
  # All rights reserved.
 
  # END COPYRIGHT BLOCK
 
  
We can see the status of the files in the source tree according to Git with the status command:
+
To check the status of the changes:
  
 
  $ git status
 
  $ git status
# On branch my_branch
 
# Changes not staged for commit:
 
#  (use "git add <file>..." to update what will be committed)
 
#  (use "git checkout -- <file>..." to discard changes in working directory)
 
#
 
# modified:  pki/README
 
#
 
no changes added to commit (use "git add" and/or "git commit -a")
 
  
This shows us that the only modified file in the source tree is '''pki/README'''.  Note also that is says that the change to this file is not staged for commit.  If you want to stage a file for commit, you can use the add command.  Here is an example of staging the '''pki/README''' file for commit and then showing the status of it:
+
To commit the changes:
  
  $ git add pki/README
+
  $ git commit
[nkinder@localhost pki]$ git status
 
# On branch my_branch
 
# Changes to be committed:
 
#  (use "git reset HEAD <file>..." to unstage)
 
#
 
# modified:  pki/README
 
#
 
  
Now we can see that our modifications to '''pki/README''' are staged for commit.  We will use the commit command at this point to check our changes in on our local branch.
+
If you want to revise the commit, make the necessary changes, stage the changes again as above, then amend the commit:
  
  $ git commit
+
  $ git commit --amend
[my_branch 535cf2d] Updated copyright in README file
 
  1 files changed, 1 insertions(+), 1 deletions(-)
 
  
 
When you run the commit command, you will have to fill in the commit message for your commit.  The format should be a one-line summary of the fix (including the applicable bug or ticket number if appropriate), followed by a blank line and a more complete description of the change.  Now that our change is commited to our local branch, we can look at the commit history to confirm that our commit is there.  We'll also check the status of the tree to show that git considers the tree to be up to date.
 
When you run the commit command, you will have to fill in the commit message for your commit.  The format should be a one-line summary of the fix (including the applicable bug or ticket number if appropriate), followed by a blank line and a more complete description of the change.  Now that our change is commited to our local branch, we can look at the commit history to confirm that our commit is there.  We'll also check the status of the tree to show that git considers the tree to be up to date.
  
  $ git log -1
+
  $ git log
 
  commit 535cf2d38b876ac784bd3449dea885b9da4b1c3c
 
  commit 535cf2d38b876ac784bd3449dea885b9da4b1c3c
 
  Author: Nathan Kinder <nkinder@redhat.com>
 
  Author: Nathan Kinder <nkinder@redhat.com>
Line 121: Line 80:
 
      
 
      
 
     The date in the copyright of README needed to be updated.
 
     The date in the copyright of README needed to be updated.
$ git status
 
# On branch my_branch
 
nothing to commit (working directory clean)
 
  
The log command used above shows the last commit.  If you want to see more history, you can simply change the '''-1''' argument to the last number of commits that you want to see.
+
= Rebasing the Local Branch =
  
= Pushing a Patch to the Remote Repository =
+
Sometimes the upstream master branch may have newer changes so your local branch may need to be rebased.
Following on our previous example of developing on a branch, we're going to go through how you would push the change up to the remote '''master''' branch.  Assuming that your review is complete, the first step is to see if anything has changed in the remote repository since you created your branch.  If there have been any remote changes, we will need to rebase our changes on top of them.
 
  
Here we will switch to our '''master''' branch and pull any changes that may have happened:
+
To rebase the local branch, pull the latest from master with the following commands:
  
 
  $ git checkout master
 
  $ git checkout master
  Switched to branch 'master'
+
  $ git pull
Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded.
+
 
  [nkinder@localhost pki]$ git pull
+
Then go back to the local branch and rebase it against master:
  Updating 0491736..8ff3cae
+
 
Fast-forward
+
  $ git checkout local_branch
  .../com/netscape/cms/servlet/base/model/Link.java  |  88 +++++++++++++++
+
  $ git rebase master
  .../com/netscape/cms/servlet/key/KeysResource.java |  55 ++++++++--
+
 
  .../com/netscape/cms/servlet/key/model/KeyDAO.java |  32 ++++--
+
If there's no conflict, the commands should complete immediately.
  .../cms/servlet/key/model/KeyDataInfos.java        |  87 ++++++++++++++
+
If there are conflicts, you will need to fix the conflicts first.
  .../cms/servlet/request/KeyRequestsResource.java  |  84 ++++++++++++---
+
 
  .../cms/servlet/request/model/KeyRequestDAO.java  | 118 ++++++++++++++++++--
+
= Pushing the Local Branch to Forked Repository =
  .../cms/servlet/request/model/KeyRequestInfos.java |  89 +++++++++++++++
+
 
  7 files changed, 506 insertions(+), 47 deletions(-)
+
To push the local branch to the forked repository, specify the name of the repository and the branch:
  create mode 100644 pki/base/common/src/com/netscape/cms/servlet/base/model/Link.java
+
 
  create mode 100644 pki/base/common/src/com/netscape/cms/servlet/key/model/KeyDataInfos.java
+
  $ git push edewata local_branch
  create mode 100644 pki/base/common/src/com/netscape/cms/servlet/request/model/KeyRequestInfos.java
+
 
 +
If you created additional commits into the local branch, you can simply push again.
 +
However, if you amended any of the commits, you may need to push with force:
  
We can see that git detected that our local master branch was behind the remote master branch.  We use the pull command to actually pull down the changes.  You should always explicitly do a pull just to double check if anything has changed in the remote repository.
+
$ git push edewata local_branch --force
  
The next step is to rebase our changes on top of this change that we pulled down from the remote '''master''' branch.  We do that by switching to our development branch and doing a rebase.  I've added some steps to show the git log in the following example to give an idea of how rebase works.
+
If [[Travis CI]] is configured in the forked repository, the push will trigger the CI automatically.
  
$ git checkout my_branch
+
= Creating a Pull Request =
Switched to branch 'my_branch'
 
$ git log -2
 
commit f6234a5ad913cc98f5bda74b5c84963753352c10
 
Author: Nathan Kinder <nkinder@redhat.com>
 
Date:  Mon Jan 16 11:50:52 2012 -0800
 
 
    Updated copyright in README file
 
   
 
    The date in the copyright of README needed to be updated.
 
 
commit 0491736b2570447391835bc2e5282d809f0de4f1
 
Author: Jack Magne <jmagne@redhat.com>
 
Date:  Fri Jan 13 16:57:06 2012 -0800
 
 
    Big numbers fix for CA and DRM.
 
   
 
    This patch resolves multiple issues related to use of big numbers on CA and DRM
 
    It also provides a fix for incomplete recovery requests causing null pointer exception.
 
   
 
    Bugs: 756133, 758505.
 
   
 
    Complete formatting changes for QueryRec.java.
 
$ git rebase master
 
First, rewinding head to replay your work on top of it...
 
Applying: Updated copyright in README file
 
$ git log -3
 
commit 5516ece394889facb511265e43a70340b19cea35
 
Author: Nathan Kinder <nkinder@redhat.com>
 
Date:  Mon Jan 16 11:50:52 2012 -0800
 
 
    Updated copyright in README file
 
   
 
    The date in the copyright of README needed to be updated.
 
 
commit 8ff3cae8509bf5527d49166f818776cfc618555c
 
Author: Ade Lee <alee@redhat.com>
 
Date:  Thu Jan 12 12:24:24 2012 -0500
 
 
    Enhanced new REST search interface for keys and key requests
 
   
 
    Defined parameters that can be searched for in key and keyrequest searches.
 
   
 
    Searches for KeyRequests and Keys will perform VLV searches if those searches are defined.
 
    The results will include links to next and previous pages in the results.
 
   
 
    Also added maxTime and maxResults parameters for regular searches.  These will be operational
 
    unless they exceed server defined limits - which are enforced at the repo level.
 
   
 
    Modified link URL from "link" to "Link"
 
 
commit 0491736b2570447391835bc2e5282d809f0de4f1
 
Author: Jack Magne <jmagne@redhat.com>
 
Date:  Fri Jan 13 16:57:06 2012 -0800
 
 
    Big numbers fix for CA and DRM.
 
   
 
    This patch resolves multiple issues related to use of big numbers on CA and DRM
 
    It also provides a fix for incomplete recovery requests causing null pointer exception.
 
   
 
    Bugs: 756133, 758505.
 
   
 
    Complete formatting changes for QueryRec.java.
 
  
The commit history shown in the logs shows how the rebase rewinds our local commit, applies any changes from the branch we are rebasing from ('''master''' in this case), then re-applies our local commit.
+
Once the changes are pushed from the local branch to the forked repository, you can submit a [[GitHub Pull Request]].
  
Now we have our patch all rebased on top of the remote '''master''' branch, so we can go ahead and push it up to the remote repository.  We want to push this up to the remote '''master''' branch.  Our local '''master''' branch is set-up to track the remote '''master''', so the first thing we need to do is to bring our change over to our local '''master''' branch.  At that point, we can push it up to the remote '''master''' branch.  Here is how we do this:
+
After the pull request is merged, refresh the master branch with the following command:
  
 
  $ git checkout master
 
  $ git checkout master
Switched to branch 'master'
 
 
  $ git pull
 
  $ git pull
Already up-to-date.
 
$ git merge my_branch
 
Updating 8ff3cae..5516ece
 
Fast-forward
 
  pki/README |    2 +-
 
  1 files changed, 1 insertions(+), 1 deletions(-)
 
$ git log -2
 
commit 5516ece394889facb511265e43a70340b19cea35
 
Author: Nathan Kinder <nkinder@redhat.com>
 
Date:  Mon Jan 16 11:50:52 2012 -0800
 
 
    Updated copyright in README file
 
   
 
    The date in the copyright of README needed to be updated.
 
 
commit 8ff3cae8509bf5527d49166f818776cfc618555c
 
Author: Ade Lee <alee@redhat.com>
 
Date:  Thu Jan 12 12:24:24 2012 -0500
 
 
    Enhanced new REST search interface for keys and key requests
 
   
 
    Defined parameters that can be searched for in key and keyrequest searches.
 
   
 
    Searches for KeyRequests and Keys will perform VLV searches if those searches are defined.
 
    The results will include links to next and previous pages in the results.
 
   
 
    Also added maxTime and maxResults parameters for regular searches.  These will be operational
 
    unless they exceed server defined limits - which are enforced at the repo level.
 
   
 
    Modified link URL from "link" to "Link"
 
$ git push
 
  
It is a good idea to do a quick pull to check if anything has changed one last time before pushing. It is also a good idea to check the commit hsitory right before pushing to see if there is a git merge commit. A merge commit is a commit that git automatically makes if you didn't rebase your fix ahead of time.  In general, we want to avoid merge commits. If you see a merge commit, you will need to rewind your tree, rebase your fix, and then go through the push procedure again.
+
The changes should appear in the master branch.
 +
 
 +
= Pushing Directly to Upstream Repository =
 +
 
 +
'''Note:''' This should only be done for patches that do not need a review. It's always recommended to push the patches to the forked repository first to make sure it passes the CI.
 +
 
 +
There are several ways to merge the changes from the local branch into master.
 +
 
 +
If the local branch has been rebased against master, fast-forward the master branch to match the local branch:
 +
 
 +
$ git checkout master
 +
$ git rebase local_branch
 +
 
 +
If the local branch has not been rebased againt master, cherry-pick each change into master:
 +
 
 +
$ git checkout master
 +
$ git cherry-pick <commit ID>
  
I did not acutally perform the push here in my example, as I didn't want to commit this example change.  When a change is actually pushed, git will output some information about the result of the push.
+
Once the changes are in master, push the changes to upstream with the following command:
  
= Rewinding Commits =
+
  $ git push origin master
You will have times where you want to rewind your source tree, or maybe just your commit history. This can be easily done with the reset command.  The first thing to understand is that there are two types of resets, soft and hard.
 
  
A soft reset is what you would use when you want to leave the source files on disk alone, but you want to back out the commit history.  A common case where this is needed is when a patch needs to be changed due to review feedback.  Instead of making a second patch to address the review feedback, you should rewind the commit history, fix the source files, then recommit everything in a single patch.  Here is an example that backs out my example change (which was never pushed):
+
= Squashing a Commit =
  
$ git log -2
+
To squash a commit into the previous commit (i.e. merging into a single commit) in the local branch:
commit 5516ece394889facb511265e43a70340b19cea35
 
Author: Nathan Kinder <nkinder@redhat.com>
 
Date:  Mon Jan 16 11:50:52 2012 -0800
 
 
    Updated copyright in README file
 
   
 
    The date in the copyright of README needed to be updated.
 
 
commit 8ff3cae8509bf5527d49166f818776cfc618555c
 
Author: Ade Lee <alee@redhat.com>
 
Date:  Thu Jan 12 12:24:24 2012 -0500
 
 
    Enhanced new REST search interface for keys and key requests
 
   
 
    Defined parameters that can be searched for in key and keyrequest searches.
 
   
 
    Searches for KeyRequests and Keys will perform VLV searches if those searches are defined.
 
    The results will include links to next and previous pages in the results.
 
   
 
    Also added maxTime and maxResults parameters for regular searches.  These will be operational
 
    unless they exceed server defined limits - which are enforced at the repo level.
 
   
 
    Modified link URL from "link" to "Link"
 
$ git reset --soft 8ff3cae8509bf5527d49166f818776cfc618555c
 
$ git status
 
# On branch my_branch
 
# Changes to be committed:
 
#  (use "git reset HEAD <file>..." to unstage)
 
#
 
# modified:  pki/README
 
#
 
$ git log -1
 
commit 8ff3cae8509bf5527d49166f818776cfc618555c
 
Author: Ade Lee <alee@redhat.com>
 
Date:  Thu Jan 12 12:24:24 2012 -0500
 
 
    Enhanced new REST search interface for keys and key requests
 
   
 
    Defined parameters that can be searched for in key and keyrequest searches.
 
   
 
    Searches for KeyRequests and Keys will perform VLV searches if those searches are defined.
 
    The results will include links to next and previous pages in the results.
 
   
 
    Also added maxTime and maxResults parameters for regular searches.  These will be operational
 
    unless they exceed server defined limits - which are enforced at the repo level.
 
   
 
    Modified link URL from "link" to "Link"
 
  
You can see that we need to supply the commit hash for the last commit that we want to keep. You can get this hash from the commit log message.  After doing the soft reset, we can see that the status command shows that we still have our local modifications, but it's as if they were never committed to the local tree.
+
  $ git reset --soft HEAD^
 +
$ git commit --amend
  
A hard reset is what you would use to completely back out a commit, or even local uncommited changes.  This will wipe out the changes to the source tree associated with the commit as well as the commit history.  You should be careful when doing a hard reset to make sure it's what you want to do, as you can lose local changes.  Remote changes are not a concern, as you can simply re-pull them from the remote repository.  Here is an example of a hard commit that continues from our soft commit example above:
+
= Removing a Commit =
  
$ git reset --hard 8ff3cae8509bf5527d49166f818776cfc618555c
+
To completely remove a commit from the local branch:
HEAD is now at 8ff3cae Enhanced new REST search interface for keys and key requests
 
$ git status
 
# On branch my_branch
 
nothing to commit (working directory clean)
 
  
We can see that our local change is completely gone now.
+
$ git reset --hard HEAD^
  
 
= Working with Remote Branches =
 
= Working with Remote Branches =
Line 333: Line 161:
  
 
  $ git branch -r
 
  $ git branch -r
   origin/DOGTAG_9_BRANCH
+
   origin/DOGTAG_10_5_BRANCH
   origin/HEAD -> origin/master
+
   origin/DOGTAG_10_6_BRANCH
  origin/IPA_v2_RHEL_6_ERRATA_BRANCH
 
  origin/PKI_8_0_ERRATA_BRANCH
 
  origin/PKI_8_1_ERRATA_BRANCH
 
  origin/PKI_8_BRANCH
 
  origin/autoformat
 
  origin/autoformat2
 
 
   origin/master
 
   origin/master
  
In this case, we are going to assume that we want to port a change that we have on our local '''master''' branch over to the remote '''DOGTAG_9_BRANCH''' branch.  To create our local branch, we simply checkout using the remote branch name:
+
In this case, we are going to assume that we want to port a change that we have on our local '''master''' branch over to the remote '''DOGTAG_10_5_BRANCH''' branch.  To create our local branch, we simply checkout using the remote branch name:
  
  $ git checkout DOGTAG_9_BRANCH
+
  $ git checkout DOGTAG_10_5_BRANCH
  Branch DOGTAG_9_BRANCH set up to track remote branch DOGTAG_9_BRANCH from origin.
+
  Branch DOGTAG_10_5_BRANCH set up to track remote branch DOGTAG_10_5_BRANCH from origin.
  Switched to a new branch 'DOGTAG_9_BRANCH'
+
  Switched to a new branch 'DOGTAG_10_5_BRANCH'
  
 
If you were simply doing new development on this branch, you could just do your development work here (or create a local branch from this point to avoid merge issues).  For our example here, we're going to be porting a change from the '''master''' branch.  This is done with the cherry-pick command.  Here is an example of how we would do this (along with some commit log output to help show how it works):
 
If you were simply doing new development on this branch, you could just do your development work here (or create a local branch from this point to avoid merge issues).  For our example here, we're going to be porting a change from the '''master''' branch.  This is done with the cherry-pick command.  Here is an example of how we would do this (along with some commit log output to help show how it works):
  
 
  $ git branch
 
  $ git branch
  * DOGTAG_9_BRANCH
+
  * DOGTAG_10_5_BRANCH
 
   master
 
   master
   my_branch
+
   local_branch
  [nkinder@localhost pki]$ git log -1
+
 +
  $ git log -1
 
  commit 8ebf890b913ffbf4cb40c09ebc9e229989303095
 
  commit 8ebf890b913ffbf4cb40c09ebc9e229989303095
 
  Author: Ade Lee <alee@redhat.com>
 
  Author: Ade Lee <alee@redhat.com>
Line 363: Line 186:
 
      
 
      
 
     Modified sslget doIO() function to be able to handle small reads.
 
     Modified sslget doIO() function to be able to handle small reads.
 +
 
  $ git checkout master
 
  $ git checkout master
 
  Switched to branch 'master'
 
  Switched to branch 'master'
 
  Your branch is ahead of 'origin/master' by 1 commit.
 
  Your branch is ahead of 'origin/master' by 1 commit.
 +
 
  $ git log -1
 
  $ git log -1
 
  commit 5516ece394889facb511265e43a70340b19cea35
 
  commit 5516ece394889facb511265e43a70340b19cea35
Line 374: Line 199:
 
      
 
      
 
     The date in the copyright of README needed to be updated.
 
     The date in the copyright of README needed to be updated.
  $ git checkout DOGTAG_9_BRANCH
+
  Switched to branch 'DOGTAG_9_BRANCH'
+
  $ git checkout DOGTAG_10_5_BRANCH
 +
  Switched to branch 'DOGTAG_10_5_BRANCH'
 
  $ git cherry-pick 5516ece394889facb511265e43a70340b19cea35
 
  $ git cherry-pick 5516ece394889facb511265e43a70340b19cea35
  [DOGTAG_9_BRANCH f4e12fc] Updated copyright in README file
+
  [DOGTAG_10_5_BRANCH f4e12fc] Updated copyright in README file
 
   1 files changed, 1 insertions(+), 1 deletions(-)
 
   1 files changed, 1 insertions(+), 1 deletions(-)
 +
 
  $ git log -2
 
  $ git log -2
 
  commit f4e12fc3ab173dfe43d47248f11b2f39bafd6cab
 
  commit f4e12fc3ab173dfe43d47248f11b2f39bafd6cab
Line 396: Line 223:
 
     Modified sslget doIO() function to be able to handle small reads.
 
     Modified sslget doIO() function to be able to handle small reads.
  
You can see that we only need to provide the hash of the commit that we want to port to our branch.  The end result is a committed fix on our branch.  At this point, you could do a push which would push the commit to the remote '''DOGTAG_9_BRANCH'''.
+
You can see that we only need to provide the hash of the commit that we want to port to our branch.  The end result is a committed fix on our branch.  At this point, you could do a push which would push the commit to the remote '''DOGTAG_10_5_BRANCH'''.
  
 
= References =
 
= References =
  
 
* [[Git]]
 
* [[Git]]

Revision as of 20:41, 12 June 2019

Overview

This page shows how to accomplish some common development procedures using Git. There are usually multiple ways to accomplish the same thing in Git, so keep in mind that the steps below are only one way of doing things. There may be other shortcuts or different ways of doing things that you prefer.

Creating a Local Repository

First, create a clone of the upstream repository on the local machine. There are two ways to do this depending on the purpose of the local repository.

If the repository is to be used for read-only access (e.g. for builds, for pull requests), it can be cloned anonymously using the HTTPS URL, for example:

$ git clone https://github.com/dogtagpki/pki.git

If the repository is to be used for write access (e.g. pushing commits directly, creating upstream branches/tags), it should be cloned with authentication using the SSH URL, for example;

$ git clone git@github.com:dogtagpki/pki.git

Verify with the following commnad:

$ git remote -v
origin	git@github.com:dogtagpki/pki.git (fetch)
origin	git@github.com:dogtagpki/pki.git (push)

Forking Upstream Repository

For development it's recommended to create a fork of the upstream repository for submitting a GitHub Pull Request and/or to run Travis CI.

Once the fork has been created, add it into the local repository, for example:

$ cd pki
$ git remote add edewata git@github.com:edewata/pki.git
$ git fetch

Verify with the following command:

$ git remote -v
origin	git@github.com:dogtagpki/pki.git (fetch)
origin	git@github.com:dogtagpki/pki.git (push)
edewata	git@github.com:edewata/pki.git (fetch)
edewata	git@github.com:edewata/pki.git (push)

Developing on a Local Branch

The preferred way of doing development is to do your work on a local branch. This makes it easy to isolate fixes you are working on from each other. It also helps to prevent merge issues when you are ready to push your changes up to the remote repository. The following example shows the commands a developer would use to fix a bug on a local branch.

The first step is to create a local branch. You should name your branch something descriptive, such as the bug number you are working on, or the name of the feature you are developing. Here is an example of creating a new local branch from master:

$ git checkout master
$ git checkout -b local_branch

Now that we are in a local branch, make the necessary changes, then make sure the changes are staged for commit.

To stage a new file or the changes in an existing file:

$ git add <file>

To check the status of the changes:

$ git status

To commit the changes:

$ git commit

If you want to revise the commit, make the necessary changes, stage the changes again as above, then amend the commit:

$ git commit --amend

When you run the commit command, you will have to fill in the commit message for your commit. The format should be a one-line summary of the fix (including the applicable bug or ticket number if appropriate), followed by a blank line and a more complete description of the change. Now that our change is commited to our local branch, we can look at the commit history to confirm that our commit is there. We'll also check the status of the tree to show that git considers the tree to be up to date.

$ git log
commit 535cf2d38b876ac784bd3449dea885b9da4b1c3c
Author: Nathan Kinder <nkinder@redhat.com>
Date:   Mon Jan 16 11:50:52 2012 -0800 

    Updated copyright in README file
   
    The date in the copyright of README needed to be updated.

Rebasing the Local Branch

Sometimes the upstream master branch may have newer changes so your local branch may need to be rebased.

To rebase the local branch, pull the latest from master with the following commands:

$ git checkout master
$ git pull

Then go back to the local branch and rebase it against master:

$ git checkout local_branch
$ git rebase master

If there's no conflict, the commands should complete immediately. If there are conflicts, you will need to fix the conflicts first.

Pushing the Local Branch to Forked Repository

To push the local branch to the forked repository, specify the name of the repository and the branch:

$ git push edewata local_branch

If you created additional commits into the local branch, you can simply push again. However, if you amended any of the commits, you may need to push with force:

$ git push edewata local_branch --force

If Travis CI is configured in the forked repository, the push will trigger the CI automatically.

Creating a Pull Request

Once the changes are pushed from the local branch to the forked repository, you can submit a GitHub Pull Request.

After the pull request is merged, refresh the master branch with the following command:

$ git checkout master
$ git pull

The changes should appear in the master branch.

Pushing Directly to Upstream Repository

Note: This should only be done for patches that do not need a review. It's always recommended to push the patches to the forked repository first to make sure it passes the CI.

There are several ways to merge the changes from the local branch into master.

If the local branch has been rebased against master, fast-forward the master branch to match the local branch:

$ git checkout master
$ git rebase local_branch

If the local branch has not been rebased againt master, cherry-pick each change into master:

$ git checkout master
$ git cherry-pick <commit ID>

Once the changes are in master, push the changes to upstream with the following command:

$ git push origin master

Squashing a Commit

To squash a commit into the previous commit (i.e. merging into a single commit) in the local branch:

$ git reset --soft HEAD^
$ git commit --amend

Removing a Commit

To completely remove a commit from the local branch:

$ git reset --hard HEAD^

Working with Remote Branches

When you want to make changes on a remote branch, the first thing that you need to do is to create a local branch to track the remote branch. This will work the same way that our local master branch tracks the remote master branch.

The first step is to list the remote branches. This is done the same way as listing local branches, except we add the -r option:

$ git branch -r
 origin/DOGTAG_10_5_BRANCH
 origin/DOGTAG_10_6_BRANCH
 origin/master

In this case, we are going to assume that we want to port a change that we have on our local master branch over to the remote DOGTAG_10_5_BRANCH branch. To create our local branch, we simply checkout using the remote branch name:

$ git checkout DOGTAG_10_5_BRANCH
Branch DOGTAG_10_5_BRANCH set up to track remote branch DOGTAG_10_5_BRANCH from origin.
Switched to a new branch 'DOGTAG_10_5_BRANCH'

If you were simply doing new development on this branch, you could just do your development work here (or create a local branch from this point to avoid merge issues). For our example here, we're going to be porting a change from the master branch. This is done with the cherry-pick command. Here is an example of how we would do this (along with some commit log output to help show how it works):

$ git branch
* DOGTAG_10_5_BRANCH
  master
  local_branch

$ git log -1
commit 8ebf890b913ffbf4cb40c09ebc9e229989303095
Author: Ade Lee <alee@redhat.com>
Date:   Wed Jan 4 00:08:03 2012 -0500

    BZ 771357 - sslget does not work after FEDORA-2011-17400 update, breaking FreeIPA install
    
    Modified sslget doIO() function to be able to handle small reads.

$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.

$ git log -1
commit 5516ece394889facb511265e43a70340b19cea35
Author: Nathan Kinder <nkinder@redhat.com>
Date:   Mon Jan 16 11:50:52 2012 -0800

    Updated copyright in README file
    
    The date in the copyright of README needed to be updated.

$ git checkout DOGTAG_10_5_BRANCH
Switched to branch 'DOGTAG_10_5_BRANCH'
$ git cherry-pick 5516ece394889facb511265e43a70340b19cea35
[DOGTAG_10_5_BRANCH f4e12fc] Updated copyright in README file
 1 files changed, 1 insertions(+), 1 deletions(-)

$ git log -2
commit f4e12fc3ab173dfe43d47248f11b2f39bafd6cab
Author: Nathan Kinder <nkinder@redhat.com>
Date:   Mon Jan 16 11:50:52 2012 -0800

    Updated copyright in README file
    
    The date in the copyright of README needed to be updated.

commit 8ebf890b913ffbf4cb40c09ebc9e229989303095
Author: Ade Lee <alee@redhat.com>
Date:   Wed Jan 4 00:08:03 2012 -0500

    BZ 771357 - sslget does not work after FEDORA-2011-17400 update, breaking FreeIPA install
    
    Modified sslget doIO() function to be able to handle small reads.

You can see that we only need to provide the hash of the commit that we want to port to our branch. The end result is a committed fix on our branch. At this point, you could do a push which would push the commit to the remote DOGTAG_10_5_BRANCH.

References