Recently a pull request was filed that looked like this:
As you can see there is an extra merge commit. As is customary we wanted to get rid of it to get a clean rebase based merge history. To do that you'd first get a checkout of the code and look at the log, which looks like the following.
So far, so good. Now let's do a rebase --interactive. It looks like this:
Suddenly Git has chosen to silently remove the merge commit from this list. Why? I have no idea. The commit had changes in it, so it was not pruned because it was empty. If you then exit the editor without any changes (which usually means "do not change anything") then the commit is deleted and any changes that were in it are gone:
If your latter commits built on those changes, you get yummy merge conflicts for something that is conceptual a no-op.
This is the essence of working with Git. Most of the time it works sort of ok, but every now and then it will, without any warning or reason, completely screw you over, destroy your data and leave you stranded, forced to debug your way out of the resulting mess without any help.
"Of course it breaks, you should have used --do-not-do-the-idiotic-wrong-thing-which-for-some-reason-is-the-default command line option, everyone knows that, duh!"
A common kneejerk response to these kinds of problems is that it is somehow the user's own fault and that they should have memorized every quirk in the software in order to use it correctly (or at all). I'm certain some of you out there on the Internet had already started writing a strongly worded message to let me know that. Don't bother.
Whenever you have a piece of software that silently destroys user data, the fault always, always, ALWAYS lies with the program. Even if "it only happens rarely". Even if you think "it's the user's fault". Even if you personally know how the problem could have been avoided. The flaw is ABSOLUTELY ALWAYS in the software. Never in users. Ever.
Any attempt at shifting the cause to the user, for whatever reason, is victim blaming. Don't do it.
Completely agree.
ReplyDeleteI'm not exactly sure what you are trying to do, but if you rebase, the patches that are not in the base tree are applied on top of the base tree, so there is no merge. When you merge, the branches are merged and the original history is retained so you get the merge commit to mark when the trees were merged.
ReplyDeleteThe fact that you need to know ANY of this to prevent Git from destroying your data shows how godawfully terrible Git's UI is.
DeleteBut was there actually data loss? Omitting some commits is actually part of rebase's algorithm, and you'll find it clearly explained in the documentation.
DeleteThe ones it skip are those that would merge as an empty commit because their content is already in the branch you rebase onto.
WHICH WOULD BE EXACTLY WHAT YOU EXPECT OF A MERGE COMMIT…
Also, in rebase --interactive, leaving the editor without change where you have an action plan for a rebase means, surprisingly, "put that action plan in action, unchanged".
DeleteThere is another command for "cancel that plan".
So you need a PhD in Git to not destroy your code base? That's insane.
DeleteYou should look at Pijul :
ReplyDeletehttps://pijul.org/
For example :
Merging and patches
https://jneem.github.io/merging/
In git you do not loose data, ever. You can always restore to the remote. Git also still have locally a copy to undo the rebase. I think you need to check "ref-log" or sth like that. Just Google how to undo rebase and you'll find that it is pretty easy.
ReplyDeleteLearn your tools: --rebase-merges option
ReplyDeleteTo me it makes total sense: the merge comment was only there to track a merge, and once you rebase all merges should be gone. Hence their respective commits. As you yourself said, the reason why you rebased was to get rid of that commit, but now that git did it silently, you complain. :-)
ReplyDeleteOk it's now clearer, i read other users's view about git. I better understand why i got complete lost and confuse doing even simple stuff (which broke and i was better off delet repo/ restart).
ReplyDelete