There are probably many ways. But this one looks pretty simple and takes seconds.

git add . && git commit -m "backup-$(date +%Y%m%d-%H%M)" && git reset HEAD^

After this command, nothing is changed in working tree or in branch history. But reflog gets a reference to the current tree content, which could be extracted (git help reflog) if you suddenly realize that you’ve messed things up.

Con’s: depends on proper .gitignore to avoid garbage in repository; can’t be used if there is something valuable in the staging area; reflog has limited lifetime, decreased even more by large rebases

 

If anyone is interested …

This blog is hosted on my home server, connected via ADSL link to MTS (formerly Stream) ISP. Unfortunately ISP blocks incoming connections on 80 and 8080 ports, so I have to use non-standard port 8079. IP address is dynamic, and yoush.homelinux.org is a DynDNS name.

Server naturally runs Debian GNU/Linux. However, WordPress engine is installed not from a debian package. This is done because IMO it is not practical to package all plugins and themes, and it is not acceptable to mix packaged and unpackaged components within same directory tree.

WordPress installation is managed via git. There are two repositories – production repository at /srv/wordpress from where it is served by the web server, and development one elsewhere. Web server has readonly access to /srv/wordpress – so nothing can be modified from outside (and also from WordPress administrative interface – which is IMO not that large cost for consistency and extended security).

In development repository, there are 3 branches – wordpress, upstream and site.

  • wordpress branch is used to import unmodified versions of WordPress engine. To import a new version, development repository is switched to wordpress branch, then entire file tree is removed, then new tree is unpacked, then the change is committed.
  • upstream branch is used to import (or remove) unmodified plugins and themes; also it gets merges from wordpress branch. To upgrade a plugin, development repository is switched to upstream branch, then old version is removed from wp-content/plugins/ directory, then archive with new version is unpackaged, then change is committed.
  • site branch gets merges from upstream branch, and holds any local modifications needed. All changes for the site are done in this branch, and then pushed into production repository.

In case of something goes wrong, older commit could be checked out on the production repository – I’ve already done this several times.

Graphics and other files that are needed for my blog, are not imported into WordPress at all, but served as static content from a directory on the server.

 

OpenEmbedded is a mighty build system, however it’s documentation is such poor that it is often a challenge to make simple thing working.

Today I spent several hours trying to find out how to make it to take package sources from a local git repository. Problem was that it tried to download an archive over http instead.

Here is a snippet from recipe that works.

# Need these two lines to stop OE's attempts to fetch local git repo
# from http mirror
CVS_TARBALL_STASH = ""
SRC_TARBALL_STASH = ""

SRC_URI = "git:///path/to/local/repo;protocol=file;branch=master"
SRCREV = "${AUTOREV}"
S = "${WORKDIR}/git"
Sep 042009
 

Sometimes it is useful to have local branches following all branches in a remote repository. For example, if building debian packages from git repositories fetched from git.debian.org using git-buildpackage, one normally needs master, debian and pristine-tar branches.

To update each of those, one has to run

git fetch remotename

and then for each branch run

git checkout branchname
git merge remotename/branchname

Here is a helpful script to do all that automatically. Just ensure that your working directory is clean, and run

git-update-from remotename

and you get all local branches updated (and new ones created if new branches appear on the remote server).

 

I’ve mentioned git add --patch recently.

I’ve used it for some time, and found that it is even more cool than I thought. Not only it allows to select particular file changes to add into commit (while not adding other changes in the same file). It also allows to edit those changes in-place!

Say, you added some debugging code. You want to keep it, but not enabled by default, so you made it #ifdef-ed. And ant the top of your file, you added something like

/* Define this to get debug messages */
#define EXTRA_DEBUG_MESSAGES

You have this in your working directory, but in the commit that adds it, you want #undef instead of #define. Because addition of extra debugging messages is a single logical change that should become a commit, while enabling/disabling those is somewhat that you do in your working directory, and that has zero reasons to be stored in project’s history.

And git add --patch allows exactly that! When it asks what to do with a particular hunk, one of your choices is “edit”. If you choose that, a editor is fired up containing the hunk in diff -u format. Not all edits are safe, but lines marked as + may be changed or deleted. If you delete a line, you don’t need to change the top line containing line numbers – just leave it untouched, git add --patch will do the magic. If you do an unsave change, git add --patch will inform you and give you a chance to recover.

So you can change #define to #undef, or fix a just-noticed typo, or choose not to add something into this commit.

With such a tool available, is there any single reason left not to follow “commit per logical change” policy?

Feb 012009
 

There are some masochists around still using subversion. If you have to deal with their work somehow, your must-use tool is git-svn. This is a bidirecteral gateway between git and svn – it allows you to fetch entire svn repositories into your git repositories, then enjoy working with git, and later push your changes back to original svn repositories if needed.

