Hacker Timesnew | past | comments | ask | show | jobs | submitlogin

> Figuring out what "properly" means is the whole problem with git.

I think you've missed OPs point by focusing too much on a single word ('properly'). Yes, there's no clear-cut way on how to use git, no silver bullet, but the main problem with git is that most devs simply panic when they have to do anything that goes beyond the bog-standard commit/pull/push/merge. Rebase? Squash? Reset? Rebase interactively? I think OP was referring to this cluelessness with 'not using properly', rather than which approach to git is the best.

I work on a monorepo with 40-something other devs, and we've recently switched to enforced linear history because the history got to the point of being completely useless, it was an unreadable spiderweb. The problem was not that folks didn't see that what they were doing was not-so-good (introducing often more merge-commits with every PR than non-merges), it was that they had no clue how to avoid that.

It took us quite a bit of time to get everyone up to speed but pretty much everyone got around to it after a while. It's not rocket science after all.



I've tried the "rebase into a feature branch" workflow, which I think you are alluding to. Unfortunately, it always results in scary conflicts. So I go back to merging the main branch into my feature branch workflow, which works every time. I then hit squash in gitlab for my merge request, and no one is the wiser.

Should I be doing something different? As I said, rebase in that situation is disastrous. Many folks recommend it vigorously but are not around when things inevitably go wrong.


> Unfortunately, it always results in scary conflicts.

I think you're referring to what I call "conflict cascades"? E.g., you're 4 commits ahead of "master", and want to rebase on top of it - but you have a conflict with your first commit, and after you resolve it, this results in conflicts in the second one, etc.?

It's a very interesting question because it's one of the main pain points of rebase that simply does not exist with merge.

What I've found for myself is that it's very important to create "atomic commits", which do not rely on other commits to make sense or "be complete". For example, a very common thing that I see is "fix formatting", "fix tests" commits, because some build was complaining about something being broken. And it's often these kind of commits that create weird conflicts (especially the formatting ones) because just a lot of code is moved/refactored/added/removed etc.

But do these commits make sense on their own? For example, if you have a history as follows:

    <commit-1> Introduce new fancy feature
    <commit-2> Fix formatting
    <commit-3> Fix tests
Does it make sense to ever check out <commit-1>? No, right, because that commit is broken - wrong formatting, broken tests. What you want is always <commit-3>. So why not just adding those changes directly to commit-1 by using commit --amend when committing or by using fixup in an interactive rebase.

This was of course just an example, but in my experience, if people follow these kinds of trains of thoughts - what can be in a separate commit, what should be together, etc., there is an inherently smaller conflict-cascade-potential, which pays off a lot when rebasing. On top of that, it also makes history generally more readable and individual commits more meaningful and easier to cherry-pick.


Not really. I give up on the first conflict, because dozens of files are in conflict and they are often incomprehensible.


I've never understood - or used - rebase as a standard part of a workflow. And I've been using git for nine years.

What is wrong with a master branch whose history reads "Merged feature foo" after "Merged feature bar"? If you need more detail then check out the feature branch and git bisect to your heart's content.

I do wish that we could "archive" branches from the output of `git branch -a` but really it's not a big deal when branch names are prefixed by Jira ticket identifiers.


I had this opinion for the longest of times as well, but me and all the other devs I know who started using a rebase-based approach just don't want to go back.

I think it's also a bit a question of team size. If your project has just a handful of devs working on it, merge-commits really don't matter all that much. If there are a few dozen with a good amount of juniors on the repo (a bit over 40 devs in my case), the commit-history becomes an absolutely unreadable spiderweb, that's at least my experience.

At work, we want to move towards trunk-based development (merge to master goes straight to prod), but whenever master was broken, a look at the commit-history didn't really all tell you that much about the who, how and why without checking it out and digging into it. So we've recently started to enforce linear history, in which case it is immediately obvious without the shred of a doubt who's responsible. Analyzing the build became an absolute breeze, at the cost of having a bit of a harder time at "insertion"-point (which is perfectly fine, given the fact that after merge, it should eventually go straight to prod).

It took a while to get everyone on board, but it was really worth the efforts and can only recommend it (I most definitely will prefer a workplace that is open to such practices in the future). In general, most devs were also quite happy to be guided through the process, as it is clear that git is probably one of the longer-lasting constants in our industry.

