0

I'm someone who's always constructing checkins of only a portion of the differences in my worktree, so some of git's special features — notably git add -i -p and -e — are a real boon. But as useful and as powerful as add -i -p can be, I find myself wanting even more.

In a nutshell, I'm wondering if there's any way to cleanly and automatically exclude from the checkin any deltas which are already checked in under other branches. This need arises from at least two common-enough scenarios:

  • I've got some idiosyncratic or personal changes which I don't intend to check in to my project's main-line branches, because they'd be distracting and not useful to anyone else. I've probably checked them in to my own personal branch, but then cherry-picked them back into a branch I'm working on.

  • I'm working on a new feature, in a feature branch, but I need to test it along with some new code which a co-worker is simultaneously developing in his own feature branch. I can easily merge the co-worker's feature branch into mine, but when it comes time to check changes in to my feature branch, I want to check in only my feature's changes, not the co-worker's.

In either case, I could just use add -i -p, and say "no" to all the changes I don't want to check in. But that gets tiresome if, checkin after checkin and day after day, I'm saying "yes" to only a handful of actual, new changes, and exhaustively saying "no" to rafts of the same changes I said "no" to on the previous checkin, and the one before that, and the one before that.

So, in a little more detail, what I'm looking for is a decently clean and easy way to do something like git add -i -p, except that it automatically answers "no" to (and does not even show me) any patch hunk which is already exactly present on some other branch. I'd probably be fine with explicitly mentioning the name(s) of the other branch(es) whose changes I want to exclude. (Obviously there will occasionally be cases where nearby "old" and "new" changes get coalesced into a single hunk, which can't be automatically suppressed and which I'll therefore have to manually edit, and I'm fine with that.)

Does this make sense? Does anyone know of a good way to achieve this?

Steve Summit
  • 45,437
  • 7
  • 70
  • 103

1 Answers1

1

The short answer is "Git can't do that" (or perhaps, if you write your own commands, "Git can't do that yet "). See the answers to this similar, though not identical, question: Multiple staging areas. I recommend using git worktree add, perhaps in your case with detached-HEAD mode.

torek
  • 448,244
  • 59
  • 642
  • 775
  • Thanks. I was pretty sure there wasn't a way yet, but it's good to have it confirmed. It's interesting you should mention the "[multiple staging areas](https://stackoverflow.com/q/28947201/1256452)" thread, because like Thomas Jensen, I absolutely want that also. And I think have imagined a rather marvelous way to achieve both things, which this Stack Overflow comment box is unfortunately too narrow to contain. :-) – Steve Summit Sep 01 '22 at 12:22
  • I'm familiar with `git worktree` and use it regularly, but I'm not sure how it applies here. Just as in Thomas Jensen's question, the situation here is that there is a single worktree containing disparate changes to untangle and check in separately. So setting up a separate worktree to have made separate changes in runs rather afoul of Ryan Tomayko's indelible comment that "[moving from the present point B to some desired point C should not require a change in behavior at point A in the past.](https://tomayko.com/blog/2008/the-thing-about-git)". :-) – Steve Summit Sep 01 '22 at 13:33
  • Detached-HEAD is something I still haven't wrapped my head around. Interestingly enough, it also shows up in [the very same answer](https://stackoverflow.com/questions/3216360#17722977) which [my other git question](https://stackoverflow.com/questions/73560503) yesterday was about, and its usage there (once I think about it some more) might ratchet me one notch closer to understanding what detached-HEAD is actually for. – Steve Summit Sep 01 '22 at 13:47
  • I suppose the real, big-picture answer to this and Thomas Jensen's question may be to delve into ["patch management"](https://git.wiki.kernel.org/index.php/PatchManagement), including the theory of ["commuting patches"](http://darcs.net/Theory/MergersDocumentation) as implemented in darcs and camp. – Steve Summit Sep 01 '22 at 14:45
  • Yes, Git prefers to work with snapshots rather than patches. There's a duality here: given two snapshots we can derive a patch, and given one snapshot and a patch, we can find the other snapshot. But the two aren't the *same* in obvious ways: adding multiple patches sometimes "cancels stuff out", and when splitting one snapshot into N patches, you might need to *add information*. – torek Sep 02 '22 at 00:40
  • As for detached-HEAD mode: it simply removes the (somewhat inflexible / overly-rigid) binding between "branch name" and "tip commit", by the rather Gordian-knot-reducing method of eliminating the branch name entirely. This has some obvious drawbacks (as does slicing a knot with a sword: you can't re-tie it afterward). Note that each index corresponds to both a checkout *and* a tip commit, acting as a bridge between them. That's why moving a branch name unexpectedly is bad: one of the bridge supports isn't where you think. – torek Sep 02 '22 at 00:42