git's cookbook for OpenSDE

I'll start by the most basic request, PLEASE read git's documentation! git is very well documented.

If you still here I guess you decided that the official documentation was to tough for you. Then you can try a different kind of documentation, one focused on understanding how git works instead of how git is supposed to be used.

but this guide is an OpenSDE-centric cookbook, so we will explain how to use git on our context.

OpenSDE itself is composed by two git repositories, one for the framework and one for the packages database.

These repositories currently don't include the past of the project which partially comes from RockLinux's, T2 and our own old Subversion repository. The task of importing these commits into a new and more complete git repository has been postponed.

In OpenSDE the targets are considered sub-projects so they have their own repositories. And we also support external repositories in package/repo. sde up currently handles these external repositories when they are svn or git.

On OpenSDE we provide a silver bullet tool which tries to hide some version control system specifics, to help in the building and maintaining processes, and to encourage some “recommended” practices while reducing the effort for the user.

But sde can't (and should not) wrap the entire vcs functionality, just the most common actions.

sde is designed to run from $PATH, from any directory, understanding the context and using that knowledge to make user's life a bit easier.

The sde wrapper takes the commands from the working directory you are using, so it's version independent.

When you already have an OpenSDE working tree, and sde in your $PATH, creating a new tree is very simple.

$ cd somewhere
$ sde new tree mynewtree

And this will use git to get the opensde repo from the same location you were using before in somewhere/mynewtree and also the corresponding somewhere/mynewtree/package.

If you don't have OpenSDE yet the steps are the following (need git installed):

$ cd somewhere
$ git clone git://git.opensde.net/opensde/opensde-nopast mynewtree
$ cd mynewtree
$ git clone git://git.opensde.net/opensde/package-nopast package

It is a very good idea to install sde in your $PATH. to do that go to the root of your OpenSDE tree and:

$ ./bin/sde install

This will symlink bin/sde of this working tree into your $HOME/bin, which is supposed to be in the head of your $PATH. Most distributions do this automatically, if the directory exists when you log-in. So logging out and back in may solve the issue. If not, you may want to add it on your own $HOME/.profile as:

export PATH="$HOME/bin:$PATH"

If you cloned opensde-nopast using git and you already put sde in your $PATH, sde up will get package-nopast for you if it's still missing.

In OpenSDE staying up to date is very easy, even when you have local commits which you don't want to send upstream (push) yet. But you have to remember git, unlike svn needs your working tree clean of uncommited changes.

$ sde up

And your tree (including framework, packages and targets) will be up to day.

To do it by hand you have to use git on each repo. (don't forget the –rebase part).

$ git pull --rebase

but when you are working on a local branch and you don't want upstream changes injected on it yet use:

$ git fetch

and origin/master will reflect the current upstream state, but your local branch wont be touched.

We inherited subversion from our predecessor. svn is great but not for us because:

  1. you need to be online to work with it.
  2. to merge from branch is painful

We encourage people to work on public branches so we can all comment, contribute, and test before the final code hits the trunk (tip or master).

But the problems shown above make people work on (private) working trees plenty of uncommited changes, and out of sync with upstream.

The first question is, a branch of what? … let see what we have

$ git branch -a
* master

Assuming you want a local branch (on which you could work) corresponding to upstream's origin/foobar we create a tracking branch using:

$ git checkout -b foobar origin/foobar

This will bind the local branch “foobar” with the remote branch of the same name, in the remote named “origin”. The other common case is to branch your current local “master” so you can:

  1. commit all the uncommited changes you have in your messy working directory to be able to get in sync with upstream again.
  2. push some commits upstream but not all, without loosing them.
  3. move your work to a different topic branch.
  4. start a new topic branch starting at this point.

The first step for all of these cases is:

$ git checkout -b mynewbranch

and now you are at “mynewbranch” instead of “master”, which can be confirmed using git branch.

If you are on case 1, the next step is to git add, git rm and git mv what have have in git status, and make a monster git commit, or if you are terribly lazy git commit -a Then you can return to “master” using git checkout master. Once back in “master”, if you were on case 1, git pull –rebase should work. If you were in cases 2 or 3, git rebase -i origin/master^ will let you remove those commits which you want in “mynewbranch” but not in “master” yet so you can push just a selected bunch.

We don't like git merge (that's why we don't use use git pull), we like to keep the commits atomic, not as a big monster commit as git merge produces.

It's perfect (and recommended) to create a branch to update (and test) all the packages related to the last foo release. But the updates of each package shall remain separated. When one keeps branches, it's common to want to include on a branch a commit done in another branch. This is done using git cherry-pick <hash>, but you don't need the whole hash of the commit, instead the first 6-8 characters are usually enough.

$ git log otherbranch | less               # to identify the commit
$ git cherry-pick 1a2bcd

Another common case is when you want to cherry-pick a range of commit, but git cherry-pick doesn't support ranges, so we need to loop. Assuming we want to merge from aabbcc (older) to ddeeff (newer), including both the shell loop would look like:

$ for hash in $(git rev-list aabbcc^..ddeeff | tac); do
> git cherry-pick $hash;
> done

The last case is when you want to cherry-pick many commit, in this case the easier way is to branch that other branch, and then rebase it interactively to yours, so you remove those commits you don't want.

$ git checkout the_other_branch
$ git checkout -b a_new_one                # make a copy of that other branch
$ git rebase -i the_one_im_working_on      # to remove those commits you don't want
$ git branch -d the_one_im_working_on      # careful! this is a delete!
$ git checkout the_other_branch            # you can't rename the current, so go out
$ git branch -m a_new_one the_one_im_working_on   # the rename

Another way of working with git (more like a complementary way to branches) is presented at git-stash.

To push a branch means to send your local commits upstream

  • misc/git-doc.txt
  • Last modified: 2018/08/14 11:25
  • (external edit)