Zen and the art of...

2009-12-15

Reading The F*ck!ng Manual

While contributing code to ClojureQL, I made a huge mistake. That is, commiting changes to the master branch directly instead of using a development branch. I had made a dozen commits, but in the meantime Lau merged the dev branch on ClojureQL's main repository. The end result was that the pull request I made after was incredibly huge as it included all changes in the merge.

I'll walk you through all steps I've taken to fix this problem. We'll first create a dev branch, it should be a copy of the current master branch, which is the default behavior.

$ git branch dev

This will create a new branch named dev that will be a copy of the current one, master. We'll then search for the first commit we've made using git log.

commit 07a516b03287b606d6a40b2e073cd3e3a1a74244
Author: Nicolas Buduroi 
Date:   Wed Dec 9 18:52:35 2009 -0500

    Removed global connection support for MySql demo as it breaks the build process when MySql is not installed.

commit cc8f234fb61739fca36e982f68eef005b3d4389c
Author: Lau_of_DK 
Date:   Tue Dec 8 23:18:03 2009 +0100

:

We must return the master branch to the state it was before commiting our first change. We can achieve this by using the reset command.

$ git reset --hard cc8f234fb61739fca36e982f68eef005b3d4389c
.gitignore: locally modified
build.xml: locally modified
ivy.xml: locally modified
ivysettings.xml: locally modified
...

Notice that you should use the --hard flag to make sure Git clean up the working repository. We can then update our master branch with the main repository. This assume you've already set up a remote Git repository named main-repo, check this page to see how to make one.

$ git pull main-repo master
From git://gitorious.org/clojureql/clojureql
 * branch            master     -> FETCH_HEAD
Updating cc8f234..b85d55b
Fast forward
 build.gradle                                       |   64 +++++++
 build.xml                                          |  182 --------------------
 ivy.xml                                            |   31 ----
 ivysettings.xml                                    |    9 -
 src/{dk/bestinclass => }/clojureql.clj             |    4 +-
...

Now, we need to switch to our dev branch with git checkout dev, and there, issue the rebase command.

$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: Removed global connection support for MySql demo as it breaks the build process when MySql is not installed.
error: src/dk/bestinclass/clojureql/demos/mysql.clj: does not exist in index
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Renaming src/dk/bestinclass/clojureql/demos/mysql.clj => src/clojureql/demos/mysql.clj
Auto-merging src/clojureql/demos/mysql.clj
Applying: Made demos code formatting more uniform.
error: src/dk/bestinclass/clojureql/demos/derby.clj: does not exist in index
error: src/dk/bestinclass/clojureql/demos/mysql.clj: does not exist in index
error: src/dk/bestinclass/clojureql/demos/postgres.clj: does not exist in index
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Renaming src/dk/bestinclass/clojureql/demos/derby.clj => src/clojureql/demos/derby.clj
Auto-merging src/clojureql/demos/derby.clj
CONFLICT (rename/modify): Merge conflict in src/clojureql/demos/derby.clj
Renaming src/dk/bestinclass/clojureql/demos/mysql.clj => src/clojureql/demos/mysql.clj
Auto-merging src/clojureql/demos/mysql.clj
CONFLICT (rename/modify): Merge conflict in src/clojureql/demos/mysql.clj
Renaming src/dk/bestinclass/clojureql/demos/postgres.clj => src/clojureql/demos/postgres.clj
Auto-merging src/clojureql/demos/postgres.clj
CONFLICT (rename/modify): Merge conflict in src/clojureql/demos/postgres.clj
Failed to merge in the changes.
Patch failed at 0002.

When you have resolved this problem run "git rebase --continue".
If you would prefer to skip this patch, instead run "git rebase --skip".
To restore the original branch and stop rebasing run "git rebase --abort".

OK, that doesn't look good: error, conflict, failed... Not reassuring, but looking more closely, this message concerns only the first patch, which I have to revert anyway. Lets see how to resolve this. You can find the conflicting files with git status. Here's an example of such a file:

