Grab the repository

First thing to know, we have a mirror on github, which makes things quite easy. They have a great UI and some interesting features that I'm sure you don't want to miss. But you should know that it's not required and you can clone the repository directly from git.postgresql.org. This post will only show the github way, but I think you can figure your way from this post anyway.

You need to create an account on github. You can have one for free if you want to work on open source projects. Here is the link: https://github.com/signup/free. You simply need to enter a username, a password, and a valid email address. I don't think there is anything else to do. You should be able to connect right after that. Next step involves that you enter your SSH public key in your GitHub profile, so that you can push commits into your git repositories over there.

Once this is done, you have to fork the pgAdmin Git repository on github. Yeah, right, fork. Not the project, but the repository :) Follow this URL: http://github.com/postgres/pgadmin3. You'll be at the pgAdmin mirror. Then, click on the "Fork" button (if it's disabled, then you're not logged in – so, first log in, and get back here). It'll take a few minutes before you actually have your pgAdmin Git repository on GitHub.

Once this is done, you don't really need your browser. Get back to your terminal session.

You'll need the Git command-line tool. So, install the right package for your distro, or grab the Git Windows installer and execute it.

Once the git command is installed, you can clone your GitHub repository:

 guillaume@laptop:~$ git clone git@github.com:gleu/pgadmin3.git 
 Initialized empty Git repository in /home/guillaume/pgadmin3/.git/
 remote: Counting objects: 113391, done. 
 remote: Compressing objects: 100% (13235/13235), done. 
 remote: Total 113391 (delta 99957), reused 113112 (delta 99725) 
 Receiving objects: 100% (113391/113391), 94.18 MiB | 789 KiB/s, done. 
 Resolving deltas: 100% (99957/99957), done. 
 Checking out files: 100% (1780/1780), done.

