This page describes how I'm planning to work with git and lp, others don't have to follow my approach. The mirroring that I describe below may be slightly unusual, so your local git expert might not fully understand it.
Configure the lp: prefix in ~/.gitconfig
[url "git+ssh://[email protected]/"]
insteadof = lp:
The following aliases may be useful if using the mirror described below:
[alias]
fetch-mirror = !git -C `git config remote.mirror.url` fetch
push-mirror = !git -C `git config remote.mirror.url` push --all
Git doesn't have a shared repository for the history data like Bazaar does.
However the mirror technique used below should reduce network traffic and result in some sharing of history data between trees.
First, clone the project as a mirror of the launchpad repository, but turn off the core.<remote>.mirror
setting:
git clone --mirror lp:epics-base mirror-base
git -C mirror-base config remote.origin.mirror false
Turning off the mirror setting is very important! Without doing this a push from this mirror back to launchpad will discard other people's commits without warning.
Now create working directories for each branch you want as separate local clones from the mirror. When cloning a working tree onto the same filesystem as the source repository, git uses hard-links to share its history files instead of making separate copies.
git clone -b 3.14 -o mirror mirror-base base-3.14
git clone -b 3.15 -o mirror mirror-base base-3.15
git clone -b 3.16 -o mirror mirror-base base-3.16
git clone --recursive -b 7.0 -o mirror mirror-base base-7.0
Build and develop in these branches as normal (avoid using git checkout
to switch to other branch series though since the result could be confusing).
The base-7.0 tree uses git submodules. These will initially be checked out with a detached head. Before starting development on a submodule, check out its appropriate master branch. The following command checks out the master branch for all submodules:
git submodule foreach 'git checkout master'
To update a working directory with new commits that were added to the branch on Launchpad, use:
git fetch-mirror # See the above alias
git pull
If you had made any local commits since your last update the git pull
command will attempt to merge those changes.
If successful it will bring up your editor for the merge commit log message.
If the merge fails due to conflicts (overlapping commits) it should be cancelled; cleanup may require
git reset --merge
Instead of merging it is probably better to rebase your commits onto the Launchpad branch:
git fetch-mirror # See above alias
git pull --rebase mirror
This may require the use of these commands:
git add <filename> # To mark a conflict in <filename> as resolved
git rebase --continue
git rebase --abort # To cancel the rebase operation.
Commits made in this branch will be recorded locally (there's no bound remote branch like Bazaar has). To push commits to Launchpad, first push them to the local mirror repository, then from there to lp:
git push mirror
git push-mirror
The second git push
from the base-mirror directory may fail with an error like this:
To git+ssh://[email protected]/~epics-core/epics-base/+git/epics-base
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'git+ssh://[email protected]/~epics-core/epics-base/+git/epics-base'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
This means that someone else has pushed a commit to this branch on launchpad since you last pulled from it.
Note that the git push
rejection error might not have been for the branch you're currently working on, double-check first!
A git fetch-mirror
now will fetch the remote updates, discarding the conflicting local commits from the mirror.
However those commits are still recorded in the local branch, so they haven't been lost completely.
To fix the conflict, use git fetch-mirror
followed by git pull mirror
or git pull --rebase mirror
as described above.
Using git pull mirror
command will trigger a merge;
a git pull --rebase mirror
is probably more likely to succeed, but may generate conflifts that must be resolved.
After resolving everything (and potentially re-testing the result), re-run these:
git push mirror
git push-mirror
Create a feature branch by cloning an existing branch from the mirror or from another checked out tree. Edit/build/commit as normal.
To push this to a new repository on launchpad:
git remote add <remote-name> lp:~anj/epics-base/+git/<repo-name>
or
git remote add <remote-name> lp:~epics-core/epics-base/+git/<repo-name>
To work with a feature branch from someone else, first add it as a remote and fetch its contents:
git remote add <remote-name> lp:~epics-core/epics-base/+git/<repo-name>
git fetch <remote-name>
You can take a look at the branch without merging it (assuming the feature is on the master branch):
git checkout <remote-name>/master
This leaves the tree with a detached HEAD, so you can't commit changes to it in this state.
To examine the git log of one specific commit including its code changes:
git log -p <sha>^!
Don't forget to switch back to your local branch again, e.g.:
git checkout 3.15
To do some work on this branch (to modify it and push it back) create a local branch which tracks the remote one:
git checkout -b <local-branch-name> --track <remote-name>/master
To push this local branch back to the remote master branch:
git push <remote-name> <local-branch-name>:master
To push this branch to a new branch in an existing repository with an existing remote:
git push -u <remote-name> <branch-name>
or
git push -u <remote-name> <local-branch-name>:<remote-branch-name>
To merge a remote master branch into your current branch without committing:
git merge --no-commit <remote-name>/master
The --no-commit
flag is useful for testing the result of merging.
This will show any conflicts between the series branch and the feature branch.
To undo a test merge and restore the workspace to its previous condition, use
git merge --abort
If the merged result is good and to be kept, instead of aborting do:
git commit
git push mirror
git push-mirror
When completely finished with that local branch and the remot, remove the remote and delete any local branches:
git branch -d <local-branch-name>
git remote remove <remote-name>
Merging commits from 3.16 into the 4 module branches of EPICS 7 is somewhat involved. This is what I have so far.
The git mv
commands below should only need to be run when new files were added to this directory on an earlier branch.
The git rm -rf
commands are needed to clean up changes to files that belong to other submodules.
cd modules/libcom
git merge --no-commit mirror/3.16
git rm -rf configure/os documentation src/ca src/ioc src/std src/template
git mv -k src/libCom/test/* test
git mv -k src/libCom/* src
Additional manual changes will probably be required, for example to src/Makefile
.
Be sure to build the result and run the self-tests before committing anything.
The git mv
commands below should only need to be run when new files were added to this directory on an earlier branch.
The git rm -rf
commands are needed to clean up changes to files that belong to other submodules.
The ordering of some of these commands matters.
cd modules/ca
git merge --no-commit mirror/3.16
git mv -k src/ca/client/perl/* src/perl
git mv -k src/ca/client/tools/* src/tools
git mv -k src/ca/client/* src/client
git mv -k src/template/base/top/caClientApp/* src/template/top/caClientApp
git rm -rf configure/os documentation src/libCom src/ioc src/std src/template
The git mv
commands below should only need to be run when new files were added to this directory on an earlier branch.
The git rm -rf
commands are needed to clean up changes to files that belong to other submodules.
The ordering of some of these commands matters.
cd modules/database
git merge --no-commit mirror/3.16
git mv -k src/ioc/db/test/* test/ioc/db
git mv -k src/std/rec/test/* test/std/rec
git mv -k src/std/filters/test/* test/std/filters
git rm -rf src/template/base/top/ca*App src/template/base/top/configure
git mv -k src/template/base/top/* src/template/top
git rm -rf configure/os documentation src/ca src/libCom src/template
The git mv
and git rm
commands below should only need to be run when new files were added to the relevent directory on earlier branches.
git merge --no-commit mirror/3.16
git rm -rf src/ca src/libCom src/ioc src/std
git mv -k src/tools/test/* test/tools
Additional manual changes may be required. Be sure to build the result and run the self-tests before committing anything.
Git has a command for generating patches which is nicely configurable.
Use this command after committing the change to create a patch file containing just the last commit (HEAD^
):
git format-patch -p --minimal --no-prefix HEAD^
To select more than one commit see git help gitrevisions
.
When committing a bug-fix, Launchpad will link to the bug if the commit message matches this regular expression:
/[Ll][Pp]:\s+\#\d+(?:,\s*\#\d+)*/
For example, LP: #123456
or LP: #123456, #234567
There are various ways to convert a Bazaar branch to git. The method Michael recommends works out-of-the-box with newer versions of git, but requires this plugin with older git versions. It provides a nice bidirectional connection between a git workspace and a remote Bazaar repository:
git clone -o bzr bzr::<path-to-bzr-repo> <new-git-repo>
See the section on creating feature branches above for how to push the result to Launchpad.
See also Launchpad's help page on using Git