Public git mirror

I have setup a public git repository that is mirrored off of the sourceforge svn. For anyone that would prefer to use git, you can clone this repository and interface with it until a patchset is ready to commit to mainline jnode.

For those that know how to work git already here are the urls.
Pull : git://repo.or.cz/jnode-mirror.git
Push : git+ssh://@repo.or.cz/srv/git/jnode-mirror.git

There is anonymous access via the 'mob' user, but it only has push access to the 'mob' branch. In order to gain full push access, you have to setup a username on http://repo.or.cz . All you need is a username, and email and a public ssh key. If you put a password on your ssh key, then you will need the password each time you push, if you give it no password, it will push automatically. Let me know your username, and i'll add to the list.

For those not totally familiar, i'll run down the basics of getting setup. I would recommend that for anyone new to git to read the git manual. It has lots of great examples on everything from the basics to more advanced multi-branch merges and bisecting regressions. The manual is at: http://www.kernel.org/pub/software/scm/git/docs/user-manual.html

Cloning the repo
The first thing to do is clone the repo. The master branch of the repo is kept in sync with the sf.net svn repo. For those that have full access, please dont push to the master branch, i'll only have to revert it. I want to keep master clean so that it mirrors the svn repo. SVN doesn't do branch merge like git does, so we can't just merge branches to master and commit to svn, its a bit more complex than that because svn doesn't keep the same information that git does (namely branch history).

To clone the new repo :

cd ~/code/
git clone git://repo.or.cz/jnode-mirror.git jnode

This will take a few minutes, the initial clone is a 125mb download, took me about 10 minutes. This is a _complete_ clone, meaning it has everything from r1-HEAD of the svn repo. This is part of the reason why I setup this mirror. Cloning the svn repo to git can take > 1 hour because it checks out r1 then r2 then r3 all the way to 5000+. So instead of 90 minutes, it should take 5-15 minutes.

Once this is done, you will now have a new directory setup with a git repo and full working directory in ~/code/jnode or wherever you chose to base it. Git will also be configured with a new remote and a new branch. By default the new remote is called 'origin' and you can use that to refer to the remote repo. There are 3 basic ways you can make use of git from this point, each will require further configuration.

1) Create patches
If you simply want to be setup so that you can create patches against origin/master then you can setup a new branch, which will have a HEAD that is initially the same as master, but diverges on its own path. Once you are ready you can simply update the master and create a patch against master for submitting via the forums.

git pull origin master  # Updates the master branch with any new changes
git diff master >changes.patch # Creates a patch from the diff of the current branch and master

2) Anonymous push access
In order to setup for anonymous push access you have to setup a new remote.

