DEV Community

Rewrite your git history in 4 friendly commands

Salma Alam-Naylor on September 06, 2022

I build a lot of public experimental demo repos to support my tutorials, and I often encourage people to fork them and deploy them to Netlify to tr...
Collapse
 
jmfayard profile image
Jean-Michel πŸ•΅πŸ»β€β™‚οΈ Fayard • Edited

Souvenir souvenir, this was my first article on this website actually :) dev.to/jmfayard/pull-requests-a-si...

git reset --soft is still my go-to solution, there is so much less opportunity to shoot yourself in the foot than git rebase --shit (not an actual git flag).

In practice, I almost always do that against origin/main to clean up the pull request

In this case, the complete workflow would be this:

git fetch
git merge origin/main

# if conflicts
echo "resolve conflicts in your IDE"
git commit -a -m "resolve conflicts"
# end if

git reset --soft origin/main
git commit -a -m "my commit message"
git push --force
Enter fullscreen mode Exit fullscreen mode

That's it, the PR contains only one commit my commit message and the workflow is pretty much idiot proof.

Collapse
 
whitep4nth3r profile image
Salma Alam-Naylor

Oh, nice!

I’m getting a lot of people all over the place say β€œwhy not rebase?” πŸ˜… and the fact of the matter is this method is less scary and much more suited to my usual use cases. As you say, you’re much less likely to shoot yourself in the foot β€” meaning you won’t end up on a weird state of β€œin an interactive rebase and not know how to get out if you make a mistake”.

Collapse
 
jmfayard profile image
Jean-Michel πŸ•΅πŸ»β€β™‚οΈ Fayard • Edited

It's a difference in mindset.

Some people like powerful tools like can do everything. If something go wrong they will read the reference docs and the best practices and make sure they get it right the next time.

For me the most important feature is simplicity, which for practical purpose I would define as focusing on choosing good enough solutions that minimize the probability that things could go wrong.

The first set will always prefer git rebase and the second git reset --soft

Thread Thread
 
whitep4nth3r profile image
Salma Alam-Naylor

Absolutely! Well said!

Collapse
 
darkwiiplayer profile image
π’ŽWii πŸ³οΈβ€βš§οΈ

This seems excessively complicated; you can just do git rebase --interactive <last good commit> and git will give you a nice description of all the things you can do, like rewording a commit message, merging two commits together, etc. You can even move commits around to put a commit fixing a bug right after the one that introduced it and have them be merged.

Collapse
 
veefu profile image
Vincent Drake • Edited

excessively complicated

It is four commands, vs your single command. Those four commands, though, leave very little margin for error, whereas an interactive rebase is a minefield. There are ways to go wrong when re-ordering commits that can result in cascading merge conflicts, confusion, and frustration.

This is a nice shorthand for squashing everything into a single commit if you're not quite ready to learn interactive rebase.

Collapse
 
whitep4nth3r profile image
Salma Alam-Naylor

Much appreciated Vincent!

Collapse
 
darkwiiplayer profile image
π’ŽWii πŸ³οΈβ€βš§οΈ • Edited

Interactive rebase literally tells you what to do and if all you do is squash commits, there is nothing to shoot yourself in the foot with. This is a complete misrepresentation.

Put even more simply, rebase is 1 command that holds your hand the whole time, it doesn't get more fool-proof than that.

Thread Thread
 
veefu profile image
Vincent Drake • Edited

I don't know what tools you use to interact with rebase. Perhaps they're more beginner friendly than my first experience, where an editor containing a script that would be run by git appeared. The hand-holding was minimal.

As for minefield, create a series of commits where each commit depends on changes introduced in the one prior.

Now try moving the last commit first. As git replays each of the commits, it will raise a merge conflict, as the diff will not apply cleanly to the code. The interactive rebase drops you to a command shell where you must merge and continue. This will happen, though, on every subsequent commit, dropping you back to shell every time.

This is not a misrepresentation, it is my first-hand experience learning the tools. You may be an expert, but you have zero authority over others' actual experiences.

/Edit

Excuse me, it looks like I missed your craftily placed qualification:

if all you do is squash commits

The fact that you have many other options when performing an interactive rebase proves that it is less simple than the 4 commands by OP. No matter how hand-holdy your tools are, the tools don't know you need to squash all commits. They won't tell you to squash all. Again, there is much more margin for error in an interactive rebase.

Thread Thread
 
darkwiiplayer profile image
π’ŽWii πŸ³οΈβ€βš§οΈ

an editor containing a script that would be run by git appeared

Yep. That's what I was talking about. It comes with instructions and all you need to do is make your changes, save and close. It doesn't get simpler than that.