Although there is some fine documentation on using git-svn, I still think the below tips may be useful for someone who just needs to set up import, and then forget that svn exists. Like in a common debian-packaging case.

The below example presents details on importing eina component of enlightenment svn repository into debian pkg-e team’s git repositoriy at alioth.debian.org.

Doing initial import

Better to do initial import into a local git repository, and not directly to repository on server, to avoid breakages if things go wrong.

  • Cd to the local repo directory (either an empty repo created by git init, or to repo that already contains previous packaging work).
  • If repo is a bare repo (i.e. git data is in the repo directory itself,
    not in .git/), set GIT_DIR environment variable to point to the repo directory. Without this hint, git-svn can’t work with bare repos.
  • Initialize git-svn:
    git svn init --trunk=trunk/eina http://svn.enlightenment.org/svn/e

    The git-svn init command line tells git-svn where svn repository is, and what part of it should be fetched. Documentation has some details.

  • By default, git-svn does not prefix remote git branches that it creates with svn/, which is ugly, especially when you have other (non-svn) remote repos tracked in your local repo. Better to fix that before initial import. To do that, change the value of git config svn-remote.svn.fetch:
    $ git config svn-remote.svn.fetch
    trunk/eina:refs/remotes/trunk
    $ git config svn-remote.svn.fetch trunk/eina:refs/remotes/svn/trunk
    $ git config svn-remote.svn.fetch
    trunk/eina:refs/remotes/svn/trunk

    You may edit .git/config file directly as well.

  • Do the import:
    git svn fetch

    First run of this command may be extremely slow (several hours, even days on slow connection) and traffic-hungry, since it will fetch entire svn history. Later updates will be fast.

Once these steps are completed, you have entire svn history in your git repo, so you may browse it using gitk, branch from whatever point, or push it to another git repo. More on this below.

To fetch svn updates into your repo, just run git svn fetch periodically.

Moving git-svn import to another repo

Once svn import is done into your local repo, svn/* branches may be pushed to another repo in the same way as any other git branches.

However, to make git-svn working on remote repo (without redoing time- and traffic-consuming initial import there), two additional steps are required.

Before pushing, login into remote server, cd to the repo there and/or set GIT_DIR environment variable, and initialize git-svn using exactly same git-svn init command line as you did on your initial import. Also do exactly same svn-remote.svn.fetch adjustment.

Then do the push:

git push ssh://alioth.debian.org/git/pkg-e/libs/eina.git refs/remotes/svn/*:refs/remotes/svn/*

In your setup, remote repository location will be likely different, but refspec should be the same.

Once import completed, login into server, cd to the repo there and/or set GIT_DIR environment variable, and run git svn fetch once, to make it rebuild it’s metadata. Git-svn stores needed info inside log messages of the imported commits, so metadata rebuild is a local operation and runs fast.

Now git-svn may be used on the remote server.

Warning: git-svn does not like when it’s branches are updated by other git commands. So don’t mix updates of those branches with git fetch and with git svn fetch – choose one of these two and use only that. If you have ocasionally updated svn/* branch from remote git repo with git fetch, you may restore git-svn functionality by removing git-svn metadata (stored in hidden files in branch directories under .git/svn/) and running git svn fetch to restore it. If that does not help, it is possible to remove all tracks of git-svn from local repo (.git/svn directory and svn-related sections in .git/config), and then move things from remote repo to local repo, exactly as described above, but in the reverse direction. Git is smart enough not to copy objects that are already in your repo, so this is even faster than you could think :) .

Setting up auto-import

Once git-svn import is on server, it is easy to set up auto-import, such that server will have a (non-remote) git branch that follows svn trunk.

We do it by having an hourly cron job on server, that runs something like

export GIT_DIR=/git/pkg-e/libs/eina.git
git svn fetch
if ! git push $GIT_DIR refs/remotes/svn/trunk:upstream-vcs; then
  git branch -D upstream-vcs
  git branch upstream-vcs svn/trunk
fi

Normally, it just fetches updates from svn, and fast-forwards local upstream-vcs branch with the fresh fetch. But if fast-forward fails (which may happen if someone occasionally changes upstream-vcs branch), then branch is deleted and re-created at current svn/trunk point. (This “rude way” is only executed in problem case, not always, to avoid having a window when upstream-vcs branch does not exist.)

Once this thing is set up, we no longer care that upstream is using svn. We have all their updates in our git. And that is cool.

Jan 202009
 

Are you aware of git add --patch? If not yet, here is a must-read article.

As a side note, adding gitready.com to your feed reader could be a good idea.

© 2011 yoush.homelinux.org Suffusion theme by Sayontan Sinha