git config --add remote.mob.url git+ssh://mob@repo.or.cz/srv/git/jnode-mirror.git
git config --add remote.mob.fetch +refs/heads/*:refs/remotes/mob/*

When you update your local master, you still want to 'git pull origin' with the master branch checked out. And it will update to that of the origin/master, mirroring the svn repo. When you create a new branch, you can configure it so that it uses the remote 'mob' and automatically sets it up to merge with the remote mob branch.

git checkout -b [branch]
git config --add branch.[branch].remote mob
git config --add branch.[branch].merge refs/heads/mob

You will now be able to 'git push mob' from the branch and it will push the changes upstream. As this is an anonymous push that anyone has access to, i would recommend _never_ pulling or rebasing against the mob branch and blindly compiling. Also it is unlikely that the mob branch will be stable, and will in likelyhood be culled back to master once in awhile. If you plan on using the remote repo to push public changesets to, i would recommend getting setup with full access. Its open to everyone.

3) Registered push access

In order to get full access to the repo, you have to create a username at http://repo.or.cz. There's nothing special, just enter a username, an email, and a public ssh key. You can choose wether to password protected your key or not, there is no password for the site. If you dont have a key you can do the following to get one. \

Note: Make your username is easy to type, as it has to go in the url for git.

$ ssh-keygen

Your public key will be put into ~/.ssh/ with a .pub suffix, mine was id_rsa.pub. The key is text so you can open it in an editor (disable word wrapping) and copy/paste into the browser.

Once you have a username and submitted a key, let me know your username and i'll add you to the list. You will then want to update your remote origin setting to the new url.

git config remote.origin.url git+ssh://[username]@repo.or.cz/srv/git/jnode-mirror.git

If you had any branches configured to with the remote mob, you can configure with the remote 'origin' and you will have push/pull access via that remote name. If you unsure of how branches are configured, git config -l will list the config options.

Once your configured with the new remote with push access, you can push whole new branches into the remote repo. In fact this is the way i would prefer it. When you create a new branch configure it against origin, and setup a merge target that uses a new branch on the remote.

Create new branch and push to public repo

git branch [branch]
git config branch.[branch].remote origin
git config branch.[branch].merge refs/head/[branch]
git checkout [branch]
git push origin [branch]

Create a branch from a remote branch, and setup automerge

git branch --track [branch] origin/[other_branch]
git pull

If you created a new branch and pushed it upstream, there will be a branch matching that of your branch. While in that branch you can simply 'git push' to update the remote branch, and 'git pull' to bring in any new changes if others are also working on that branch. Remember you can always commit/reset and otherwise change your local branches, but once changes get pushed into the public repo, dont do any reverting. If you have to 'undo' something, then undo the changes and commit a new change undoing what was already commited, and push the change upstream. Pulling changes out from under a git branch has nasty side effects that can be hard to resolve. This way your old undone changes are not lost either.

Also, please do not push any changes to master. I want to keep the master clean and in sync with the svn repo. So long as we still have an svn repo, then we have to gimp some features of git. the public git master branch is a complete mirror of trunk. When changesets are ready to go from the public git to sf.net svn, the mainline, then we will have to diff against that master to come up with change sets that can be commited to svn from an svn-aware git repo. I have an svn-git repo so i can pull and mrege branches from the public git repo, to my private repo for commit on the svn.

Commiting to sf.net svn

If anyone that has svn commit access would like to commit from git to sf.net svn, then you will have to create a special repo on your local system that is configured with git-svn. There are 3 basic commands i use with git-svn.

git svn clone --stdlayout [sf.net svn url] [jnode-svn dir] # Clone the svn repo to a local repo of its own.
git svn rebase     # Same as svn update
git svn dcommit    # Same as svn commit

Note: git svn clone takes a long long time. At least an hour, possibly 2 depending on your net connection. This is because this is cloning _everything_. Every rev since r1 will be checked out, every branch will be checked out, every tag will be checked out. It is a complete clone.

I also setup new remotes that are configured to other locations. There will be a default remote-svn created that has all the config needed for the svn rebase/dcommit. The 'master' branch is linked against /trunk. In order to bring changes from an outside git into the git-svn repo, you need to setup new remotes.

Linking svn-git repo to your local git repo
git config --add remote.local.url /path/to/local/repo/.git
git config --add remote.local.fetch refs/heads/master:refs/remotes/local/master

Linking svn-git repo to repo.or.cz
git config --add remote.gitpub.url git://repo.or.cz/jnode-mirror.git
git config --add remote.gitpub.fetch refs/heads/master:refs/remotes/gitpub/[some_branch]

These are the two basic remotes that im using from my svn-git.

There are likely to be some 'conflicts' when dealing with svn and git together. The major conflict is that when a commit is made from git to svn, there is a 'new commit object' created that has a different SHA hash that the original. This requires rebasing from the master. Its not a big problem, its mostly because svn uses a linear history, where git uses a branched history. svn wants all commits in the same branch, trunk, where git happily keeps track of dozens of branches and simply merges them. The difference between svn merging a branch and git merging a branch is git remembers the heads of both of those branches before the commit. A git merge object has two parents, svn commits can not have two parents. This is where the complication arises and is solved with whats called rebasing. If you want to know more, i recommend the git manual, its a quick and easy read.

Crash Course

I found this crash course documentation on git aimed at svn users. It highlights the brief details of git usage for someone that is used to svn. This has been linked in the git docs of the handbook also.

http://git.or.cz/course/svn.html

If the GIT mirror is "supported" ...

... then the material in this forum topic should be turned into a page or pages in the Documentation tree.

section added to the dev man

section added to the dev man for git. Its only a brief on settings, getting setup, and a couple of simple rules.

GIT plugin for major IDEs

I have found these plugins for major IDEs :
Eclipse : EGit
Netbeans : nbgit
Intellij IDEA : git-idea

Fabien

my blog : en français, in english or both

Something else i forgot. The

Something else i forgot. The public page for the git repo web interface.

http://repo.or.cz/w/jnode-mirror.git

Some other options

Signoff
If you want to setup git to put in a Signed-off-by tag into commit messages then setup two config options.

git config --add user.email [email]
git config --add user.name [name]

Now when you commit a change to a branch, add the -s flag to git commit and it will automatically insert your sign-off tag.

Rebasing
Because of svn, any changes that are brought downstream from svn into a branch will require a rebase. Normally git would merge branches and there would be a new merge object that held refs to the two heads of each branch. Instead to merge changes from svn into a branch, we 'rebase' the branch. What happens is, git undoes all of your commits going back to a common point between your branch and the branch your rebasing to. Git then applies all the changes from the other branch, and then reapplies your changes on top of that. In this way a linear history instead of a branched history is formed, and is suitable for svn. For this example, origin/master is the master branch on the public git repo that is mirroring svn.

git checkout [my_branch]
git rebase origin/master
... deal with merge conflicts if any ...

Seeing what has changed

If you want to see what is new since a branch was made, the '..' syntax can do this, some examples...

git log origin/master..[some other ref] (1)
git log [some other ref]..origin/master (2)

The first lets you see all the new commits on origin/master, the other lets you see all the new commits on the other ref. The point where the log would start is the common ancestor of the two. When you create a new branch, that point is the common ancestor between your branch and the branch you came from. This syntax can also be handy in making diffs where there are changes to origin/master that you havent rebased to yet.

git diff [my_branch]..origin/master

Will give me a diff of everything on my branch since i branched from origin/master, or since at least since i last rebased from origin/master.

Common refs
Getting used to refs is a bit different from working with svn. The basic ref is a 40-byte sha1 hash. If you have to use one of these hashes as a ref, it suffices to only use a prefix of the hash, say the first 6-8 bytes, in general that is plenty unique enough to avoid collisions in the same repo. But there are other labels that are simpler to use and remember.

HEAD : This is the latest commit in the currently checked out branch.
[remote/][branch] : explicetly naming a branch. [remote] is optional and can be used to name a branch in a remote location.

refs can have relative suffixes that specify some revision based on that ref. The ^ is used to reference the parent of a ref. HEAD^ is the parent of HEAD. You can also use ~[num] to specify previous refs. HEAD~0 is the same as HEAD, HEAD~5 is 5 commits before HEAD.

Like you seen above with the log above, the .. syntax can be used to find changes on one branch that dont exist in another. A..B shows the changes in A that dont exist in B, this can be usefull to see only what is new in some branch compared to another.

If you need to translate a labeled ref into an sha1 ref, git rev-list is the tool.

git rev-list --max-count=3 HEAD  # The last 3 commit IDs on the current branch
git rev-list origin/master..HEAD # List of commit IDs on master that are not in HEAD