In our last episode, I confessed to making an unholy mess of a branch snarl by ignoring standard software process ‘Best Practices’, and running head-on into an especially concentrated cluster of all those things that make those Practices the Best ones.
But, hey, we’re using Git! Git is great! Git is all about branches! No worries, right?
Starting Simple – Rebase
So, I hear there’s a rebase command in Git, that allows you to “edit history” so it looks like what it should have looked like. Maybe that’s what I want? Let’s ask Google:
google: git rebase edit history
OK, loads of pages there. Peruse a few. Lots of info, lots of different perspectives. One common thread, though, that runs through them all:
Do not include any commit you have already pushed to a central server – it will mess other people up.
OK, that lets me out: my messy changes have been pushed, and pulled, and built upon, repushed, merged to other branches, folded, spindled, and mutilated. That’s the whole problem. So, let’s drop rebase.
More simplicities – cherry-pick
How about this: we leave the current, confused branch alone, and build up a new one to be what the original should have been. Git has a cherry-pick sub-command that applies one change to a branch. We just have to find the last moment when the branch was as desired, and roll forward from there cherry-picking only the desired changes.
git help cherry-pick
Hmm … four pages long. Hmmm …. third sentence gives me a few qualms:
When it is not obvious how to apply a change, the following happens:
But, let’s give it a go.
Since the exercise here is to select some changes and not others, I’m not going to be able to just tell cherry-pick to do them all at once: I need to figure out which commits are wanted. Figure there are really three kinds of commits:
- The ones I want: changes made explicitly to my branch, or to working branches off my branch (there’s some of that going on).
- Merges, in any direction (the merge itself isn’t cherry-pick material anyway: we’ll deal with the actual changes instead)
- Changes originally made to the delayed branch (and then merged into mine, or into a working branch off mine)
Now git log (from within a check-out of my branch) will tell me every commit that has contributed to my branch, so far so good.
At this point, I ran into a problem I was unable to solve. Note that git log tells you about each commit regardless of what branch the change was originally made to, regardless of how convoluted the path from original commit to my branch. Ordinarily, that’s a good thing, knowing the change itself regardless of the path. But in this case, the paths are important to me: in some cases, the only way I can identify whether I want the change is to know where it was first made (or to constantly bug the author for that info). I suspect git can tell me this. In fact, as you’ll see in subsequent chapters, the graphical tool gitk tells me this quite cleanly, and I have a strong suspicion that it’s merely wrapping command-line functions, or something darned close. But I couldn’t find how to do this from the command line, and furthermore my efforts to do that were digging me deeper and deeper into “learning opportunities” (that is, things I didn’t understand, like advanced Git Revision Expressions).
[Interesting story: at least at the time of this writing, Google can’t find any documentation on Git Revision Expressions. Very odd, since there’s so much good info on so many other git-topics. The best googlable reference is this Stack Overflow article, which points out that the answer is in GIT-REV-PARSE(1) (the man page, or git help page, for Git’s rev-parse command). Which is highly googlable. But you apparently have to know the answer before you’re allowed to ask the question. If you head down this path, I can recommend The Horse’s Mouth, and also a blog that, if nothing else, proves just how complicated all this stuff really is!]
Well, we could dig down that rat-hole for several more miles. But fortunately, we don’t have to. Click below to follow the next installments so I can show how you the Easy Way!