On 2 May 2012, Slávek Banko told this:
With Git I still do not know how much. But I was in CVS can be tagged branch, in which the patches can grow independently of the main branch. I suppose it is possible also in the GIT. And so - to separate branch - I thought the inclusion of patches for 3.5.13.1 (or how to be named).
All branches in git have this property: in fact every single commit has this property, since all a branch is is a name (git parlance: a reference, or 'ref') pointing to a commit which can move forward to point at it's child if you hang a new commit off it. (CVS's branches are, well, I'm not sure there *is* a conceptual model for them other than 'we tried to make per-file RCS branching into something per-repository and it nearly worked', which isn't much of a model.)
Even better for patch tracking is 'git rebase', because it solves a perennial problem trying to use branches to track changes that apply to one release when the next one comes out. Say you have a tree with a release, and you have a branch with patches based on that that you applied:
- A - release 1.0 - B - C - D (trunk) \ -- patch -- patch -- patch (patch-branch)
Now a release 2.0 comes out... but you don't want to throw all those patches away, or run around reapplying them and damaging the history. So your tree currently looks like this:
- A - release 1.0 - B - C - D - release 2.0 (trunk) \ -- patch -- patch -- patch (patch-branch)
In this situation,
git rebase trunk patch-branch
will rewrite the patch-branch so it depends on the head of 'trunk' (if you want to rebase on some earlier commit in 'trunk', you can make a temporary branch at the appropriate point in 'trunk' and rebase off that).
This converts the history to look like this:
- A - release 1.0 - B - C - D - release 2.0 (trunk) \ -- patch -- patch -- patch (patch-branch)
If git finds conflicts while doing this -- patches that applied to release 1.0 that no longer applied to release 2.0 for some reason other than their being applied to upstream -- it'll stop you halfway, with all patches up to the conflicting patch applied and the conflicting one in a merge-conflict state, and let you fix the problem, resolve the merge conflict as usual (hack the files shown as conflicting by 'git status', 'git add' and 'git commit'), then 'git rebase --continue' or 'git rebase --abort' if you want to give up).
But note that while this is often thought of as changing the history of the patch-branch, it really isn't. Commits in git are pretty much immutable[1], so what it actually does is creates a *new* patch-branch with rewritten commits on it derived from the commits on the old branch, and gives it the same name as the old branch had. The old branch no longer has a name, but is still visible in e.g. 'git log -g' until garbage-collected in a few weeks time. (The existence of commands like this that can generate whole branches'-worth of garbage at once is one reason why garbage collection is so important in git's design, though it happens so automatically these days that you can mostly ignore it.)
Big caveat here, though: if anyone else was doing work on the tip of the patch-branch and you push your rewritten branch, all their work is gone unless they take special and annoying measures to preserve it -- and indeed git warns you of this by forcing you to push with 'git push -f' to emphasise to you that you might be about to spoil someone's day. So in general either one never rebases public branches, or one advertises that 'this branch is regularly rebased' and people take care not to base work on it directly. (Git's own 'pu' branch, and the linux-next tree, are examples of the latter).
One thing you *can* do if you want to rebase a branch full of changes against release 1.0 to changes against release 2.0 without messing up other people is
git branch patch-branch-2 patch-branch git rebase trunk patch-branch-2
and now the branch that got rebased (the patch branch for release 2.0) has a new name, and the old branch still exists, the same as ever; so the newly-named patch-branch-2 can be pushed without any worry about messing people up who happen to be playing with the patches against release 1.0 on the original patch-branch.
I also commend to you 'git rebase -i', which is a simply stunning way of reshuffling, merging, fixing up and magically manipulating commits before pushing them. Again, to play with this stuff on a branch, make a new branch out of it and play on that: the old branch will be quite safe from your history-defiling experiments.
Most of this stuff is thoroughly git-specific magic. I know of no other version control system that has anything really like 'git rebase': Mercurial is trying but has a long way to go to catch up. (I'd say that Mercurial's advantage these days lies in a much nicer little language for selecting changes to do things to, beside which git's looks rather like white noise.)
[1] 'pretty much' because if someone breaks SHA-1's security badly enough, they'll not be immutable anymore