2

tl;dr: How can I keep the current last couple of commits on a branch, and replace the history before that with that of another branch?


I have a branch where I want to keep the existing last 3 commits but replace the history with that of another branch.

So I have:

        E-F-G   :: my-branch
       /
A-B-C-D   :: main
  \
   B'-C'-D'     :: new-past

and I want

A-B-C-D         :: main
 \
  B'-C'-D'      :: new-past
         \
          E-F-G :: my-branch

Currently I am doing this manually

git checkout new-past
git pull
git checkout -b my-branch-temp
git checkout cherry-pick E
git checkout cherry-pick F
git checkout cherry-pick G
git branch -D my-branch
git branch -m my-branch

So is there some opposite of cherry-pick where you can insert the past commit or something or some flag on merge or rebase that would make this more elegant?


PS- The case here is I am on a child branch of another branch that is getting regularly rebased and I'm trying to avoid having merge commits.

PPS- I'd just as soon script the existing process were there not frequent conflicts that need to be resolved

Sled
  • 18,541
  • 27
  • 119
  • 168
  • Protip: use tools like GitKraken or SourceTree to do this kind of rebasing/cherrypicking. – Dai Mar 30 '22 at 14:01
  • `git pull` <-- Why are you doing pulls? – Dai Mar 30 '22 at 14:01
  • @Dai just to make sure I have the latest version of the code – Sled Mar 30 '22 at 14:20
  • Consider doing a `git fetch` instead: that way you'll get the remote commits added to your local repo, but without git doing any automatic fast-forwarding or merging, that way you can update your branch refs when you're ready, with fewer headaches. – Dai Mar 30 '22 at 14:23
  • 4
    This sounds like a fairly straightforward case for `git rebase --onto`, for which there's a nice example in the [`git rebase`](https://git-scm.com/docs/git-rebase) documentation. Also, re: frequent conflicts, [`git rerere` can help](https://stackoverflow.com/a/49501436/20270) if you're fixing the same conflicts repeatedly. – Hasturkun Mar 30 '22 at 16:20
  • 1
    @Dai Using a Git GUI app is not "pro". – matt Mar 30 '22 at 17:38

2 Answers2

3

So is there some opposite of cherry-pick where you can insert the past commit

You have the right idea, but you are over thinking it. Instead of inserting past commits, you can create a new branch and cherry-pick the commits you want on top:

git checkout -b new-past new-branch
git cherry-pick E
git cherry-pick F
git cherry-pick G

From here, you can delete the old branch and rename the new one:

git branch -d my-branch
git branch -m new-branch my-branch

For a large number of commits, this is cumbersome and time consuming Fortunately, git provides a command called rebase which performs batch cherry picks. It looks like this:

git checkout my-branch
git rebase --onto new-past my-branch~3

Instead of my-branch-3, you can use any commit-ish, such as another branch, tag, or commit hash.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
1

Thanks to @Hasturkun for pointing me towards rebase --onto which led me to Git rebase --onto an overview & How change parent branch in git?

So for the example in the question the answer is:

git rebase --onto D' D my-branch
Sled
  • 18,541
  • 27
  • 119
  • 168