Also, I can't repeat it enough; speaking from experience, most devs severely overestimate the complexity of cherry-pick/rebase/reset/reflog etc. Whenever I had sessions explaining it or helping someone out with a problem, they had their first "aha!"-moments after a few minutes, and after that with some do-it-yourself-experience most of them get there rather fast. Obviously, there are always a few outliers who need a little bit of extra-nudging and extra-help to stay in line, but those are usually the ones who often also need that sort of assistance in other areas so that's okay.


> I think it's also a bit a question of team size. If your project has just a handful of devs working on it, merge-commits really don't matter all that much. If there are a few dozen with a good amount of juniors on the repo (a bit over 40 devs in my case), the commit-history becomes an absolutely unreadable spiderweb, that's at least my experience.

git log --first-parent gives you a nice linear history of (generally) your top level merge commits. If you follow a PR workflow, it's PR-by-PR breakdown of activity. The DAG gives you the power to "explore the spiderweb" if want/need to, but also pull back and say "give me the high level over" (--first-parent). I still think a lot of the emphasis on rebase-only workflows would disappear if more of the graphic UI tools (including and especially GitHub) had a better --first-parent experience by default. With the GitHub PR flow it has always surprised me that the main commit log isn't just a --first-parent view with an optional drilldown experience.


Sorry to beat a dead horse, but I'd love to be convinced. Could you give me an actual example where you were able to review a commit log that had been rebased easier than it would have been had been merged? Or an actual example where a merged commit log was a pain where it would have been easier had it been rebased?

Maybe the advantage is for people who use graphical tools? I'm still in the stone age using Git in bash.

Thanks.


> I've tried the "rebase into a feature branch" workflow, which I think you are alluding to. Unfortunately, it always results in scary conflicts.

You never rebase something into something else, you rebase onto something. I suppose you meant you want to rebase feature branch onto master.

If you have conflicts, you'll have them anyway, regardless if you're merging feature branch into master, merging master into feature branch or rebasing feature branch onto master. Conflicts are not a consequence of rebasing.


I'm working in a feature branch, and after a day or three changes have landed in the main branch. Which I need to incorporate or my merge request will be behind.

When I pull from main (git pull origin develop) there are rarely conflicts. When there are they are easy to understand and fix. Clicking squash on my request hides all intermediate commits so history stays clear in any case.

When I try to rebase from main (git pull --rebase origin develop) often almost every file in the project is in conflict, and the conflicts themselves are incomprehensible. I then run rebase --abort and go back to the merge strategy.

I've tried this about four times in the last few years; no one is able to explain what went wrong. If I had to guess it may have something to do with me pushing the branch when creating it.


That's not how you do it.

    git checkout master     
    git pull             => fetch and merge the new things on master
    git checkout develop => go back to your work branch
    git rebase master    => simple rebase, no squash, no nothing. The conflicts are the same as you'd get with git merge
do not forget to force push the changes of your branch

    git push origin --force develop => to update your branch on the server


You can skip the "checkout master + pull" part by using "git fetch origin master:master", or by using just "git fetch origin" and then "git rebase origin/master". Other than that, that's pretty much my workflow too :)


Yes, I know. I just wanted to keep it at the simplest form.


Ok, thanks. Although making a one step process into five, doesn’t sound like a big win. Perhaps the shorter version is workable.


I don't know, most people I've seen "scared" by merge/rebase conflicts have simply been scared by the UI provided to resolve them. It's just a matter of spending a bit of time familiarising yourself with what you're seeing and understanding what the tools are doing.

There's a bunch of resources on that and once you wrap your head around what git is doing it shouldn't be too hard to figure out how to navigate conflicts.


Merge conflicts in a rebase can propagate through every commit in your feature branch (suppose that you modify a boilerplate line in 10 commits, and you get a conflict on that line in the rebase, you now have to solve that conflict 10 times possibly with some interference with nearby conflicts)

In many cases also there are problems with git being line oriented rather than token oriented, IMHO I would have expected language aware diffs (for definition of "words" and maybe parenthesis) for common languaged to be common place by now (maybe even with a language server support)

In my team we are lucky as most conflict are a matter of simply choosing a side and overwriting the other.


>Merge conflicts in a rebase can propagate through every commit in your feature branch (suppose that you modify a boilerplate line in 10 commits, and you get a conflict on that line in the rebase, you now have to solve that conflict 10 times possibly with some interference with nearby conflicts)

