Reputation: 35301
With interactive rebase (git -i rebase ...
) one can edit commits anywhere in the current branch's lineage, thus "rewriting history".
A given commit, however, can belong to the lineages of multiple branches.
For example, suppose I have a repo with this branch structure:
A --- B --- C --- D --- F --- G branch_1*
\
`-- H --- I --- J branch_2
\
`-- K branch_3
If the active branch is branch_1
, and I use rebase -i
to edit commit B
, the resulting repo would look like this (at least until GC happens):
,-- b --- c --- d --- f --- g branch_1*
/
A --- B --- C --- D --- F --- G
\
`-- H --- I --- J branch_2
\
`-- K branch_3
Note that the original B
continues to be in the lineages of branch_2
and branch_1
. Repeating the process for each of these branches, as tedious as that would be, would result in multiple redundant commits, and the original branch structure would be lost:
,-- b --- c --- d --- f --- g branch_1
/
A --- B --- C --- D --- F --- G
| \
| `-- H --- I --- J
| \
| `-- K
|\
| `-- b' -- c' -- h --- i --- j branch_2*
\
`-- b'' - c'' - h' -- i' -- k branch_3*
Note that b
, b'
, and b''
are essentially equivalent commits. The same thing goes for c
, c'
, and c''
, h
and h'
, and i
and i'
.
Is there a halfway convenient way to achieve something like this:
A --- b --- c --- d --- f --- g branch_1*
\
`-- h --- i --- j branch_2
\
`-- k branch_3
...where the modification to the B
commit gets propagated through all the lineages it belongs to?
(I'd prefer a solution that also propagates the changes through to all the descendant stashes.)
Upvotes: 1
Views: 502
Reputation: 488013
... is there a halfway convenient way to achieve [a sensible result]
No.
There's one command, git filter-branch
, that can do it, but it's not halfway convenient, nor even 1/4th convenient. It's about 1000% inconvenient. :-)
The new git rebase --rebase-merges
machinery is pretty obviously adaptable to doing this sort of thing in a more convenient way,1 but it's not currently designed to rebase multiple branch names.
The new experimental git filter-repo
is capable enough to do what you want, and probably less inconvenient than git filter-branch
, but it's still swatting bugs with nuclear weapons—in this case, maybe a moderately large bug, not just a fly, but still serious overkill.
(I once wrote my own experimental thing to do this sort of rebase, but I never finished it. It did what I needed it to, when I needed it. It worked using the equivalent of repeated git rebase --onto
operations and had a lot of corner cases.)
1The key is to be able to label particular commits, so that after rebase copies them, you can pair up the <old, new> hash-ID pairs, and otherwise jump around the graph structure from one chain to another as the rebase progresses. The old --preserve-merges
code could not do that; the new --rebase-merges
code can. Once you have these pieces in place, rebasing multiple branches "simultaneously" is just a matter of saving multiple branch names to force-adjust after the rebase completes. You then have the rebase list the correct commits and jump-points. The main bulk of the rebase operation consists of copying those commits. Last, using the old-to-new mapping, rebase can adjust each branch name, then reconnect HEAD
to the one you want.
The remaining user-interface level problem lies in selecting the correct set of branch names to multi-rebase.
Upvotes: 3
Reputation: 2095
As you say, if you rebase branch_1
, changing B
, you will get:
,-- b --- c --- d --- f --- g branch_1*
/
A --- B --- C --- D --- F --- G
\
`-- H --- I --- J branch_2
\
`-- K branch_3
You can then rebase branch_2
onto c
with:
git rebase --onto c C
yielding:
,-- b --- c --- d --- f --- g branch_1*
/ \
| `-- h --- i --- j branch_2
|
A --- B --- C --- D --- F --- G
\
`-- H --- I --- J
\
`-- K branch_3
and then rebase branch_3
onto i
:
git rebase --onto i I
yielding:
,-- b --- c --- d --- f --- g branch_1*
/ \
| `-- h --- i --- j branch_2
| \
| `-- j branch_3
|
A --- B --- C --- D --- F --- G
\
`-- H --- I --- J
\
`-- K
which will at least mirror your original branch structure.
Upvotes: 1