Thread Thread
 
whitep4nth3r profile image
Salma Alam-Naylor

This is EXACTLY my experience and why I wrote this article. Thank you for explaining it brilliantly!

Collapse
 
whitep4nth3r profile image
Salma Alam-Naylor

I'm getting a lot of "why not use rebase?" πŸ˜… Rebase is a tricky concept for beginners, and it's got me in a mess before in large organisations and when I was less experienced. I'm not saying this is the only way, it's just a way.

To me, this isn't excessively complicated because you're not likely to end up in a situation that you can't escape on the command line if you don't know what you're doing. Moving commits round is a scary concept for people just starting out. Even me now, with many years of experience.

Collapse
 
darkwiiplayer profile image
π’ŽWii πŸ³οΈβ€βš§οΈ

because you're not likely to end up in a situation that you can't escape on the command line if you don't know what you're doing.

Git is really forgiving in this regard though; interactive rebase gives you an on-screen explanation of all the things you can do, and git status always includes hints about what you're doing and how you can cancel it (usually just the command that started it with --abort)

Thread Thread
 
ccoveille profile image
Christophe Colombier • Edited

I agree with you.

I can get why @whitep4nth3r prefers a way she understands.

But for me, this is misleading for who wants to understand the git concepts/features, and very strange for people experienced with git.

Does it work ? Yes
Is it a way to achieve what git rebate interactive? Yes, somehow
Is it simpler ? Maybe
Will I use it ? No
Would I ever suggest doing like this? No
Would I discourage people to do this? No, but I will encourage them to use git rebate interactive.

Give man a fish ... you know

Image description

But yes, I remember git rebase interactive was something I had to learn before mastering it

Collapse
 
ccoveille profile image
Christophe Colombier

A very uncommon a
way to do a rebase interactive and fix up.

Collapse
 
whitep4nth3r profile image
Salma Alam-Naylor • Edited

I've had some bad professional experiences on teams who rebased everything which ended in some wild consequences. I'm scared to go back to that place πŸ˜…

Collapse
 
jessekphillips profile image
Jesse Phillips

Elaboration? The basic rule is that branches have a single owner and don't force push main.

Thread Thread
 
whitep4nth3r profile image
Salma Alam-Naylor

This is my preferred way to do it with my personal projects. Rebase is a more involved concept and this article is meant to show git in a friendly light for personal projects where you might want to clean up your commits.

β€œThe basic rule” you speak of isn’t always followed … which is why people can end up on a mess with rebase. Anyway this is really just about my personal experience and some people requested that I share what I do after seeing me do it on stream.

Collapse
 
avinashvagh profile image
Avinash Vagh

I think you got many fans hereπŸ˜… in comments section.
Thanks for sharing this, after reading all comments decided to try both way.

Collapse
 
ebonydomingue13 profile image
Ebony Dominguez

Interesting. Thanks for the post

Collapse
 
alia5 profile image
Peter Repukat • Edited

git rebase -i

  • let's you have a bit more control and is more iterative than just "git reset --soft XYZ"

git push --force-with-lease

  • you really shouldn't just force-push, theres a safer force-push for that
Collapse
 
smitterhane profile image
Smitter • Edited

I am relatively new to Git and as per my knowledge, anything you do with git is still undoable. I think the git reset is also tracked in the git history.

I did not understand when you say "the --soft flag leaves all files in their most recent up-to-date state"

The reset command instructs git to reset the repository to a particular state, in this case the initial commit, and the --soft flag leaves all files in their most recent up-to-date state

Did you mean that the working directory is not reset?

By the way, as I was learning Git's architecture, I also wrote an article about workings of git like: the working directory, The commit hashes, ...
understand Git

Collapse
 
whitep4nth3r profile image
Salma Alam-Naylor

Using --soft ensures the working directory is not reset to the state it was during your initial commit. So your local files are in the same state as the most recent commit. It's like you're winding back the commit history in terms of the hash, but keeping the latest file changes.

Collapse
 
adrianbienias profile image
Adrian Bienias

There's a git reflog so the true history is still in your repo, you're just hiding it.

If I understand correctly, your goal is to have a single commit that contains all the work you've done while making other commits during the way.

Can't you just remove .git folder and git init to create a new clean repo?

If (for whatever reason) you want your new local repo to override the previous origin repo you can just preserve config file from your .git folder and reuse it after git init to don't need to manually set origin.

Then the repo will be truly clean without the whole bloat of history available in reflog.

Collapse
 
denniskahlerlon profile image
DennisKahlerlon

Good one πŸ‘