Yes, this is true. But in a lot of cases this is a relatively trivial fix. That being said, I do think git could do better here. But I have not had it happen very often (and usually I know when it's about to happen so I know what to expect).

> In many cases also there are problems with git being line oriented rather than token oriented, IMHO I would have expected language aware diffs (for definition of "words" and maybe parenthesis) for common languages to be common place by now (maybe even with a language server support)

Language aware diffs would be a neat idea indeed, but I guess the issue may be that now git would need to have metadata to tell it which language server to use for which file.

I wonder if it would be possible to give git a plugin system for diffs, just have an option to offload to a diff program which could handle the metadata separately.


> [...] in a lot of cases this is a relatively trivial fix. > [...] I have not had it happen very often

Often it is simple but it is tricky and hard to practice. Part of the problem is not git fault, it is just that thinking in diffs is not easy.

> metadata to tell it which language server to use for which file

My understanding is that git already does this (via filename or custom helpers) for binary/text files, I believe that it is used only for newline conversion, but for most usecases filename-based rules in a gitignore derived syntax would be enough.


Currently for binary files git has heuristics described in gitattributes(5) and these only go as deep as text encoding autodetection and the ability to specify the text encoding of a file or mark a file as binary. It's not sophisticated enough to know what kind if file it's looking at outside of just that.


See my earlier comment here:

https://qht.co/item?id=27580478


Regarding your first point (and I think some of the commenters in that thread also address this already) is that as long you don't have uncommitted changes, you're safe. You're right that a lot of git-commands mess with uncommitted changes in hard-to-recoverable ways, but once changes are committed, there's almost no way to mess anything up, you can always go back to the previous state (git reflog <branch> telling you which commit that was).

Regarding the second point - if you have a rebase-based work-flow, you will encounter this problem less often (or not at all).

For your third point - what helped me a lot is to actively distinguish between commits and the working tree, and making myself aware that branches really are just "pointers" to commits (obviously, but somehow, actively thinking about it made the intent of git commands a lot easier to understand). Also, most git commands are just combinations of other commands. git reset is just moving the pointer (--soft without touching the working tree, --hard will do so), rebase is essentially a hard-reset with consecutive cherry-picks afterwards, and so on.

Also, an eye opener for me personally has been that e.g. an interactive rebase with squash towards a branch that is strictly ahead of you except for the commits you want to rebase is essentially just a "git reset --soft <target>", and then recommitting everything with a fancy commit-message. This and similar mental gymnastics with git-commands has helped me a lot; most of them really are quite sane (except for all those crazy options), "git checkout" is really the odd-one-out of the bunch (and "git pull" a combination of things that should never have been combined in the first place).


LOL. :D

I really am not sure if you were being sarcastic or are really that unaware what a mish-mash of specialized jargon you just threw at the guy.

Don't think you the proponents actually understand the problem. It's not that programmers are unwilling to learn (something that many elitistic people love to pretend so they look smarter), it's something called tool fatigue. You just want your tools to do their job and move out of the way which GIT absolutely does not do.

I know that one day I'll get completely sick of GIT and will research and learn it to the bone. Sure, it's bound to happen. But the fact that GIT imposes its internal data model on you and doesn't attempt to solve more problems for you from the get go is what many of us are ticked off about.


> I really am not sure if you were being sarcastic

I was not :P But the commenter also said in the linked comment that they "understand how git works", so I took the liberty to make a few assumptions ;)

> But the fact that GIT imposes its internal data model on you

It does, to some degree, but once you get a grip of "everyday commands" that go beyond commit/merge (cherry-pick, rebase, reset, reflog), it's actually almost surprising how little you have to know about gits internals. It does help to have an idea about them, though.

My main complaint about git is that most commands have too many options that make it do too many different things. And that resolving conflicts via command line is absolutely atrocious (something I actively avoid and discourage).

> I know that one day I'll get completely sick of GIT and will research and learn it to the bone

I can only recommend it! It's really not that hard as many people suspect (as I've mentioned, I have a bit of a habit of teaching people git at work). If you had any exposure to something computer science in the past, the puzzle pieces probably start to come together after some hours.

And it's probably one of the longer-lasting constants in our industry, so in my opinion, it's really worth it to know how to make good use of it.


Yeah. That clarified everything.


Honestly, if you were less busy sulking about it you might have had some capacity left to be receptive, in stead... And then it might actually have helped clarify a lot.

Also: In a discussion where one party is being helpful and the other sullenly sarcastic, it's not the helpful one that comes off as an asshole.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: