mcwayliffe
mcwayliffe

Reputation: 436

Safe way to 'reshape' a branch's history

Often, when using git, I will make the mistake of rebasing or merging something that I didn't really want. For example, say I have three commits that I initially don't want to show in the history, and one that I do, like A-B-C-D, where D is the commit that I want. So I run

git rebase -i HEAD~4

and I squash A, B, and C. But then, later, I decide that I actually wanted to have two commits, because A was totally unrelated to the other three and the history would make more sense if it were on its own. What I would do now is,

git reflog | grep 'rebase -i' 

which would spit out some list that ends with

<someHash> HEAD@{<num>}: rebase -i (start): checkout HEAD~4

and I would then run

git checkout HEAD@{<num>+1}
git br -D <branchIWasWorkingOn>
git checkout -b <branchIWasWorkingOn>
git rebase -i HEAD~4

and do exactly the same thing I did before, but picking commit A too this time. This is really cumbersome, and requires deleting branches, which makes me nervous that this workflow isn't particularly safe. My question is, is there a more secure way to rewrite history than this reflog & branch deletion method?

Upvotes: 4

Views: 105

Answers (1)

Ryan Poolos
Ryan Poolos

Reputation: 18561

My favorite way to split commits if necessary is to simply git reset --soft HEAD~1 which will bring all the changes of the last commit, in your case 4 merged commits, to the staging area. From there you can recommit them as you see fit. So the basic flow would be having commits like such A-B-C-Dwhere D is multiple commits you'd like to break up. run git reset --soft HEAD~1 and you'll have A-B-C with D's changes in the staging area. Commit as many separate times as you'd like say two, and you'd have A-B-C-E-F.

Now thats great if the commit is at the top of your HEAD. But if you need to go back several commits, you'll still need to create a branch, git reset --hard HEAD~n to remove extra commits (don't worry they're safe on the other branch). Then run the git reset --soft HEAD~1. Once you've recommitted whatever you'd like, you can rebase your original branch off this branch to get to where you'd like to be.

I can't say its much cleaner than your method, might be a bit easier. For me its at least easier to visualize whats happening. That being said, if you're rewriting history, its going to be a bit messy. Just be sure you take your time and are mindful of whats getting deleted when.

Also, as a nice side note, turns out even rebasing commits out of the branch doesn't make them go away. Git caches everything. So I'd deleted a commit I shouldn't have before, but because I knew the commit hash by scrolling up in terminal, I was able to cherry-pick it back into existence. So not all is lost when you delete something.

Upvotes: 3

Related Questions