View source for Hints on using GIT and stgit
From Openmoko
You do not have permission to edit this page, for the following reasons:
You can view and copy the source of this page:
Template used on this page:
Return to Hints on using GIT and stgit.
You do not have permission to edit this page, for the following reasons:
You can view and copy the source of this page:
Template used on this page:
Return to Hints on using GIT and stgit.
Linus Torvalds invented git and uses it heavily in Linux development, most people would take that as an impressive suggestion it might be useful in kernel and similar development work.
Your stgit patch stack appears in your local git repo in a synchronized way, without explicit commits -- as you add, edit and remove patches in stgit your git repo is making the same moves, without losing the patch stack.
When you use the two together, you have a fast and flexible system for dealing with many branches of large source trees, rebasing them in a controlled way, and generating and managing patches to export elsewhere.
You just need to install the git and stgit packages for your distribution. There are GUI tools like qgit that can be helpful to navigate projects that you can install too.
You can optionally edit your ~/.bashrc to define some environment variables to control your commit identity for git
The git init command should have created a default .gitignore file at the top level directory of your project -- you can edit this to ensure that any generated files other than the default *.o and so on are ignored by git if you need to, normally the default ones are enough.
If you want to work on a tree that already existed in a remote repo, the first move is to clone it. This is different than "checking it out", when you clone it you are not just getting HEAD but *all revisions* of the project. (If the remote repo lost everything about that project tomorrow, what you cloned would be a full replacement for what it had.)
What you end up there is a local branch fix-andys-bugs which has no patch stack, but is at exactly the state of origin/andy. So when you add local patches, they are against current origin/andy.
Don't forget to tarball up your project directory before doing an experiment with git and stgit, until you are used to it. The tarball will fully capture and restore the project and git / stgit state, so you can try things without worrying about how to "hit undo".
Using stgit is a great deal like using quilt.
If you experience a genuine merge problem during an stg push for example, stgit will tell you about which source file had the problem, and where it put a copy of the merge diff. When you cleared the problem, you must run
stg resolved <filepath>
to tell stgit that you have resolved the merge problem in <filepath>. Then you will be able to do
stg refresh
to capture the changes under that patch and go on about your business.
Exporting patches is super easy
stg export
will very rapidly export your whole patch stack in a directory ./patches-<branch> and create a series file in there as well. If you append a patch name to stg export, it just exports that one to the same directory.
You can import individual patches with
stg import <path to patch>
or a whole series at a time by pointing it to the series
stg import -i -s <path to series file>
The patches are imported to be above the current applied patch top, which doesn't have to be the top of your patch series.
BUT stgit is picky about patch formatting on import.
Typically you are importing external patches once, but if you need to accept patches on a continuing basis you should export any patches that caused trouble from stgit once they are imported, and provide these versions back to where your imported patches came from so that ongoing patch updates will go in without difficulty next time. Most times you are in fact removing fuzz from the patches by doing this.
Sometimes you see there is a problem in a source file you need to fix, but you want to make sure the fix goes in the right patch and you don't know which is the right one.
stg patches <file> will list all the patches in the current branch patch stack that modfied <file>. You can then use stg goto <patch name> to move to that patch in the patch stack and make the edit in that context.
You can make hierarchies of branched versions in git/stgit really easily with minimal disturbance. The main thing you have to watch is that your "current working directory" as it were, the current branch you are in, is the one you think it is. You can check that with
You can move to an existing stgit-initialized branch with
The branching stuff initially sounds like it can be a can of worms, because once you made these easy, cheap branches, what do you do when the thing you based it on gets new patches and commits? Your stuff is still based on the parent's version at the time you branched it, right? Isn't it just a big mess?
It's true that your branch will stay at the parent's version at the time it was branched, even if new commits come into the parent branch -- until you rebase it. Git and stgit together make rebasing almost as easy as spawning the new branch. Let's say we had the default "master" branch and we made a new branch from it
Then we did lots of work on newbranch
But then we decided we needed to update master (in this example master pulls from a remote repo to get updates) perhaps to get a bugfix
and we wanted those updates on newbranch too. Easy (we are in newbranch again remember)
So we are able to update master and reset newbranch to start from the new master HEAD without disturbing the patch series associated with newbranch, except we have to push them back on and deal with any failures to merge due to conflicting edits in the new patches... but that's what we have to do anyway, and we can do it inside the patch stack system.
The kernel trees in git currently use branches in a structured way to allow staged rebasing.
This allows master to be pulled from kernel.org or otherwise updated when needed, separately the moko patchset can be updated when needed and lastly the working branches can be rebased as described above when needed
stgit has a very tight coupling to git commits -- when you stg pop a patch the patch is undone on the files and the commit history for the patch is erased, not reverted. This works great for local use, since the patch stack retains the information needed to bring the patch back with stg push again and you didn't care about tracking your history of pushing and popping patches from the stack since you do it all the time randomly. The git 'history' in the local case is just reflecting the currently applied patchset rather than any actual 'history'.
The problems start when another repo, say a public repo you push to, or pull from, will have its own commit history for that project. If you clone the remote repo locally and then use stgit directly on the branches, say to stg uncommit and then stg delete a patch, your git history for that branch is no longer an unbroken thread in agreement with the origin: the uncommit snipped a bit of the history off on your version. You won't be able to push any more to the other repo: git will give you an error.
The only way to maintain a consistent public history for people to work with is to never erase history with stgit on those shared branches. It means that you have to work on a temporary branch and export the patches, importing them into your stable branch in a single action without using stgit... but if you have to remove a patch that was committed to the stable branch, use git revert to issue an anti-patch.
The other way to deal with this is to accept that the public repo isn't there to maintain a project history but to make public your branch in a "snapshot" kind of mode.
You do this by pushing your local branch using this syntax:
git push ssh://git@git.openmoko.org/<projectname> +<remote-branch-name>:<local-branch-name>;
...this will overwrite <remote-branch-name> with the contents of <local-branch-name>. So when you want to expose a snapshot of your branch state on the public repo, you run the line above to force the remote branch into sync with yours.
#!/bin/sh NAME="Britney Spears" EMAIL="britney@spears" if [ -z "$1" ] ; then echo "Usage: $0 patch-name.patch" exit 1 fi PATCHNAME=$1 stg new --author "$NAME <$EMAIL>" --commname="$NAME" --commemail="$EMAIL" --sign --message="$PATCHNAME" $PATCHNAME
#!/bin/sh PATCH=$1 echo `pwd` if [ -z "$1" ] ; then stg refresh PATCH=`stg top` echo "*** checking top patch $PATCH" fi while [ ! -f ./scripts/checkpatch.pl ]; do cd .. echo looking for checkpatch.pl, cd `pwd` done if [ -f ./scripts/checkpatch.pl ]; then stg export $PATCH && \ ./scripts/checkpatch.pl -strict patches-`stg branch`/$PATCH else echo "./scripts/checkpatch.pl not found." echo "Please cd to the kernel tree!" fi
Send a patch using a gmail account. You will find a way to make this work for you with another provider.
OPT= #TO=linux-kernel@vger.kernel.org # mainline! #TO=openmoko-kernel@lists.openmoko.org # OM people TO=new_kernel_hacker@gmail.com # Send these first for yourself and check! #TODO: I am paranoid enough to care about my pass being in freed RAM :-/ Is this OK? echo "pass:" read -s PASS #OPT=-e # Edit first message OPT=-E # Edit each patch before sending it, do not get used to this. GMAIL_USER_NAME=new_kernel_hacker stg mail $OPT -a --to $TO --smtp-server smtp.gmail.com:587 -u $GMAIL_USER_NAME -p $PASS -T $OPT