Version 78 (modified by 11 years ago) ( diff ) | ,
---|
Git
Table of Contents
Sahana Eden uses the Git DVCS & hosts active branches on GitHub
Developer Workflow
Fork the Sahana Eden Repository
If you've not used GitHub before:
- Sign-up for an account on GitHub
- Set up git on you your computer by following these instructions.
Note: In order to contribute code back to the Eden project, you need to "push" your changes to GitHub, and GitHub requires you to authenticate for that. The instructions describe authenticating using a password. If you don't want to do do that, you can use SSH keys instead, but the SSH setup is longer, and they do not provide instructions for Windows. If you're using Windows, you can follow these instructions. They're for Launchpad, not GitHub. The only difference is, while you're doing Step 5 (which has you copy the "OpenSSH" formatted public key to the clipboard), go over to the GitHub instructions, to the "Add your SSH key to GitHub" section. Ignore the Linux commands and do the part that saves your public key in your GitHub account. If you want, you can also save that public key in a file. - There is on-line help at GitHub
Then get your own copy of the Eden repository (repo) on both GitHub and your local machine:
- Fork the Eden repo at: https://github.com/flavour/eden/fork
- Use git to clone your own new fork down to your PC, as follows:
cd web2py/applications git clone git@github.com:mygitusername/eden.git cd eden git remote add upstream git://github.com/flavour/eden.git
https://docs.google.com/drawings/d/1TppJKr9Qrq6I2KpkljRixx5gYh1seRqCXk8KDWdeIF0/edit
Ongoing Coding
cd web2py/applications/eden # Update your local repository with latest code from the trunk repository on GitHub git pull --rebase upstream # Write Code # Quick review of code (no test code left in, etc) git diff # Check for any new files which need adding git status git add . # Commit Code (Note, no pushes to GitHub here) git commit -am "My Story: Part 1" . . . git commit -am "My Story: Part N" # Pull in changes from trunk git pull --rebase upstream # Resolve any conflicts (see below for how) # Commit fixed code git add . git commit -a # Review commits git log # Use rebase to squash commits to as few as possible to keep revision history clean & make it easier to review the work # http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html git rebase -i HEAD~N # Where N = Number of commits # Push to your branch on GitHub git push
https://docs.google.com/drawings/d/1KElPNMq_annNSi_2f5r9grD-c0c_aZh1KBAOqSAtuPA/edit
Once you have pushed to your branch on GitHub, you will likely want this to be merged with Trunk - this should be done via a Pull Request. This is done on GitHub:
- https://github.com/mygitusername/eden/pull/new/<mystory>(the branch name)
https://docs.google.com/drawings/d/1QmGeuQvFpg3pDQpM9xu81V7MlVy4uU8EzVIRqQ14MwU/edit
Resolving Merge Conflicts
If you encounter conflicts during the rebase, the conflicts will be tagged in the files with:
<<<<<<< HEAD # Commits from Trunk ======= # Commits from <mystory> >>>>>>> "My Story"
You can correct these conflict in your code text editor, then add them andcontinue the rebase:
git add -u git rebase --continue
You can create the .THIS & .OTHER files using:
git show :2:file.txt > file.txt.THIS git show :3:file.txt > file.txt.OTHER
You can use the changes to a file in the remote branch (theirs / OTHER):
git checkout --theirs filename.c git add filename.c git commit
...or the changes to a file in your local branch (ours / THIS):
git checkout --ours filename.c git add filename.c git commit
...or the changes to ALL files in the remote branch (theirs / OTHER):
git checkout --theirs . # checkout our local version of all files git add -u # mark all conflicted files as merged git commit # commit the merge
Or the changes to ALL files in your local branch (ours / THIS)
git checkout --ours . # checkout our local version of all files git add -u # mark all conflicted files as merged git commit # commit the merge
Although on Windows this seems by default to produce UTF-16 files! ('UCS-2 Little Endian'). A script to make this process easier for Windows users is attached: merge.cmd
Rebasing after pushing to GitHub
Squash your commits if they are not in between two executions of git pull or git merge:
# Stash your current work git stash # N = number of commits to squash git reset HEAD@{N} git add -A git commit -am 'Your commit message for the one-big-commit' # Push to your branch on GitHub, overwriting any previous code there git push origin +master # Restore your work in-progress git stash pop
Undoing a commit
You may need to remove a commit you've made, either if you find you don't want it, or if it needs to be fixed. (Note if your commit has already been pushed to GitHub and accepted into the trunk, then you should use a new commit to take out unwanted changes. This section only applies if you're fixing up your repository before the changes are in trunk.)
If you want to fix up your latest commit, you can undo the commit, and unstage the files in it, by doing:
git reset HEAD~1
This will return your repository to its state before the git add commands that staged the files. Your changes will be in your working directory. HEAD~1 refers to the commit below the current tip of the branch.
If you want to uncommit N commits, but keep the code changes in your working directory:
git reset HEAD~N
If you want to get rid of your latest commit, and do not want to keep the code changes, you can do a "hard" reset.
git reset --hard HEAD~1
Likewise, if you want to discard the last N commits, and do not want to keep the code changes:
git reset --hard HEAD~N
If you are not entirely sure you want to discard the code changes, but need a branch without them, you can simply check out a new branch that ends at the last commit you want. E.g. to make a branch that ends N commits before the latest:
git checkout -b <new_branch_name> HEAD~N
See below for more on using multiple branches. To remove a commit from your repository on GitHub, use either the hard reset or new branch method above to reset your local repository to the commit you want on GitHub. GitHub will not let you overwrite a branch with a different history unless you tell it to with the --force option. If your local and remote branches have the same names, you only need to specify the branch name once, without the ":".
git push --force origin <local_branch_name>:<github_branch_name>
Working with multiple branches
If you are working on several tasks, or want to make temporary changes for experimentation, or want to back up your work before doing a rebase or reset, you can do that by having multiple branches in your repository and switching between them. Each branch is a sequence of commits leading up to a specific head commit (which can be referred to as HEAD without confusion since git knows which branch you're referring to by which is checked out). It is very common for git users to switch between branches, and this is a fast operation in git.
To make a new branch equivalent to the current branch:
git checkout -b <new_branch_name>
To switch from one branch to another, just check out the other branch: ((( git checkout <other_branch> }}}
Note git will not let you switch to a different branch if you have uncommitted changes in tracked files. To get around this, the simplest thing to do is to commit your modified files in a temporary commit, then undo that commit later. You can also "stash" your work, which actually makes a commit on a special branch. Since it's easy to forget what's in the stash, unless you're only stashing briefly, a real commit with an informative message is probably better.
To list all the branches in the repository:
git branch -v
The -v (for verbose) tells git to show not just the branch names, but also the head commit's revision number and message.
To rename the current branch:
git branch -m <new_branch_name>
To rename a branch that is not checked out:
git branch -m <old_branch_name> <new_branch_name>
To delete a branch:
git branch -d <branch_to_delete>
Under some circumstances, git will complain when you try to rename or delete a branch. If you are sure you want to do it, use -M instead of -m for rename, or -D instead of -d for delete.
If you will be working on a specific branch for a particular event (e.g. a deployment or hackathon), then you can add that branch to your local repository:
git remote add <branch_name> https://github.com/flavour/<branch_name>.git git fetch <branch_name>
Now you have both the master branch from the trunk repository, and the specific branch <branch_name>.
You can push branches other than master to your GitHub repository.
git push -u origin <branch_name>
Note it is good to specify the branch name to push, else git will try to push all of them. The -u tells git to make your local branch "track" the remote branch. This is only needed on the first push to that branch.
If you need a specific revision of the current branch, your can check out that revision on a new branch:
git checkout -b <revision> <branch_name>
(git requires a name for a branch if you want to preserve commits.)
Creating a second working directory and repository
If you wish to have multiple directories containing different branches, you can run these as separate web2py applications. (Note this is not a standard manner of working when using git, and is generally only needed if you are working on multiple projects at the same time, and need to preserve their databases and other state.)
- Create a fresh clone:
cd web2py/applications git clone git@github.com:flavour/eden.git <new_repository>
- Setup a new repository on GitHub -- see: https://github.com/repositories/new
- Add remotes.
git remote add upstream git@github.com:flavour/eden.git git remote add origin git@github.com:<my_git_username>/<new_repository>.git
- Push to GitHub:
cd <new_repository> git push -u origin master
Using Patches
If you have made changes to one branch & wish to backport them to another branch, then this is done most easily using a Patch:
Story Branches
The Story Branch pattern allows pushing interim work to GitHub for review & also allowing contributing quick fixes to Trunk without needing to complete the interim work:
git checkout -b <mystory> git commit -a ... git commit -a # Quick review of code (no test code left in, etc) git diff master...HEAD
https://docs.google.com/drawings/d/1Vhvm1EmqWOVNZkZsiJ0MLLpdTl6H_ya263Tdb2HK1N0/edit
Developer Configuration
Tell git your name and email, which it uses to identify you as the author of commits. And tell it your account on GitHub.
git config --global user.name "Your Name" git config --global user.email your@email.com git config --global github.user yourgithubusername git config --global github.token yourtoken
These are examples of other settings you can change. The values shown are not necessarily ones you'll want to use. For instance, the choice of diff and merge tools is contentious -- use your favorites.
git config --global core.editor "'C:/Program Files (x86)/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin" git config --global merge.tool diffmerge git config --global diff.tool diffmerge git config --global difftool.diffmerge.cmd 'C:/Program Files (x86)/Git/etc/wrappers/git-diff-diffmerge-wrapper.sh' "$LOCAL" "$REMOTE" git config --global difftool.prompt false git config --global merge.tool diffmerge git config --global mergetool.diffmerge.cmd 'C:/Program Files (x86)/Git/etc/wrappers/git-merge-diffmerge-wrapper.sh' "$PWD/$LOCAL" "$PWD/$BASE" "$PWD/$REMOTE" "$PWD/$MERGED" git config --global mergetool.prompt false git config --global mergetool.trustExitCode false git config --global mergetool.keepBackup false
An alternative to diffmerge is Perforce's free P4V:
Windows
Install Console & Diffmerge & configure Powershell.
Developer Tools
.gitattributes
runs version.py
to update the VERSION
file on commit
Possibly we could add a pre-commit hook to run tests, e.g. based on http://tech.yipit.com/2011/11/16/183772396/ or http://blog.penzilla.net/2011/09/git-pre-commit-hook-for-python-now-with.html
Notifications
You can subscribe to commits via RSS, e.g. to subscribe to Trunk, use:
If you wish to receive email notification of commits, then you can use an Email to RSS service like:
Resources
- Community Book: http://book.git-scm.com
- Tips & Tricks: http://gitready.com
History
Why?
Sahana Eden has decided to move from Bzr/LaunchPad to Git/GitHub
- The current repository is huge & bloated, taking too long to download.
- Even simple changes take an age to Pull down to servers
- Web2py no longer supports Bzr/LaunchPad, so we want to be able to maintain a common tool to work with both repositories.
- New developers are likely to be more familiar with Git/GitHub
How?
The preferred approach is to have a clean repository, in order to get the maximum benefit from the migration...although it is technically possible to migrate the commit history. Commit History will instead be maintained on the LaunchPad site as an archive
Migrating existing Branches
Merge branch with trunk using normal Bzr tools
Assuming that you have already forked Eden Trunk, then you will need to create a new repository manually for additional branches, as you cannot fork your own project on GitHub:
- https://github.com/repositories/new
cd web2py/applications git clone git@github.com:flavour/eden.git <mybranch>2
- Move
.git
&.gitignore
from <mybranch>2 to <mybranch> - Delete the rest of <mybranch>2
- Edit
.git/config
:[remote "origin"] fetch = +refs/heads/*:refs/remotes/origin/* url = git@github.com:<mygitusername>/<mybranch>.git
- Create the initial repo for this new branch
cd <mybranch> git add . git commit -am "Initial Git version of My branch" git push -u origin master git remote add upstream git://github.com/flavour/eden.git
Attachments (2)
-
merge.cmd
(186 bytes
) - added by 13 years ago.
Windows script to help with merge conflicts
-
pre-commit
(190 bytes
) - added by 3 years ago.
pre-commit
Download all attachments as: .zip