2

I want to rebase and checkout a branch onto the current branch without checking it out first. This saves time checkout out an old repository state and recompiling the files it touches.

For example, I have this:

A -> B -> C (HEAD -> main)
 \
  D -> E (old)

I want the following. Basically checking out old and rebasing on top of main.

A -> B -> C (main) -> D -> E (HEAD -> old)

I would normally run:

git checkout old
git rebase main

The problem is I was working on the old branch months ago. Checking it out will touch many files. The repository is huge and I'll need to spend hours recompiling if I do that. What I really want to do is the following:

# Don't update 'main'
git checkout --detach

# Automatically cherry-picks commits after the common ancestor,
# just like a 'rebase' from that branch would do.
git cherry-pick main..old

# Update the branch ref
git branch -f old HEAD

# Check out the "rebased" branch
git checkout old

Is there a shorter way of doing this?

jozxyqk
  • 16,424
  • 12
  • 91
  • 180
  • Arguably, the `git rebase main old` form of the command *should* work the way you want. In fact, it used to literally run `git checkout old; git rebase main`, i.e., the way you *don't* want. Since the rewrite in C, some aspects of `git rebase` are improved and it's *possible* it works the way you want now, but I wouldn't assume this. (I also don't like the fact that `git rebase U B` leaves you on branch B even if you are on branch C when you start: it should leave you on branch C. So I always recommend against this form of rebase anyway.) – torek Jan 11 '22 at 05:10
  • Note that the above is not an answer: it's a comment on how bad `git rebase` used to be. :-) (Also, I like your profile, but I note it's py2k-specific. And: is your user name the word Cat used in the Scrabble game in Red Dwarf?) – torek Jan 11 '22 at 05:11
  • @torek I had a read through the [rebase docs](https://git-scm.com/docs/git-rebase). Some arguments sounded like what I wanted but then gave a different result - probably what you're describing. Maybe there's still a way. (You know the reference! Great show :-)) – jozxyqk Jan 11 '22 at 07:28
  • I had (I think I lost it) a key ring that had a picture of the space bug and a label: "My other spaceship is the Red Dwarf". (I bought a magazine about the show primarily for the key ring...) – torek Jan 11 '22 at 09:14

1 Answers1

1

This just combines the commands in the question into a macro:

git config --global alias.checkoutrebase '!git checkout --detach && git cherry-pick HEAD..$1 && git branch -f $1 HEAD && git checkout $1 && :'

Bash completion (add to ~/.bashrc): __git_complete checkoutrebase _git_checkout

Usage:

# Rebase another_branch onto the current HEAD and check it out
git checkoutrebase another_branch

It will break if another_branch is not actually a branch but another kind of reference.

Testing:

# Setup
git init --initial-branch=main
touch one two
git add one two
git commit -am A
echo D > two ; git commit -am D
echo E > two ; git commit -am E
git branch old
git reset --hard HEAD~2
echo B > one ; git commit -am B
echo C > one ; git commit -am C
# State before
git log --all --graph --oneline
* 203b3f2 (HEAD -> main) C
* ee8761e B
| * aaf8ea8 (old) E
| * 0e592b1 D
|/  
* fede4c2 A

# Run the above alias
git checkoutrebase old
HEAD is now at 203b3f2 C
[detached HEAD 11bca25] D
 Date: Mon Jan 10 16:47:13 2022 -0800
 1 file changed, 1 insertion(+)
[detached HEAD 7e22429] E
 Date: Mon Jan 10 16:47:17 2022 -0800
 1 file changed, 1 insertion(+), 1 deletion(-)
Switched to branch 'old'

# State after
git log --all --graph --oneline
* 7e22429 (HEAD -> old) E
* 11bca25 D
* 203b3f2 (main) C
* ee8761e B
* fede4c2 A
jozxyqk
  • 16,424
  • 12
  • 91
  • 180