<<<<<<< HEAD:src/clojureql/demos/derby.clj
(ns clojureql.demos.derby
=======
;; TEST ====================================================

(ns dk.bestinclass.clojureql.demos.derby
>>>>>>> Made demos code formatting more uniform.:src/dk/bestinclass/clojureql/demos/derby.clj

Fix the conflict by picking one of the offered options. Then, once everything is cleaned up, you can tell the merge process to accept your changes with git add and restart the rebase one.

$ git add .

$ git rebase --continue
Applying: Made demos code formatting more uniform.
Applying: Added build directory to ignored files.
Applying: Changed PostreSQL backend to be more like MySQL one, follow non-nulls new standard.
Applying: Updated create-table docstring to reflect recent changes.
Applying: Added a shortcut in create-table's options to make all columns non null.
Applying: Added support for multiple primary keys to create-table.
Applying: Changed EmbedConnection class to EngineConnection interface for added flexibility in Derby backend.
Applying: Removed useless prefer-method.
Applying: Added the :unique option to create-table for all backends, needs refactoring.
Applying: Refactored contraints using a list as argument for all backends.
Applying: Refactored column options for all backends, made minor changes to list-constraint and cleaned up a little.
Applying: Added new derivation for ::Generic as java.sql.Connection proxies are confused with com.mysql.jdbc.Connection ones, put prefer-method back in Postgres backend as it now cause problems.
Applying: Added primary-key, unique and non-nulls options to generic create-table.
Applying: Added the :defaults option to create-table for all backends.

We must now return to the master branch where we'll merge the rebased patches.

$ git merge dev
Updating b85d55b..5f771d6
Fast forward
 .gitignore                         |    1 +
 src/clojureql/backend.clj          |   49 ++++++++++++++++++++++++++++++++++-
 src/clojureql/backend/derby.clj    |   31 +++++++++++-----------
 src/clojureql/backend/mysql.clj    |   36 ++++++++++++++------------
 src/clojureql/backend/postgres.clj |   42 ++++++++++++++++++------------
 src/clojureql/demos/derby.clj      |   11 ++++---
 src/clojureql/demos/mysql.clj      |   16 ++++-------
 src/clojureql/demos/postgres.clj   |    2 +-
 src/clojureql/frontend.clj         |   18 ++++++++++---
 9 files changed, 134 insertions(+), 72 deletions(-)

That was simple, isn't it? Joking aside, this may look complex to the uninitiated, but it all make sense once you get used to it. One last thing, after going through this, I had still to push my rebased commits to the Gitorious clone. It didn't worked!

$ git push origin master
Enter passphrase for key '/home/budu/.ssh/id_rsa': 
To git@gitorious.org:~budu/clojureql/budu-clojureql.git
 ! [rejected]        master -> master (non-fast forward)
error: failed to push some refs to 'git@gitorious.org:~budu/clojureql/budu-clojureql.git'

That problem happen to be caused by a safety measure that prevents users from pushing a "non-fast forward" branch to a remote repository. Simply put, when you mess to much with your repository it could end up causing troubles, here's a message from Git's mailing list archives explaining things more properly. You need to use the --force option to circumvent that protection.

$ git push --force origin master
Enter passphrase for key '/home/budu/.ssh/id_rsa': 
Counting objects: 117, done.
Compressing objects: 100% (41/41), done.
Writing objects: 100% (103/103), 17.40 KiB, done.
Total 103 (delta 70), reused 80 (delta 62)
To git@gitorious.org:~budu/clojureql/budu-clojureql.git
 + 42eb50e...5f771d6 master -> master (forced update)
=> Syncing Gitorious... [OK]

I wrote this post for those who are in a hurry and didn't had the time to learn Git properly before contributing to some project. But remember that it's always better to RTFM!

RTFM

No comments:

Post a Comment

About Me

My photo
Quebec, Canada
Your humble servant.