Getting the GIT checkout
Import Straight from the SVN repo
First, we need to fetch a copy of the repository.
git svn clone -s -r 40000:HEAD https://svn.parrot.org/parrot # choose some recent-ish commit
-s is for --stdlayout which presumes the svn recommended layout for tags, trunk, and branches.
-r is for the revision to start taking history from. If you want to include all of the history, just leave that option off, but it will take a very long time, and you really don't need all of it.
NOTE: The older a revision you choose, the longer it will take to import. But you will not be able to "git blame" past the earliest revision you import. Choose wisely.
This takes a clone of the repository at that revision; to update it to HEAD, you now need:
git svn rebase
Which is very similar to svn up.
From the leto's github mirror
Because importing all of history is *very* time consuming, DukeLeto has already gone through the trouble and maintains a github mirror of Parrot at http://github.com/leto/parrot/tree/upstream .
git clone git://github.com/leto/parrot.git
This will create a directory in the current directory named 'parrot'. If you want to specify the directory to create, pass one more argument.
The "upstream" branch is what directly mirrors Parrot trunk. To start a local branch that tracks the upstream branch:
cd parrot && git fetch && git checkout -b upstream origin/upstream
Adding git-svn metadata to the github clone
If you want to re-populate the SVN metadata that can quickly be done by taking your up-to-date clone of leto's repo off of gihub and adding this to your .git/config
[svn-remote "svn"] url = https://svn.parrot.org/parrot fetch = trunk:refs/remotes/trunk
Then run this command to find the "top commit"
git show origin/upstream | head -n 1
and put that commit hash into a file .git/refs/remotes/trunk (obviously replace the has with the one from the above command)
echo c85aaa38b99cedb087e5f6fb69ce6d4a6ac57a0b > .git/refs/remotes/trunk
git svn fetch
From full git-svn tarball
You can also download a tar archive containing the complete history and all branches as well as svn meta data from
- http://technosorcery.net/system/parrot-git-svn.tbz (Updated daily)
- http://moritz.faui2k3.org/files/parrot-all-git-svn.tar.gz (recommended; prepared by Tene, polished by moritz).
Basic local workflow
Now, start working on patches. The simplest way to work, without local branches, is:
hack; hack; hack; hack git diff # look at differences since the last commit
If you want to commit all of these changes, run:
git commit -a
and enter your commit message. This creates a local commit only. It hasn't been pushed to the SVN server yet. If you only want to add changes from some files but not others, run:
git add file1 file2 file3 ... git add -i file4 # if you only want to add some diff hunks and not others git commit
and enter your commit message. After this, 'git diff' will still show the uncommitted changes. While you're adding changes to be committed, you can run 'git diff --cached' to see what's going to go in the next commit.
After you've made however many commits, you can push up to the svn server with:
git svn dcommit
That will also bring your local tree up to date. To bring your tree up to date in general, run:
git svn rebase
This will update your local checkout and then re-apply your local un-submitted commits on top of the new trunk.
If you want to get the commits for all branches that exist in your clone:
git svn fetch
Patches Between Local Changes and Trunk
If you want to see the patchset representing your commits and the remote server:
git format-patch remotes/trunk
Change trunk to the name of the branch, if you're working against a branch. This will create a series of numbered patches, corresponding to every commit you've made. You can review them as you like.
One of the neat things about git is that you can modify your commits before you push them up to the SVN server. Let's say you've made 10 commits to your local git repository, but you want it to look like two when it gets pushed up to SVN. All you need to do is type
git rebase -i HEAD~10
And git will launch your $EDITOR and allow you to perform what's referred to as an "interactive rebase."
pick 08464ae bug 9074 Fix bad logging call. pick 8750643 bug 9995 Run the supplied architecture through arch_extract() to change 'x64' into 'x86_64' when it occurs. pick af6f7ae bug 9995 Make sure the architecture string occurs on word boundries (ie, it's not part of a larger word) pick 8e4ef0c Don't generate a warning for generic apps. pick 1e4d124 Add a module for handling script-based custom applications. pick 808607d bug 9879 Resolve paths to entity IDs at the start of a process. pick e02a0db bug 9879 Cosmetic code formatting changes. pick 3e1cc94 bug 10010 Added an optional comparator argument to compare_homes pick 218805c bug 10010 Added comparator argument to default implementation for consistency pick 21e20fa bug 10010 Made procs_under_home use compare_homes to handle case insensitivity on windows # Rebase 05e760e..21e20fa onto 05e760e # # Commands: # pick = use commit # edit = use commit, but stop for amending # squash = use commit, but meld into previous commit # # If you remove a line here THAT COMMIT WILL BE LOST. # However, if you remove everything, the rebase will be aborted. #
If you change any of the lines that start with "pick" to start with "squash" instead, when you exit your $EDITOR, that commit will be squashed into the commit above it and you'll be popped back into $EDITOR to combine the commit messages into one. You can also squash multiple commits into more than one commit in a single session; $EDITOR will be fired up for each of the resulting commits for you to combine the commit messages.
You can also reorder commits just by moving them up or down in the list, and you can drop commits entirely by removing them from the list.
Attached to this page is a perl script called gsquash which uses git log to look for commits that haven't been pushed to SVN yet and builds the appropriate git rebase -i HEAD~n command.
Let's say you're working on some stuff that's not quite ready to be checked in, but you suddenly need to work on something else. You can type git stash, which will record the current state of your work and give you a clean working directory again. You can then make whatever changes you want to your working directory, commit them, dcommit them to SVN, and then type git stash pop to get what you were working on before back. You can also build a stack of stashed work by repeatedly making changes followed by git stash commands; you can then list these stashed modifications with git stash list. For full documentation on the fun of git stashing, type git stash --help .
Another benefit of git is it's extremely easy to create a branch in your local git repository:
git checkout master git branch rt1739 git checkout rt1739
This makes a local branch off your master branch called "rt1739". You can commit changes to this branch that won't affect your master branch, and you can switch back and forth between your local branches and your master branch. In addition, each of these branches is connected to the trunk of the SVN repository, so any changes dcommitted from these branches will automagically be merged into the SVN trunk and appear in your local trunk the next time you run git svn rebase when you have your trunk checked out.
Other developers may access your local branches, but in order to do so, they would need to be able to access your git repository.
Tracking SVN branches with GIT
Start svn branch in git.
git svn branch -m "Branch for work on extra cool feature" extra_cool_feature git checkout --track -b extra_cool_feature_local remotes/extra_cool_feature # to avoid warning from git about ambiguity git reset --hard remotes/extra_cool_feature ... hack/git commit/git commit --amend/git rebase -i HEAD~10/... as usual
dcommit to svn
git svn dcommit --dry-run # check that it will commit to proper svn branch. git svn dcommit
Merging trunk into branch
git checkout master git svn rebase git checkout extra_cool_branch git merge --squash master git commit -m "Bring branch up-to-date with trunk"
Merging branch back to trunk
git checkout master git svn rebase git merge --squash extra_cool_feature git commit -m "Merge branch into trunk"
Hints and caveats:
- Don't try to rebase already dcommited changes. They are not belong to you anymore.
- Always run "git svn dcommit --dry-run" before real commit to check in which branch your changes will be committed.
- Always merge branches with "--squash". Otherwise git-svn will do it for you and can epicly fail sometime.
- svn isn't smart enough to track merges. So, don't try to merge branches with pure svn and git-svn on same branch.
Ignoring generated files
Svn stores ignores as meta data, git in .gitignore files. You can ignore the SVN metadata (and generated files) with these files. First, edit your .git/info/exclude file to contain:
... or else git-svn will want to track all .gitignore files. Now generate the .gitignore files automatically by running
git svn create-ignore
If you have not excluded these files, they will be staged for your next commit. You probably do not want this, as dcommitting them will add them to Parrot's SVN. Beware.
We've heard a lot about how git will ease the pain of working in branches; can you provide an example, showing a branch that all committers can collaborate on, that can be rebased against trunk as needed, and then merged back to trunk?