Skip to content

Instantly share code, notes, and snippets.

@anjohnson
Last active November 7, 2022 16:43
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save anjohnson/4344d3ed541f5af27e493aebd68cb3df to your computer and use it in GitHub Desktop.
Save anjohnson/4344d3ed541f5af27e493aebd68cb3df to your computer and use it in GitHub Desktop.
Notes for Git on Launchpad

Andrew's Notes on using Git with Launchpad

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.

Getting Started

Configure the lp: prefix in ~/.gitconfig

[url "git+ssh://anj@git.launchpad.net/"]
    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

Initial Checkouts

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).

Working in branches

Submodule checkouts

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'

Updates

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

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://anj@git.launchpad.net/~epics-core/epics-base/+git/epics-base
 ! [rejected]        master -> master (fetch first)
error: failed to push some refs to 'git+ssh://anj@git.launchpad.net/~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

Feature Branches

Creating

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>

Developed Elsewhere

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

Making Changes

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>

Merging

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

Cleaning Up

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 up into Base-7.0

Merging commits from 3.16 into the 4 module branches of EPICS 7 is somewhat involved. This is what I have so far.

modules/libcom

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.

modules/ca

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

modules/database

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

core

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.

Other Stuff

Create a patch file

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.

Linking to Bug Reports

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

Import from Bazaar

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.

References

See also Launchpad's help page on using Git

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment