You can't get what you've drawn, because you drew in commit hash IDs: f8114a
for instance. Given that f8114a
is drawn as a root commit, this means that f8114a
is always a root commit, in the past, present, and forever in the future too. But in the right hand side of the drawing, f8114a
is not a root commit: it has a parent d0ece
. So you've claimed that f8114a
is both a root commit (no parents) and a regular everyday commit (one parent, d0ece
), and this is simply not possible.
You may be able to get what you want. This depends on precisely what it is that you do want. Trying to do this with git rebase
is usually a bad idea, though: if there are any branch-and-merge operations in the set of commits you're trying to graft onto one of your branches, rebase itself will have to re-perform any of the merges involved, and that's a recipe for breaking stuff.
Now, remember that any commit, whatever its hash ID might be, and whatever parent hash IDs it might have, represents a full and complete snapshot of the files that are contained inside that commit. So commit f8114a
is a snapshot. Since it it has no parent (on the left side), Git will show it as a comparison against a pseudo-commit that has no files.1 So f8114a
consists of add all of its files, when viewed as a set of changes.
If you take f8114a
and copy it to a new-and-¿improved? commit—let's call this f9114a
, although the actual hash ID will probably be different, but we need to have something to call it2—that does have a parent commit, though, now git show
and other Git operations that compare the copy against its parent will have a snapshot to compare against. So now, instead of add all of these files, the diff may say delete most of the files, and create these mostly new ones instead, then change a whole lot of a few remaining files.
If that's OK with you, it's easy to get this to happen in your own repository, without having it happen in any clones anyone makes of your repository. Just use git replace
with the --graft
option. See the git replace
documentation for details.
Once you're satisfied with some replacement(s), you can use a no-op git filter-repo
(or the old but still supported, and included with Git distributions, git filter-branch
) to rewrite commits reachable from the tip of imported-branch
. This will "cement the replacement in place" and allow you to discard the graft; cloning this filtered repository will produce a copy of the filtered repository, which no longer uses the replacement trick.
1Technically Git uses the empty tree to fake up this pseudo-commit. It diffs your commit's tree against the empty tree to produce all the "add entire file" diff-hunks.
2Call it Fred or Barney or Wilma if you like; just don't call it late for dinner.