(of course, you should replace "gleu" with your username on GitHub... this is also true for the other commands we'll see in this blog post)

On my laptop, it takes 3 minutes to clone the whole repository. When I say "whole repository", I really mean it. You've got all the repository history in your local drive. Right now, it gives me a 181MB directory.

First patch with Git

Now that you have cloned your GitHub repository, what can you do? work on a patch for the 1.12 branch? OK, let's do that. First, we need to switch to the 1.12 branch (its real name is REL-1_12_0_PATCHES):

 guillaume@laptop:~$ cd pgadmin3 
 guillaume@laptop:~/pgadmin3$ git checkout REL-1_12_0_PATCHES 
 Branch REL-1_12_0_PATCHES set up to track remote branch REL-1_12_0_PATCHES from origin. 
 Switched to a new branch 'REL-1_12_0_PATCHES'

Now, we can work on the code? not really. You should not change the "official" branches. Well, you can do, but it's not the recommended way of dealing with Git. You need to create your own work branch. So, here it goes:

 guillaume@laptop:~/pgadmin3$ git branch mybugfixwork

This command creates the "mybugfixwork" branch from the "REL-1_12_0_PATCHES" branch at the currently checked out point. Now, we need to get into our new branch:

 guillaume@laptop:~/pgadmin3$ git checkout mybugfixwork 
 Switched to branch 'mybugfixwork'

(lazy people like me would prefer the "git checkout -b mybugfixwork" command because it does the "git branch" and the "git checkout" all in one command)

Now, you can work on the code, modify it, test your changes... well, do the work of a well trained developer.

You can find the differences with the "git diff" command:

 guillaume@laptop:~/pgadmin3$ git diff 
 diff --git a/pgadmin/frm/frmStatus.cpp b/pgadmin/frm/frmStatus.cpp 
 index 7120a83..e5f2bef 100644 
 --- a/pgadmin/frm/frmStatus.cpp 
 +++ b/pgadmin/frm/frmStatus.cpp 
  -453,15 +453,19  void frmStatus::OnExit(wxCommandEvent& event) 
 
 void frmStatus::OnChangeDatabase(wxCommandEvent &ev) 
 { 
 +    // If locks connection is different from the usual one, 
 +    // we first need to close it 
      if (locks_connection != connection) 
      { 
          delete locks_connection; 
      } 
  
 +    // Now open the new connection 
      locks_connection = new pgConn(connection->GetHostName(), cbDatabase->GetValue(), 
        connection->GetUser(), connection->GetPassword(), connection->GetPort(), connection->GetSslMod 
        0, connection->GetApplicationName()); 

 +    // And send the "be quiet on the logs" query 
      locks_connection->ExecuteVoid(wxT("SET log_statement='none';SET log_duration='off';SET log_min_d 
  }

The "--color" option displays the diff in a much better way.

When you're happy with your changes, you have to ask git to record them. Before doing any commits, you first need to add every changed and new files to the git index. Let's assume I made some changes to pgadmin/frm/frmStatus.cpp. I'll add this file to the next commit with this command:

 guillaume@laptop:~/pgadmin3$ git add pgadmin/frm/frmStatus.cpp

If you don't remember which files you changed, you can always use "git status":

 guillaume@laptop:~/pgadmin3$ git status | grep modified 
 #	modified:   pgadmin/frm/frmStatus.cpp

Once all new and modified files are added to the git index, you can commit your work:

 guillaume@laptop:~/pgadmin3$ git commit

An editor will open with the list of added and modified files. You can enter your commit message. Once you quit the editor, the commit is done. If you don't want to open an editor, you can still use the "-m" option with your commit message right after this option, just like you did with the cvs and svn commands.

 guillaume@laptop:~/pgadmin3$ git commit 
 [mybugfixwork b4f9cda] Add a stupid comment. 
  1 files changed, 4 insertions(+), 0 deletions(-)

(once again, lazy people like me would prefer the "git commit -a" command because it does the "git add" command on all modified and removed files, and the "git commit" all in one command, but you would still need the "git add" command for new files)

All of this happens in your local repository. Nothing happens on github yet. You can do as many commits as you want. When you want to push your commit(s) to github, you'll have to do a "git push". As we never pushed this new branch, we'll also have to specify:

 guillaume@laptop:~/pgadmin3$ git push origin mybugfixwork
 Counting objects: 9, done. 
 Delta compression using up to 4 threads. 
 Compressing objects: 100% (5/5), done. 
 Writing objects: 100% (5/5), 584 bytes, done. 
 Total 5 (delta 4), reused 0 (delta 0) 
 To git@github.com:gleu/pgadmin3.git 
  * [new branch]      mybugfixwork -> mybugfixwork

(lazy people like me tried once the "git push --all", and felt usually sorry right after... because it pushed all branches, even ones you don't want to push... happened to me when I was writing this :-/ )

The new branch is now on your GitHub pgAdmin repository.

Sending your patch

You want to let the commiters of pgAdmin know about your great patch? No problem. You have usually two ways to do it. The easier one is to send an email to the pgadmin-hackers list to let them know about your repository and in which branch is your patch (here, it is "mybugfixwork"). Otherwise, you can send them a real patch. Git makes that easy for you. When you did the commit, the first output line was this one :

 [mybugfixwork b4f9cda] Add a stupid comment.

The hash in front represents your commit. You need to find the hash of the previous commit :

 guillaume@laptop:~/pgadmin3(mybugfixwork) $ git log --format=oneline
 cd3d7a65628c85f648638489409ebb435b0e8fe4 Add a stupid comment. 
 55e9b5cae1060da39be3a77f181bf413157d6dc3 Fix an issue with tab keypress on frmQuery. 
 bc16a495cdd43e4ac23d35cbce19d6a8522d1000 Cast the transaction ID to text so we can sort on it in the 
 ...

In my example, the interesting hash is the second one, aka 55e9b5cae1060da39be3a77f181bf413157d6dc3. Now, I can ask git to create a patch file:

 guillaume@laptop:~/pgadmin3(mybugfixwork) $ git format-patch 55e9b5cae1060da39be3a77f181bf413157d6dc3 
 0001-Add-a-stupid-comment.patch

Git created a file, named "0001-Add-a-stupid-comment.patch ". You just need to send this patch file.

Commiter's work

What will the commiter do with all this. Let's begin with the patch file. He first need to create a branch on its own local repository (cloned from the official repository) :

 commiter@laptop:~/pgadmin3$ git checkout REL-1_12_0_PATCHES 
 Switched to branch 'REL-1_12_0_PATCHES'
 commiter@laptop:~/pgadmin3$ git checkout -b newpatchtocheck
 Switched to a new branch 'newpatchtocheck'

Then, he will apply the patch:

 commiter@laptop:~/pgadmin3$ git am 0001-Add-a-stupid-comment.patch 
 Applying: Add a stupid comment.

He'll then check the patch. If everything works great, he will switch to the "REL-1_12_0_PATCHES" branch, and merge the contents of the "newpatchtocheck" branch.

 commiter@laptop:~/pgadmin3$ git merge newpatchtocheck 
 Updating 55e9b5c..cd3d7a6 
 Fast-forward 
  pgadmin/frm/frmStatus.cpp |    4  
  1 files changed, 4 insertions(+), 0 deletions(-)

Everything's fine, he can now push it in the official repository.

If you gave him your repo and branch, he has a much better way to handle this. He first has to add a remote repository :

 commiter@laptop:~/pgadmin3$ git remote add gleu_s_github git://github.com/gleu/pgadmin3.git

"gleu_s_github" is a remote repository. Now, he needs to fetch every branches from this repository :

 commiter@laptop:~/pgadmin3$ git fetch  gleu_s_github

Once this is done, he needs to check out the branch he wants to work on :

 commiter@laptop:~/pgadmin3$ git checkout  mybugfixwork

And then, he has to bring all the new stuff in the "REL-1_12_0_PATCHES" official branch into the "mybugfixwork" branch :

 commiter@laptop:~/pgadmin3$ git rebase REL-1_12_0_PATCHES

Then, he'll do the usual step : get back to the REL-1_12_0_PATCHES official branch, merge the changes from mybugfixwork branch, and push the results.

 commiter@laptop:~/pgadmin3$ git checkout master
 commiter@laptop:~/pgadmin3$ git merge  mybugfixwork
 commiter@laptop:~/pgadmin3$ git push

Once its patch has been pushed onto the official repository, the developer can get it in his own local repository with this command :

 commiter@laptop:~/pgadmin3$ git fetch origin

One last note, I really like to know on which branch I'm working on. So I changed my PS1 env variable to use the __git_ps1 command (it displays your current branch if you're in a git directory).

Hope you learned a way to work with pgAdmin source code. Just waiting for your patches to review :)