[HN Gopher] Idiot Proof Git
       ___________________________________________________________________
        
       Idiot Proof Git
        
       Author : softwaredoug
       Score  : 279 points
       Date   : 2022-11-09 14:28 UTC (8 hours ago)
        
 (HTM) web link (softwaredoug.com)
 (TXT) w3m dump (softwaredoug.com)
        
       | wodenokoto wrote:
       | Pretty cool idea.
       | 
       | Something I really want is a version of `git amend` that takes a
       | commit hash, so I can amend my changes to any commit, not just
       | the last one without having to start an interactive rebase.
        
         | Zitrax wrote:
         | You could create an alias doing something like a "git commit
         | --fixup <sha1>" and then a "git rebase --autosquash <sha1>~".
        
       | [deleted]
        
         | [deleted]
        
       | Shadowed_ wrote:
       | Nothing is idiot proof. Only more or less idiot resistant.
        
       | danpalmer wrote:
       | Big fan of Git style guides in teams. We had one at Thread. It
       | was common for engineers to come in and find we didn't do
       | rebasing and find it weird, but we took the opinion that history
       | should be exactly what you actually did, not some clean and
       | idealised version of what you wish you had done. There are
       | advantages and disadvantages to this, but having a defined
       | approach was the most important aspect.
       | 
       | Also the fact that we didn't rebase and used merges everywhere
       | was a major contributor to no one ever breaking their git repos,
       | something that git seems notorious for elsewhere.
        
         | eternalban wrote:
         | > history should be exactly what you actually did, not some
         | clean and idealised version of what you wish you had done.
         | 
         | This is a false premise. There is a product (and its various
         | versions), and the team that develops it. Both have a claim to
         | a meaningful definition of "history". What you are arguing is
         | that the 'history of developer' is more fundamental than a less
         | noisy 'history of the product development'.
         | 
         | Does it really matter (and need we record it for posterity) if
         | developer x used n commits to post n incremental changes to a
         | well defined software unit of the product?
         | 
         | It seems a comprise position of _(1) no history rewrites before
         | code review_ , followed by _(2) post code review cleansing
         | squash before merge_ would satisfy all concerns and history
         | records have also served their purpose.
         | 
         | . A developer 's timeline is relevant to her team lead, not the
         | product manager.
        
         | tyingq wrote:
         | What about squashing commits in a merge? I don't do that all
         | the time, but it is useful for certain things. Like repeated
         | code changes to test something in the CI/CD pipeline (that I
         | can't replicate well locally), where only the last change that
         | got it working is of any interest.
        
           | dec0dedab0de wrote:
           | _What about squashing commits in a merge? I don 't do that
           | all the time, but it is useful for certain things. Like
           | repeated code changes to test something in the CI/CD pipeline
           | (that I can't replicate well locally), where only the last
           | change that got it working is of any interest._
           | 
           | You can get the same effect by reverting-to/checking-out a
           | merge commit, or doing diffs between merge commits. You can
           | also get a fairly clean history by only showing merge
           | commits.
           | 
           | My rule of thumb is that any commit that has been pushed to a
           | shared remote should never be re-written[]. If you're going
           | to rebase, do it on your computer before pushing, or on your
           | own repo before opening a merge/pull request.
           | 
           | [] exceptions would be removing accidentally committed
           | secrets or large files that are no longer needed.
        
           | prettyStandard wrote:
           | Squashing is rewriting history.
           | 
           | It sounds like the grandcomment had a ban against rewriting
           | history across-the-board, which would help make git idiot
           | proof. I love rewriting history, not because it's what I
           | wished I had done but because it's what I am going to want to
           | review when I have to.
           | 
           | Rewriting history is a great way for gitiots to shoot
           | themselves in the foot.
        
             | peteradio wrote:
             | Couldn't you rewrite history locally on your own branch and
             | nobody would know?
        
               | prettyStandard wrote:
               | Yeah... You should never rewrite history of shared
               | branches. You are just asking for trouble in that case.
        
               | danpalmer wrote:
               | We informally allowed whatever you wanted until you
               | opened a pull request.
        
               | chrisfinazzo wrote:
               | Hard agree. Do whatever the heck you want locally, just
               | try not to screw everybody else up when you push.
               | 
               | (From the guy who force-pushed on a personal project
               | yesterday to resolve a situation with multiple remote
               | heads - I am ashamed)
        
               | opsy_ wrote:
               | Sure, unless you bork your local repo enough you need
               | help from a teammate getting your work into a PR.
               | 
               | Not to say that doesn't make for a good learning moment.
        
               | OkayPhysicist wrote:
               | At some point, every junior is going to mangle something,
               | and need a senior to sit them down and give them the git
               | reflog talk. It's an inevitability, and should be
               | embraced as a natural part of the evolution of a
               | developer.
        
               | prettyStandard wrote:
               | Haha. what's the git reflog talk? To be clear I know what
               | reflog is, but what's "the talk"?
        
               | olddustytrail wrote:
               | Probably just making them aware of it. But I can give a
               | slightly longer spiel:
               | 
               | Commits in git are immutable. They're identified by their
               | hash, so they have to be. What's more they have the hash
               | of the previous commits so the whole chain back to the
               | first commit can't be changed. You can only add new
               | chains.
               | 
               | As a consequence, if your main branch points to commit
               | abc123 and your feature branch points to commit def456
               | then it doesn't matter if you merge, cherry pick, rebase
               | or dance the fandango, if you point those branches back
               | to those commits, the branches must by necessity look
               | identical to the way they looked before you did anything.
               | 
               | And you can find out where they used to point in the
               | reflog.
        
               | OkayPhysicist wrote:
               | Just the explanation of "no matter how bad you've fucked
               | up your repo, as long as you haven't run 'git gc' or
               | waited a few years, all you need to fix it is to find the
               | commit hash from git reflog, git checkout that hash, and
               | then git branch to give you an easily accessible
               | reference to the commit". Followed by some pointers on
               | how to efficiently dig through reflog.
               | 
               | It's pretty freeing to realize that it's basically
               | impossible to lose committed code.
        
         | cnity wrote:
         | If the employer I worked for started micro-managing the way I
         | use my tools (that affects nobody else) I would consider
         | leaving, honestly. If I rebase on a branch that hadn't been
         | shared with someone else, why does it matter what my boss or
         | team thinks about that approach?
         | 
         | Code styles are one thing, what I type into my terminal is
         | another.
        
           | gardenhedge wrote:
           | When you commit you're sharing with your team and future
           | team. I think it's fair to have a set of agreed guidelines
           | around that. What if you wanted to put all your commit
           | messages as "cnity did it"?
        
         | hinkley wrote:
         | Telling people not to rebase and having code that was never
         | rebased are two very different things. Have you asked _former_
         | employees if they rebased when nobody was looking? If you
         | haven't then you have no reliable data on what happens.
         | 
         | When people set ridiculous absolute rules, what develops is an
         | underground of people who don't follow the rules and in some
         | cases get a thrill from subverting the dystopia.
        
           | eikenberry wrote:
           | When I hear 'no-rebasing' I hear 'no-rebasing after you've
           | done a PR'. That's when my code and commits are ready for
           | others. My ongoing commits are often more notes to myself as
           | I find those more useful during the work but make no sense as
           | pushed commit messages where you need to block things off
           | logically. Organizing your commits is not much different than
           | organizing your code into modules. Something that should be
           | done purposefully and with forethought.
        
         | ajkjk wrote:
         | gosh, wow, I want the opposite of that for any project I work
         | on. In the last five years I have never used a merge commit and
         | I love it. I'd honestly prefer a version of git that doesn't
         | have em.
        
           | umvi wrote:
           | Without merge commits you can never have more than 1 long-
           | lived branch because said long-lived branches will not have
           | any common ancestors which makes pulling changes between them
           | a nightmare (literally every file will be in conflict)...
           | 
           | I like linear histories too, but if you have a production
           | branch and a development branch you need merge commits
           | between them.
        
         | wizofaus wrote:
         | Technically your git history isn't a record of what you did,
         | only what you committed. If I make a bunch of changes locally,
         | commit then realise I need to make a few extra changes before
         | pushing there's really no harm amending the commit. But once
         | pushed, I agree, it should stay as is.
        
         | idop wrote:
         | Obviously what works for you works for you, but I respectfully
         | disagree with everything you said.
         | 
         | The "history should be exactly what you did" argument - which
         | many people make - is really funny to me because a pull/merge-
         | only strategy only preserves the _wrong_ history. As a tech
         | lead, for example, I absolutely do not care one bit about the
         | date of a commit, or when the developer started working on it,
         | or what was the commit they started working on top of. That may
         | be "what really happened", but it's worth nothing in the grand
         | scheme of things. When a commit _has made it into the product_
         | is the only " what really happened" there is, and that is what
         | I care about. And a linear history makes this much easier to
         | analyze and understand, reducing cognitive load considerably.
         | 
         | Also, it's strange that you see merges as a contributor to
         | keeping repos from breaking, as my experience is the opposite.
         | 
         | I advocate for a rebase-based strategy wherever I go as it
         | helps developers push better code, it actually curbs hysteria-
         | driven "merge it as fast as possible no matter how shit it is"
         | cases, and I see how it turns the Git log into an actually
         | useful source of information for developers and other personas.
         | People start reading the logs!
         | 
         | The log should track the product's evolution, not the
         | developers' activities.
        
           | Shacklz wrote:
           | > And a linear history makes this much easier to analyze and
           | understand, reducing cognitive load considerably.
           | 
           | This, so much this! And the price you pay for it is a
           | slightly more difficult "insert". We started to enforce
           | linear history in one of our bigger repositories (about 100
           | devs) about two years back; the first months were quite the
           | ride (I had to do plenty of support-sessions to recover
           | 'lost' changes). But the devs really started to see the
           | benefits, and once they got the hang of it which was actually
           | faster than I anticipated for most, it was smooth sailing.
           | Many actually started to embrace it and advocate it for other
           | repositories as well.
           | 
           | For me, it became also evident that filtering for people
           | capable of learning git (rebase, cherry-pick, reset etc.) was
           | very good at finding out who I'd want to work with and who
           | not. It's really not that big of a deal, the UX of the CLI
           | might be lackluster but the underlying datamodel is rather
           | straight-forward. It's such a quintessential tool in our
           | every-day-workflow that it's really worth putting a bit of
           | time into understanding it, and if someone can't or doesn't
           | want to, well, it might just be better if they work somewhere
           | else than I do.
        
             | dbt00 wrote:
             | You can, 99.9% of the time, emulate linear history with
             | first parent history, which is a post-hoc tooling choice
             | that doesn't remove context.
             | 
             | Developers shouldn't try to merge branches with
             | wip/wip/wip/wip histories either, that's just garbage.
             | Commit messages are documentation, fix your documentation
             | before you publish.
        
           | mibollma wrote:
           | I disagree with both of you :). Personally I prefer to squash
           | to one commit per ticket but on a team level I don't care
           | about a consistent way.
           | 
           | I've found that the history rarely doesn't matter at all to
           | me. Finding out who modified a specific code section (git
           | blame) is usually good enough.
        
           | Jenk wrote:
           | I advocate for rebasing, but I discourage using a linear
           | history. The two may seem to contradict one another but they
           | are distinct (enough) that I felt it worth mentioning. When a
           | developer pushes, it makes sense for them to rebase first
           | because they are shipping those commits at the time of the
           | push.
           | 
           | But, depending on your git workflow, when merging to main, I
           | prefer a merge commit so I can see the tree of activities
           | that lead to any particular release.
        
             | idop wrote:
             | That's fine of course. Personally, I prefer to make things
             | as easy as possible to understand at that unspecified but
             | probable future date when a customer opens a SEV1 and I
             | have to consult with the log, among other things. Make it
             | idiot proof later, when time is _really_ of the essence,
             | rather than now, when you're being artificially pressured
             | to deliver that story for the sprint review in two hours.
        
               | Jenk wrote:
               | I'm advocating that merge commits in main make it easier
               | precisely for the requirements you specify: To track what
               | feature(s) was introduced at a given release. With merge
               | commits you not only have groupings of commits for
               | features developed, you have that ability to revert a
               | whole feature with just one revert. If you rebase onto
               | main you are flattening those groupings and the entire
               | commit stack into one serial history. For super quick
               | "fix forward" products, that's fine and I would be happy
               | with that. In products that are not so quick or perhaps
               | you have tighter controls/SLAs/etc. Being able to
               | immediately identify and revert an entire feature from
               | main is very valuable, above and beyond a feature toggle
               | imho.
        
               | pierrebai wrote:
               | Squash commit will squash everything done into a single
               | commit, so reverting it is _easier_.
               | 
               | Also when you have to cherry-pick fixes into an older
               | release branch, you get to fully appreciate squashed
               | merges. If you did not squash, you need to cherry-pick
               | all commits from the merge. If the feature branch was not
               | rebased and the dev merged main into the feature branch
               | multiple times, then the branch commits are inter-mingled
               | with main commits and it is so easy to mess up the
               | cherry-picking. Just imagine if the dev had to fix
               | conflicts...
               | 
               | All that makes squash commit a time-saver.
        
               | tremon wrote:
               | _so reverting it is easier._
               | 
               | Only reverting the entire feature is easier. Reverting a
               | single change (for example, because it introduced a bug
               | but is not critical to the feature itself) becomes much
               | harder after squash.
        
               | seba_dos1 wrote:
               | > Squash commit will squash everything done into a single
               | commit, so reverting it is easier.
               | 
               | No, it's _just as easy_ , while needlessly throwing away
               | other useful information.
               | 
               | > If you did not squash, you need to cherry-pick all
               | commits from the merge.
               | 
               | ...or use a single `git rebase` invocation.
               | 
               | > If the feature branch was not rebased
               | 
               | Linear workflows with merge commits usually require
               | feature branches to be rebased on merge (just like
               | squashes, just without the actual squashing), so that's
               | not a problem at all.
        
           | danpalmer wrote:
           | My point wasn't that this strategy was the right one, but
           | that having a clear strategy is more important.
           | 
           | I personally prefer a more rebase-heavy approach, but what we
           | had worked very well for us.
        
             | idop wrote:
             | Oh definitely, a clear and enforced strategy and
             | conventions are more important than anything.
        
               | smaudet wrote:
               | Boundaries are equally important - a set of expectations
               | in context is fine, letting people know there is a world
               | outside your little ego-bubble is also important, them
               | knowing how and when to live in both is valuable.
        
           | hinkley wrote:
           | Usually my strategy, but it breaks down if you have someone
           | who is bad enough at merge conflict resolution. We had one
           | guy Steve who was upset that he was not as in charge as he
           | wants to be, but he was doing a few things that break my
           | trust so we are keeping him on a shorter leash than he likes.
           | His code and ideas are okay but not great. He's picking on
           | this guy Mark, who sat next to me, to make himself look more
           | valuable. Mark was not the brightest senior dev I ever worked
           | with but he had his uses, and I hate bullies. Last but not
           | least he was that he was terrible at merges and his solution
           | to this problem was to delay as long as possible. We are a
           | full CI environment and he's making work for others by doing
           | this. Namely me. None of these are conducive to me giving out
           | a lot of responsibility, so he has some but not what he was
           | after.
           | 
           | One day he's blaming Mark for a regression in the code. Being
           | pretty loud about it in fact. When I look at the bug, it sure
           | looks like the sort of mistake Mark would make, and the
           | annotation says Mark. Only the thing is that I'm the one who
           | reviewed this code and I know Mark so I was looking for
           | exactly this sort of bug and was pleasantly surprised to find
           | that he was learning and had dodged that pitfall. So I go
           | excavating the history and sure enough, that bug wasn't in
           | the code I reviewed. It was in Steve's merge resolution.
           | Fuckin' Steves, man. And the fact that git lets you do things
           | like that is not a great feature either.
        
             | bornfreddy wrote:
             | I don't know either Steve, Mark or you, of course - but
             | this sounds like a broken dynamic where boss's preference
             | of one person (sitting next to Mark, probably mentoring
             | him) pushes another, Steve, to show his fighting side.
             | 
             | Yes, Steve should have kept things honest. But being the
             | boss, you need to be careful not to pick favorites and to
             | treat everybody in a similar fashion. People are very
             | touchy about how they are treated within the "tribe".
             | 
             | Also, if you identified the issues both of them are bad at,
             | are you all solving them? Being "terrible at merges"... how
             | does that even work? Isn't that kind of an important skill?
             | As their boss, their know-how is your responsability too,
             | are you solving it?
             | 
             | Sorry if I have misjudged the situation, I obviously don't
             | know it first-hand, so you will need to see for yourself if
             | the above is true. There were just too many red flags (for
             | me) in your comment to let it pass... And the reason I see
             | them is that I have misjudged colleagues in the past, and
             | wish I had known better then. Ah well.
        
             | smaudet wrote:
             | The one who does the merge is always the one responsible...
             | even if your code is amazing if it doesn't work with the
             | (working) body of code that's on you, not the people who
             | came before.
             | 
             | Of course Steve can just commit terrible code to main-line,
             | and Mark (or yourself) are always stuck fixing their code,
             | but that's what review/testing are supposed to be for -
             | maybe blame the reviewers and testers in that case instead.
        
           | idop wrote:
           | Also, keep on mind that Git is the engine with which
           | Continuous Integration is made. CI is developers integrating
           | with the work of one another on a regular basis. If the
           | product changed since you started working on your new brach,
           | then your branch is stale and you need to integrate with the
           | recent changes. Why wait until you're done to find out that
           | your branch can't be merged anymore and you have to make a
           | ton of changes when you can keep on top of things at regular
           | intervals and make the final merge as easy as possible, not
           | just for you, but for the code reviewers, the QA guys, the
           | DevOps guys, everyone.
        
           | rtepopbe wrote:
           | My current thought on this is that the git model (or at least
           | the interface for it) is probably a touch too simple to
           | accommodate all the things people want to use it for. As a
           | result, you get this whole 'clean history' vs 'what really
           | happened' split. And often you can find a few more splits if
           | you dig in a bit deeper into the actual mechanics people
           | prefer.
           | 
           | Generally, bigger picture stuff works best with cleaner
           | histories as they mop up a bunch of unnecessary and
           | distracting details, and neatly package things together. But
           | doing so also means you're getting rid of, well, the details.
           | If you need them later - and some poor bastard always will -
           | you're just screwed.
           | 
           | Unfortunately all we've got are commits, so you're constantly
           | fighting different groups and even different people who value
           | the benefits of different approaches due to their positions,
           | histories, or preferences.
           | 
           | This isn't even a half-baked idea at this point, but at first
           | glance something like a meta-commit which just contains more
           | commits and a message seems like it might be better. The top-
           | level commits could just be the 'clean history' while deeper
           | levels could record more of the as-happened details.
        
           | dec0dedab0de wrote:
           | _The log should track the product 's evolution, not the
           | developers' activities._
           | 
           | Git is a development tool, not a product release tool. If you
           | want to see the product evolution you could filter to just
           | merge commits, or just merge commits in a specific format.
           | 
           | If you want to keep track of releases specifically, then use
           | tags, that's what they're for. I suppose you could make a
           | separate branch/repo where every commit = a release, but that
           | opens you up to merge conflicts without any benefit over tags
        
             | idop wrote:
             | At the end of the day everything depends on the
             | organization. In a hectic startup where requirements change
             | on an hourly basis and releases are made several times a
             | day, I would absolutely insist on keeping the log linear
             | and as clear as possible. Tags are important, of course,
             | but they're not that useful for analyzing a repository.
             | 
             | When I say "the evolution of the product" I really mean
             | "the "evolution of the code". When a small feature branch
             | with 5 commits - four of which say "wip" and the last one
             | says "added color support" - gets merged as is, and all
             | relevant information is held hostage by whatever Git
             | platform the company is using this week and not inside the
             | repository itself, the log is not useful to me regardless
             | of any strategy.
             | 
             | But in a different setting I would not necessarily insist
             | in the same way.
        
               | dec0dedab0de wrote:
               | _When I say "the evolution of the product" I really mean
               | "the "evolution of the code". When a small feature branch
               | with 5 commits - four of which say "wip" and the last one
               | says "added color support" - gets merged as is, and all
               | relevant information is held hostage by whatever Git
               | platform the company is using this week and not inside
               | the repository itself, the log is not useful to me
               | regardless of any strategy._
               | 
               | Yes, it can be annoying if your developers are committing
               | nonsense, but then just tell them to not do that, or to
               | rebase locally before pushing.
               | 
               | If you find yourself troubleshooting a bunch of nonsense
               | commits, you can just do a diff to the merge commit, and
               | it will show you all the changes. But you also have the
               | option of figuring out exactly which commit caused the
               | problem, and seeing it in context. If I see an error in
               | the middle of a bunch of commits that look like "trying x
               | with y." Then I know that this is a tricky problem, and
               | the developer was lucky to get it to work at all. If it
               | is in the middle of a standard looking commit, then the
               | developer didn't struggle with this. So maybe they didn't
               | put enough effort into it, or maybe it is a rare corner
               | case.
               | 
               | When I'm troubleshooting other peoples problems, every
               | bit of information helps. Especially when the developer
               | who introduced the problems is no longer with the
               | company. Squashing commits removes some of that
               | information, without providing anything that I can't
               | approximate by using merge commits in logging/diffs.
        
               | krinchan wrote:
               | git add .; and git commit --amend --no-edit; git push
               | origin --force
               | 
               | Rarely, I have to do pipeline work on repositories. You'd
               | normally see twenty "Fix Jankins Issue" commits on the
               | main branch because of some nonsense that only happens
               | when you deploy UAT or whatever. Once I learned this
               | little gem, this is also how I manage my feature branches
               | mostly. But also my employer's fleet of laptops has been
               | aging and I've had to do 3 swap outs this year, so I like
               | to keep my in progress work pushed up just in case.
        
               | tremon wrote:
               | _git add ._
               | 
               | We have had multiple security incidents because some
               | developer left a credential file inside the local git
               | clone (no, not all tooling supports out-of-tree stored
               | credentials). Blind 'git add .' is the first thing I
               | teach my developers not to do.
        
               | sixstringtheory wrote:
               | I did this for a while but have moved on to
               | git commit --fixup HEAD
               | 
               | and you can tack an -e on the end to add more notes in
               | the commit message body. You can fixup prior commits by
               | supplying their short hash, which is how I originally
               | discovered this: I essentially wanted to amend a commit
               | farther back in my branch.
               | 
               | This makes a commit with a "fixup!" prefix that works
               | with                   git rebase --interactive
               | --autosquash
               | 
               | you can also form that kind of commit directly, and there
               | is also a "squash!" directive. Now you don't have to
               | force push amended commits. And it helps sometimes when
               | you accidentally amend something you didn't mean to-now
               | you can just soft reset to HEAD~1 and try again.
               | 
               | I don't even bother locally rebasing to autosquash it all
               | anymore since we use squash-to-merge/rebase in github PRs
               | now.
        
               | tkot wrote:
               | I'd probably suggest --force-with-lease just to be sure
               | ;)
        
               | xenomachina wrote:
               | > Yes, it can be annoying if your developers are
               | committing nonsense, but then just tell them to not do
               | that, or to rebase locally before pushing.
               | 
               | I'm pretty sure rebasing locally is exactly what the
               | person you're arguing with is arguing for. The original
               | comment in this thread was saying you should never
               | rebase, always just merge.
        
               | Quekid5 wrote:
               | > If I see an error in the middle of a bunch of commits
               | that look like "trying x with y." Then I know that this
               | is a tricky problem, and the developer was lucky to get
               | it to work at all.
               | 
               | Just an aside, but if there problem being solved is
               | harder than it looks then this deserves a comment
               | explaining _why_ in either the commit message or in the
               | code itself.
        
               | idop wrote:
               | To be clear, what I'm advocating for is that feature
               | branches get rebased regularly by the developer until PR-
               | time and a clean merge into the mainline. I usually
               | recommend squashing to one commit but do not insist.
               | 
               | I can definitely see how those intermediate commits can
               | provide more information, but there's a tradeoff. More
               | often than not, they do not provide me much value, and
               | instead give me bloat, so I prefer to keep things simple.
               | 
               | Telling developers not to do something is like telling a
               | kid not to push that red button. The average developer
               | chooses what's easiest _right now_ and thinks it's
               | someone else's job to fix the mess at PR time. And
               | they're afraid, because that one time five years ago they
               | ran a rebase without knowing what it does, and lost some
               | code without knowing it's actually right there in the
               | reflog, and since then they are deathly afraid of Git. I
               | know how to use log and diff and all the others quite
               | well, but most don't. So I'm trying to make things easier
               | on everyone in the long term, not the short term.
        
               | mixmastamyk wrote:
               | > feature branch with 5 commits - four of which say "wip"
               | 
               | Merge+squash eliminates this and it works every time. One
               | or two clicks on gitlab for example.
        
             | smaudet wrote:
             | Actually you're both wrong, its a change tool, not a
             | development or a product release tool.
             | 
             | "then use tags, that's what they're for"
             | 
             | No they're not - that's definitely a useful way of using
             | them, but they are just labels.
             | 
             | Why is it useful to know this? Well, when you know your
             | tool better (how it operates, not the porcelain or CLI),
             | you have better insights and are able to use it better.
             | 
             | You can manage Agile-style "features" with nothing but
             | hashes and tags, no branches necessary. Branches are
             | actually somewhat antithetical to distributed development,
             | they're a useful concept, but that's all they are.
             | 
             | I do tend to agree though, re-base is superior to merge, in
             | a product setting. If you want to track a feature set,
             | having the set of commits which represents that feature set
             | is better than a litany of nonsense tangled up in twelve
             | feature "roots" (branches which have been merged together).
             | 
             | In a "do what I want" setting, rebase and merge are about
             | equal, though. If I want to work on 3 features
             | independently, I'd like to be able to easily see both
             | features in parallel. I also would like to squash my
             | features to single commits, and rebase them into feature
             | branches where I can then merge/rebase/whatever those into
             | my final "product" branch.
        
       | jgworks wrote:
       | This is off topic:
       | 
       | I have a dumb git question and I can never seem to formulate a
       | google search that will help me.
       | 
       | I use a Mac and for some reason I am able to use `head`
       | (lowercase) instead of `HEAD` (uppercase) in every command and
       | its trained in my muscle memory.
       | 
       | So when I go to another computer, this shortcut isn't there, so
       | when I type `git reset --hard head^` I get an error, and I have
       | to go back and change it to `git reset --hard HEAD^`.
       | 
       | Anyone know of a configuration option or something somewhere that
       | I can enable this?
        
         | [deleted]
        
         | [deleted]
        
         | trillic wrote:
         | MacOS defaults to a case insensitive filesystem. Branches are
         | just a commit tag which is just a git object which is a file???
         | I think? Everything is a file?
        
         | Anktionaer wrote:
         | Not to worry, I am a professional googler
         | 
         | https://stackoverflow.com/questions/25976794/is-head-in-git-...
         | 
         | ...I keep finding out neat new stuff about git plumbing.
        
         | periodontal wrote:
         | This is probably due to the underlying filesystem being case
         | insensitive on Mac. As a hack, you can create a symlink alias
         | on a per repo basis.
         | 
         | ln -s HEAD .git/head
        
         | quesera wrote:
         | > Anyone know of a configuration option or something somewhere
         | that I can enable this?
         | 
         | I'd suggest that you retrain yourself instead. "HEAD" and
         | "head" are not the same thing, and any fakeout configuration to
         | change that will also be nonstandard and not available
         | everywhere.
         | 
         | The underlying issue is that HEAD is the label Git uses for the
         | reference to the top of the repo. It's saved in the filesystem
         | as .git/HEAD.
         | 
         | MacOS filesystems are _case-preserving_ by default. Linux
         | /POSIX filesystems are _case-sensitive_ by default. I consider
         | this a bad default setting in macOS. Try  "cp FILENAME
         | filename" sometime. :(
         | 
         | Anyway, consequently, on default macOS, "head" will be remapped
         | to "HEAD", if "head" does not exist. Watch out for "Head" and
         | "hEaD" though. Of course those won't happen in normal Git usage
         | (though they could be valid, and different, tag names!).
         | 
         | My suggestion is to not let bad macOS defaults creep into your
         | habits. And to not make things even more weird by trying to
         | reproduce their bad behaviour in non-macOS environments.
        
       | stblack wrote:
       | I might be mistaken but this post is basically describing git-
       | friendly which I've used for years, is 100% flawless, and you'd
       | need to pry from my cold, dead hands.
       | 
       | https://github.com/git-friendly/git-friendly
        
         | [deleted]
        
         | jaimehrubiks wrote:
         | OP's post describe the exact command git would use, and
         | explains why, which is great for learning purposes as well.
        
         | ccity88 wrote:
         | I know HN will absolutely tear me apart for recommending this,
         | but I use GitHub desktop. It has all the bells and whistles of
         | the CLI, but you can actually see and understand what's going
         | on.
         | 
         | As a Junior Engineer, a Senior Engineer recommended it to me. I
         | thought he was joking at first, but he kindly reminded me that
         | using a GUI app is completely fine and okay. We shouldn't
         | stigmatise tools that make it easier to use and understand your
         | workflow. GitHub desktop allows me to see what i'm committing,
         | commit history and much more. I'd definitely recommend it.
         | 
         | PS. Using it is not an excuse not to learn how to use the CLI.
         | Others will accuse me of being lazy and not learning best
         | practice. Learn both. Use the easier one.
        
           | matkoniecz wrote:
           | > It has all the bells and whistles of the CLI
           | 
           | Somehow I strongly doubt it. Does it have at least access to
           | cherry picking, reflog and rebasing?
        
             | burkaman wrote:
             | Yes you can rebase, and drag-and-drop commits to cherry-
             | pick. Not sure about reflog, but I think the visual
             | interface sort of replaces some of the need for it.
        
           | RadiozRadioz wrote:
           | The reason people on here tend to dislike those types of
           | tools is because they've probably been the ones who had to
           | fix the tangles people get themselves into by using those
           | tools. Tools that obscure details in favor of simplicity are
           | fine in some cases, but version control is an inherently
           | complex problem domain where having those details is
           | important.
           | 
           | In my experience mentoring juniors new to git, those who are
           | just given a few basic commands don't create as much of a
           | mess because they don't have the commands required to make a
           | big mess. When they do make a mess, it's usually because
           | they've copy-pasted something from the internet, and most
           | will acknowledge that blind copy-pasting _feels_ wrong. Give
           | them a GUI, and suddenly there are buttons to create all
           | sorts of unholy mangles right at their fingertips.
           | 
           | As a really simple example, one of the most frequent things I
           | see from juniors using git GUIs is adding files to a commit
           | that they didn't intend to (say stuff that's not in the
           | .gitignore, but doesn't belong in the commit). In the CLI,
           | they probably don't know about -a, so they would be forced to
           | add files/directories individually and think about what to
           | include. Most GUIs I've seen include a "Stage All" button
           | front-and-center, which is very tempting for a new user to
           | click (or, worse, they make staging an opt-out thing). I do
           | not know if this specific example is the case in GitHub
           | Desktop, it's something that I see regularly.
           | 
           | I agree with your last point. I think git GUIs are best for
           | users who already know what they're doing and find that a GUI
           | speeds up their workflow.
        
             | dullcrisp wrote:
             | > they probably don't know about -a
             | 
             | How are you going to keep them from learning about -a?
        
               | xmprt wrote:
               | When I first learned git, I had no idea what staging
               | meant and the differences between A, M, D, R, AM, etc...
               | 
               | Only some time later (albeit a short time) I learned
               | about -a, at which point I had a bit more understanding
               | of the statuses and what it meant to stage a change. If
               | you gave me -a before that, I would have never understood
               | those things properly.
        
             | OkayPhysicist wrote:
             | You didn't mention the fact that the GUI tools often lack
             | functionality that's present in the CLI. Like git notes
             | (looking at you, GitHub, who previously HAD notes support,
             | but dropped it) or worktrees (Sourcetree lets you view
             | worktrees, but provides no interface for interacting with
             | them as worktrees, rather than just another repo). Or they
             | hide basic functionality, like git ammend, or give less
             | useful error handling advice than git itself (Sourcetree, I
             | love your commit graph, but your error messages are
             | worthless).
        
             | squeaky-clean wrote:
             | git add .        git commit -m ""
             | 
             | Are like the first 2 got commands anyone tends to learn
             | after git init or clone
        
             | make3 wrote:
             | the other thing is that this likely doesn't work over ssh
        
               | sdiacom wrote:
               | It does. GitHub has been soft-deprecating HTTP for years
               | now.
        
             | __blockcipher__ wrote:
             | > As a really simple example, one of the most frequent
             | things I see from juniors using git GUIs is adding files to
             | a commit that they didn't intend to (say stuff that's not
             | in the .gitignore, but doesn't belong in the commit). In
             | the CLI, they probably don't know about -a, so they would
             | be forced to add files/directories individually and think
             | about what to include. Most GUIs I've seen include a "Stage
             | All" button front-and-center, which is very tempting for a
             | new user to click (or, worse, they make staging an opt-out
             | thing). I do not know if this specific example is the case
             | in GitHub Desktop, it's something that I see regularly.
             | 
             | I agree with your general point, but on this specific point
             | I'd be remiss if I didn't mention that I see an insane
             | amount of people regularly use `git add .` to add every
             | file, because they don't realize they actually want `git
             | add -u` (only add already-tracked files) 99% of the time.
             | 
             | But as a counterpoint, since your example is about giving
             | devs a limited set of commands, you naturally wouldn't be
             | giving them `git add .`. But it's definitely something that
             | frequently comes up in crappy git tutorials.
        
           | ezfe wrote:
           | Sublime Merge here, love it and won't go near the CLI anymore
        
             | tylerscott wrote:
             | Seconding Sublime Merge. I've been using it since it was
             | launched and it has been a solid tool.
        
           | jamisonbryant wrote:
           | > Learn both. Use the easier one.
           | 
           | This is a great point that I will be sharing with my team.
           | Sometimes (most of the time) I use the git cli, and sometimes
           | I use the built-in Git pane in VS Code.
           | 
           | I have not used GitHub Desktop in quite a while. In your
           | opinion does it make the commit graph easy-to-read? Because I
           | have not found a tool _yet_ that makes that diagram easily
           | parseable by the human eye. It just looks like a mountain of
           | spaghetti commits linked together with a myriad of colored
           | lines.
           | 
           | (I realize that part of the cause of my confusion is crappy
           | discipline around commit history, but what can you do on a
           | team of a certain size where you're not the lead? Just have
           | to suck it up.)
        
             | nevada_scout wrote:
             | Github Desktop doesn't have a commit graph. It only shows a
             | list of commits for a selected branch.
        
               | kyawzazaw wrote:
               | SourceTree does well in this regard.
        
       | daneel_w wrote:
       | I'm incredibly thankful that 99% of my Git usage at work gets
       | away with just PULL, CHECKOUT [-b], COMMIT [--amend] and PUSH.
       | Rarely do I need to rebase, for any reason.
        
         | Shacklz wrote:
         | I understand the sentiment, but since git is probably one of
         | the longer-lasting constants in our industry (if not _the_
         | longest-lasting constant), I personally think it 's really
         | worth to have a bit of a look into it.
         | 
         | Something I wish someone suggested to me years ago: Instead of
         | trying to understand the commands, try to understand the
         | datamodel. A branch is just a pointer to a commit, a commit is
         | just a pointer (with metadata) to a tree, a tree is just... and
         | so on. Once you understood this (which really isn't any harder
         | than, say, understanding how quick-sort works), going from the
         | data-model to the commands is fairly easy, almost intuitive if
         | it weren't for all the convoluted options that each command can
         | take.
         | 
         | Anyway, not trying to convince you or anything, just saying
         | that I've been in your place a few years back, and wish I'd
         | realized earlier how easy it actually is.
        
           | daneel_w wrote:
           | You have misunderstood. It's not a case of not knowing more
           | about Git and its toolset. It's about our underlying
           | workflow, letting us do version control of our software with
           | simple means instead of throwing everything at it. It's
           | _easy_ to throw a hammer, mallet, pein and a club all at once
           | on a nail, but that doesn 't mean it's necessary or helpful.
        
           | theptip wrote:
           | Agreed, once you grok the start/end semantics of rebase it is
           | not hard to work with. But it can be intimidating for new
           | users.
           | 
           | I actually think it is easier to teach the fully-specified
           | and interactive form 'git rebase -i start-sha-a end-branch-b
           | ---onto target-c' which makes it really explicit what is
           | going on ("snip from A to B and put that chain on C"). When
           | you understand that you can start using the defaults that
           | abbreviate the common cases. (Specifically "end-branch-b" is
           | usually not needed since you usually run the command from
           | that branch.) And getting to this level of grokking requires
           | you to understand the data model mentioned above, but not any
           | obscure internals, so I think it is a good bar for "knows
           | enough of git" for senior engineers in most orgs.
        
         | cnity wrote:
         | I mentally categorise `commit --amend` right there next to
         | rebase personally. When people debate about rebasing and
         | rewrite of history, I include `--amend`. Maybe I'm unique there
         | though.
        
           | daneel_w wrote:
           | I personally separate that particular type of
           | revisioning/amending of history (e.g. someone overwriting
           | some WIP commit over and over on their work branch) from
           | rebasing, which to me primarily means reconciling with
           | changes elsewhere in a different branch - figuratively
           | _rebasing_ the changes from over there to here.
        
           | RadiozRadioz wrote:
           | The "is it rewriting history?" boundary for me is whether
           | you're amending a local commit or one that exists on the
           | remote.
        
       | ok_dad wrote:
       | --force-with-lease can be a footgun.
       | 
       | It will overwrite the tree on remote as long as remote hasn't
       | changed since you last fetched it. It doesn't always work,
       | particularly if you have a tool which continuously fetches
       | remote, like an IDE configured to do so such as VSCode. In that
       | case, you will have fetched the other person's changes, and
       | --force-with-lease will happily blow-away anything on remote that
       | might not be in your tree yet.
        
         | js2 wrote:
         | From https://git-scm.com/docs/git-push
         | 
         | A general note on safety: supplying this option without an
         | expected value, i.e. as --force-with-lease or --force-with-
         | lease=<refname> interacts very badly with anything that
         | implicitly runs git fetch on the remote to be pushed to in the
         | background, e.g. git fetch origin on your repository in a
         | cronjob.
         | 
         | The protection it offers over --force is ensuring that
         | subsequent changes your work wasn't based on aren't clobbered,
         | but this is trivially defeated if some background process is
         | updating refs in the background. We don't have anything except
         | the remote tracking info to go by as a heuristic for refs
         | you're expected to have seen & are willing to clobber.
         | 
         | If your editor or some other system is running git fetch in the
         | background for you a way to mitigate this is to simply set up
         | another remote:                   git remote add origin-push
         | $(git config remote.origin.url)         git fetch origin-push
         | 
         | Now when the background process runs git fetch origin the
         | references on origin-push won't be updated, and thus commands
         | like:                  git push --force-with-lease origin-push
         | 
         | Will fail unless you manually run git fetch origin-push. This
         | method is of course entirely defeated by something that runs
         | git fetch --all, in that case you'd need to either disable it
         | or do something more tedious like:                   git fetch
         | # update 'master' from remote         git tag base master    #
         | mark our base point         git rebase -i master   # rewrite
         | some commits         git push --force-with-lease=master:base
         | master:master
         | 
         | I.e. create a base tag for versions of the upstream code that
         | you've seen and are willing to overwrite, then rewrite history,
         | and finally force push changes to master if the remote version
         | is still at base, regardless of what your local
         | remotes/origin/master has been updated to in the background.
         | 
         | Alternatively, specifying --force-if-includes as an ancillary
         | option along with --force-with-lease[=<refname>] (i.e., without
         | saying what exact commit the ref on the remote side must be
         | pointing at, or which refs on the remote side are being
         | protected) at the time of "push" will verify if updates from
         | the remote-tracking refs that may have been implicitly updated
         | in the background are integrated locally before allowing a
         | forced update.
        
           | Noumenon72 wrote:
           | The existence of such a complicated workaround mainly serves
           | as an official confirmation that you should just turn off
           | auto fetch or not use force-with-lease. I use PyCharm's
           | Update Project to fetch all branches at once on demand, so I
           | will always get anyone's changes to my branch at the same
           | time I fetch.
        
         | eru wrote:
         | Yes, but it's still better than --force under most
         | circumstances.
        
           | blowski wrote:
           | Why use force at all, on a default command?
        
             | skrtskrt wrote:
             | my flow is (on my-branch with no one else's commits)
             | 
             | * push some commits up to my remote branch
             | 
             | * git fetch
             | 
             | * git rebase master/main to get the latest stuff
             | 
             | * add changes on my-branch that use new stuff from
             | master/main
             | 
             | * git push --force-with-lease to my remote branch - this
             | fails if you don't use some version of force since my most
             | recent commit is based on a commit (from master) not on the
             | remote branch
        
               | G3rn0ti wrote:
               | I don't get why everybody wants to rebase their topic
               | branches. Just use merge, come on. If you want a ,,clean"
               | commit history on main/master do a squashed merge into
               | main at the end.
               | 
               | This way we never had to force anything on the remote.
        
               | ok_dad wrote:
               | I rebase on my topic branches because then my edits are
               | neatly stacked on top of the other branch, so I can re-
               | arrange things more easily. Why would I want a weird
               | commit with a bunch of work I didn't do on the topic just
               | smooshed into the middle of my well-crafted series of
               | commits?
        
               | mixmastamyk wrote:
               | Work you didn't do won't be in your branch. There is no
               | rearranging, it is one commit.
        
               | aulin wrote:
               | Why would you have to force anything with rebase? you
               | rebase your feature branch against main to rewind it on
               | top of it and clean up history so you can do a clean fast
               | forward merge. Squashing is bad for anything non trivial,
               | you want small independent commits: easy to review, easy
               | to revert, easy to blame if something goes wrong.
        
               | G3rn0ti wrote:
               | As soon as you pushed your branch to remote (which I tend
               | to do for backup reasons especially after working hard on
               | a solution) rebase only means trouble.
        
               | aulin wrote:
               | if you're the only one working on that branch I don't see
               | where is the problem in rewriting history and force
               | pushing
        
               | mixmastamyk wrote:
               | Until you make a mistake.
        
               | __blockcipher__ wrote:
               | Not if it's the remote for your own dev branch. It only
               | matters if the remote branch is being (actively) used by
               | other people.
               | 
               | Unfortunately I've met far too many who have your
               | "remote" superstition. I remember arguing this exact
               | point in my last gig, when someone was mad at me for
               | force pushing my own remote branch that nobody else was
               | using nor should have been.
        
               | npc12345 wrote:
        
           | smaudet wrote:
           | The implication with anything with '--force' in it, is you
           | shouldn't be doing it without _talking to someone_ first.
           | 
           | Absolutely does not belong in automatic anything, anywhere.
        
             | eru wrote:
             | Oh, obviously you need to know what you are doing.
             | 
             | I mostly use --force-with-lease to push something to my own
             | branches. No need to talk to anyone.
             | 
             | Force pushing to other people's branches without asking is
             | just rude.
        
       | fedeb95 wrote:
       | This can be fine in two scenarios: - solo dev - enforcing its use
       | in your company
       | 
       | Otherwise big messes will inevitably arise. In the second case,
       | new people with their (correct) git workflow will suffer.
        
       | MichaelCollins wrote:
       | Missed opportunity to title this "Git Proof Git"
        
       | jarek83 wrote:
       | Why use risky rebase while you can just squash all into one
       | commit and push it via intermediate branch (something that Github
       | does as an option)? I prefer to be worry free than always be
       | ready for someone screwing up a branch.
        
         | Arelius wrote:
         | To be fair, squash is a form of rebase.
        
         | anonuser123456 wrote:
         | Why do you feel rebase is risky?
        
       | prepend wrote:
       | I just never rebase. Am I missing out? It seems the only major
       | advantage is to reduce the number of items in the history and
       | that doesn't seem very important to me.
        
         | __blockcipher__ wrote:
         | Yes, you're missing out. Rebasing isn't about reducing the
         | number of items in history, although it can do that too. It's
         | about having a sane, readable history.
         | 
         | If you write two commits in your local feature branch, then
         | pull master in and generate an ugly merge commit, and then
         | stack two more commits on top to your local feature branch, and
         | then finally get all that mess merged to master, you have a
         | difficult to read history because of the merge commit randomly
         | in the middle. Whereas if you instead rebase onto origin/master
         | (after fetching of course), you get a nice history where your
         | feature branch commits are cleanly on top of origin/master, so
         | there's no crazy merge commits in the middle.
         | 
         | Most people just use git as a fancy save button, and therefore
         | never actually use the git log / git blame to answer questions
         | about why some part of the codebase is the way it is, and
         | therefore they never realize why their merge commit insanity is
         | so destructive to the usability of the git log.
        
         | jcon321 wrote:
         | For a 1 man team there is no point. Even for a 1 man team with
         | a local and remote repo there is no point, because your local
         | branch is always the same as the remote branch.
         | 
         | For a 2+ man team that does not protect the remote repo (i.e.,
         | don't require merge/pull requests, and you can commit/push
         | directly into remote branches), then there is no point
         | because... When you go to push a branch and remote complains
         | about changes existing on remote, so you must pull first. You
         | issue a pull and that does a fetch/merge into your local
         | (commits are overlaid in order by date committed - some people
         | complain about this and is why they rebase (commits from remote
         | are back filled, and then your commits are inserted)).
         | 
         | For a 2+ man team that does protect the remote repo, and does
         | require merge/pull requests then an explicit rebase or merge is
         | needed, sometimes. At the end of the day you should be creating
         | a merge/pull request from a source branch that has all of the
         | changes as the remote target (at that point in time) to help
         | the reviewer/approval only see your changes. If you updated
         | your local branch via a rebase then the commits related to your
         | changes are all in order, if you updated your local branch via
         | a merge then the commits related to your changes are interlaid
         | between other commits that happened around the same date). But
         | really that's only a problem if someone cares to use git-log
         | and not the 100 other ways to review history.
        
         | Arelius wrote:
         | No, your not missing out... I mean, it's a powerful tool, and
         | like any tool, learning to use them can be helpful. Having said
         | that, rebase is a tool that I find myself compelled to use more
         | often than I feel it's actually useful to use.
        
       | Sverigevader wrote:
       | Nice page! Very well made and great explanations. However; I'm a
       | big fan of aliases in git, but I don't think this is the way to
       | go personally. Knowing the difference between rebase and merge is
       | vital, and I think it's worth the time investment to learn git
       | properly.
       | 
       | It took me 1 month of painstakingly learning the git CLI and I'm
       | happy I spent the time. Before that I was using a GUI and was
       | essentially afraid of git.
       | 
       | I'm no longer afraid. Instead I'm actively exploring ways to do
       | things faster and/or smarter every day.
       | 
       | This happened when I switched jobs recently and came into contact
       | with a fantastic developer and patient teacher. Doing it myself
       | would have taken a bit longer and I wouldn't be able to see how
       | much it would be worth it.
       | 
       | I'm enjoying a rebase workflow everyday. And I especially like
       | the -i flag for interactive rebasing;                 git rebase
       | -i
       | 
       | Same with -p for interactively adding code/files before commits
       | git add -p
       | 
       | I read the first three chapters of the git-scm book[0] and it
       | made a world of difference in understanding what's actually going
       | on.
       | 
       | [0] https://git-scm.com/book/en/v2
        
       | agentwiggles wrote:
       | I guess this will come off kinda... douchey? But I just don't
       | find Git to be that hard. I know there's a lot of complexity
       | there, but I find that 95% of the time I'm just git add -p or git
       | add . and then committing. Every once in a while I'll do a
       | rebase, and that's the most complex part of Git that I use with
       | any frequency.
       | 
       | I remember when I first was introduced to Git I found it
       | confusing, so I'm sympathetic to newbies who have to cross over
       | the learning curve, but I think the main day-to-day Git
       | operations just aren't that much to learn. What is it about Git
       | that people find so difficult, even after using it for a while?
        
         | squeaky-clean wrote:
         | 95% of hit usage is fairly easy, yeah. But that other 5% can be
         | extremely difficult.
        
         | randomsearch wrote:
         | The UI is inconsistent and unintuitive.
        
           | agentwiggles wrote:
           | I won't disagree with that, but idk. Once you understand the
           | basic operations everything weird is a Google away.
           | 
           | I'll admit that Git is the only VCS I've spent any time with,
           | so maybe I just don't know how much better it could be. But
           | I've almost never had an issue with Git where I actually lost
           | code. And anytime I'm doing something dangerous, I just make
           | a backup copy of the directory in case I screw up
           | irrevocably. But even if I'm doing something nasty, the
           | reflog is there, and the cases where I've need to use my
           | backup copy are very few and far between.
        
             | IshKebab wrote:
             | > Once you understand the basic operations everything weird
             | is a Google away.
             | 
             | Yes that's true, but what you've probably forgotten is that
             | _understanding the basic operations_ is way way harder than
             | it should be thanks to Git 's terrible CLI, nomenclature
             | and general UX.
             | 
             | I would also argue that the lack of an obviously good GUI
             | makes it quite a lot harder for beginners, and the attitude
             | that a lot of HN commenters have that you _shouldn 't_ use
             | a GUI, despite Git being an obviously visual thing.
             | 
             | Btw any beginners reading this, I would recommend Git
             | Extensions. Terrible name which led to me not trying it for
             | ages, but it's actually one of the best. In particular it
             | lets you browse the repo at every commit which is something
             | that makes it way clearer what Git is doing.
        
             | jfk13 wrote:
             | > almost never ... actually lost code
             | 
             | That seems like one of the absolute basics. "Almost"
             | never...?
             | 
             | > I just make a backup copy of the directory in case I
             | screw up irrevocably
             | 
             | If you really felt you could trust your source control
             | system, that shouldn't be needed, and...
             | 
             | > the cases where I've need to use my backup copy
             | 
             | ...should be nonexistent.
        
           | eru wrote:
           | That's true. But they are working on this. Slowly.
           | 
           | Eg compare https://git-scm.com/docs/git-switch to git
           | checkout.
           | 
           | https://www.infoq.com/news/2019/08/git-2-23-switch-restore/
        
         | softwaredoug wrote:
         | I don't find it _hard_, but it is very _unopinionated_
         | 
         | So if you mix up one kind of workflow with another, you can
         | really shoot yourself in the foot. There's people that have a
         | merge-based workflow, a rebase-based one, more advanced
         | projects (Linux kernel) have something more bespoke. Getting
         | used to one project, then using those practices in another, can
         | really mess you up.
        
         | opsy_ wrote:
         | I think (from working with git newbies) the core difficulty is
         | not understanding the Git's fundamental data structure. If you
         | have computer science training / data structure understanding,
         | once you realize (1) Commits are nodes in a graph (2) branches
         | are just pointers to a specific node, you're off to the races.
         | 
         | From there, I find it straightforward to conceptualize all the
         | different commands. Commit/push/reset/merge/pull/rebase/etc are
         | all just different graph manipulations. There's usually
         | multiple ways to achieve the end graph you want.
         | 
         | If you don't understand the data structure, you have no good
         | mental model and it's just a series of ritual. If something
         | goes off the ritual path, you're in trouble.
        
       | coding123 wrote:
       | I love git, but I have to be honest about one thing: It's
       | definitely hard on purpose and introduces hard on purpose
       | features (and naming conventions) to weed out people.
       | 
       | rebasing and squashing and tracked/untracked. Yes they all have a
       | place, but has anyone noticed with SVN it's just commit, merge
       | and branches.
       | 
       | Would it be impossible to make git with svn's UI?
        
         | Arelius wrote:
         | Yes, svn hides and pushes most of the complexity to the users
         | workspace, and just gives up when any sort of complexity
         | happens.
         | 
         | Git could clearly be improved, but much of sun's ease is due to
         | hiding the complexity of development.
        
       | danwee wrote:
       | Git commit crafting (and rebase to achieve it) is overrated. If
       | you care about crafting beautiful series of commits so that the
       | future readers understands what's going on: don't. Context is
       | more useful to find out why something changed. Example:
       | 
       | - you build feature F that is touching N files and M lines of
       | code
       | 
       | - you craft your git commits so that each of them is atomic and
       | "understandable" on its own
       | 
       | - now if I want to see the context of change for line X, I won't
       | get the changes in all the N files... I'll get your crafted
       | commit that updates only line X (worste case) or its immediate
       | surroundings (best case). But how do I get the full context
       | (i.e., this line is about feature F)? I have to git blame lines
       | around line X and see if I can actually make a picture of the
       | bigger feature. Examples of feature F: a whole new http endpoint
       | touching controllers, services, data access models, middleware.
       | What do you get when people craft their commits? 1 commit for the
       | controller, 1 commit for the service, 1 commit for the data
       | access model, etc. Zero context. Time wasted for the reader
        
         | jrochkind1 wrote:
         | But I've most often seen rebase used, as in OP, to squash
         | multiple commits into ONE commit that covers the feature that
         | was added.
         | 
         | I feel like the outcome of rebase used there is to give you
         | what you are asking for, and without rebase you wouldn't be
         | getting it?
         | 
         | (I have very mixed feelings toward rebase, myself)
        
           | prepend wrote:
           | Why does this matter? I can just diff from the first commit
           | before to some point if I really want to see it all wrapped
           | up.
           | 
           | It seems like lots of work that almost always does not
           | matter.
           | 
           | I don't think git is a good project management system. If I
           | want easy to read stuff I can look at the release notes or
           | tag notes or whatnot.
        
         | cnity wrote:
         | > commit crafting is overrated.
         | 
         | For you, in your use case. When I look at my neat history and
         | use git bisect, I get plenty of value out of it.
         | 
         | People keep telling me to stop rebasing. I keep ignoring them;
         | nothing new here.
        
           | cube2222 wrote:
           | This is basically solved by squashing each PR on merge and
           | having a good PR title + description.
        
             | theonething wrote:
             | This is my habit and I advocate for it on new teams. It's
             | so simple and effective. Why make it complicated?
        
             | hardolaf wrote:
             | This is exactly what we do at my job. The only time it ever
             | causes issues with some things is when we're ramping up a
             | new project and the PR and ticket titles don't necessarily
             | match the work we've done. But that's more of a problem
             | where we could make everything bite-sized, or we can
             | deliver complete packages in terms of a feature plus all of
             | the miscellaneous changes that we needed to make along the
             | way to make it work. Now, is this the best way to do
             | things? No, you should ideally make those changes
             | separately and push each one separately. But that slows
             | down progress.
        
             | aulin wrote:
             | why would you squash multiple informative commits with
             | their commit messages and their informative context about
             | your thought process into a single big squashed commit? git
             | can merge branches and keep track of it, there is no need
             | to squash unless you split trivial changes that belong
             | together and want to group them before sharing them
        
               | theonething wrote:
               | > no need to squash unless you split trivial changes that
               | belong together
               | 
               | If a PR represents a distinct product feature/bug
               | fix/unit of work, one could argue that its commits belong
               | together.
               | 
               | Squashing makes for a very clean history. True it reduces
               | granularity, but in my opinion at least, it's a good
               | level of granularity.
               | 
               | The exception to this would be a really big PR. That's a
               | reason to avoid huge PRs.
        
             | ajorgensen wrote:
             | But why not do both? I find that nice commit messages make
             | it easier on the review to see whats going on rather than a
             | bunch of wip commits. Then squash all of the commits into a
             | single commit with a nice title and message. The benefits
             | of the squash at the end are, assuming you require tests
             | pass before merge, you have a history of commits all with
             | passing builds which makes bisect possible.
        
               | mixmastamyk wrote:
               | Wouldn't the cleanup work be lost in the squash?
        
         | montebicyclelo wrote:
         | For a nice record of history - rather than squashing all of the
         | smaller commits into a single commit for a given feature, and
         | then rebasing (which makes it less easy to have small commits
         | with specific explanations that add together to create a
         | feature), something like semantic-release [1] could be used,
         | which autogenerates release notes based on commit messages.
         | 
         | [1] https://github.com/semantic-release/semantic-release
        
         | theptip wrote:
         | I think you are arguing against an extreme version of the
         | practice.
         | 
         | Normal advice is to shoot for 100-200 lines in a commit, not
         | split that into ten commits that each change 15 lines.
         | 
         | If someone is splitting 100-line commits into 10-line commits,
         | I would advise not doing that.
         | 
         | However the direction that people normally err (IME) is
         | submitting 500-2000-line commits which conflate multiple atomic
         | changes. I would also advise not doing that.
         | 
         | It's easier to review a sweet-spot commit, and it's easier to
         | understand when you later have to debug/bisect a change set.
         | 
         | Another related concept is to try to split "functional no-op"
         | refactors from behavioral changes. This is usually the first
         | and easiest way of getting your commit size down, as refactors
         | often bloat the diff.
         | 
         | In your example case I'd hope you have UTs exercising each
         | chunk that is added. There are sensible APIs to shape at
         | granularities smaller than the whole feature (model, service,
         | etc) (or should be at least). If you really can't add a new
         | endpoint without a 1k- line PR I think you might need a new
         | abstraction layer. But often you can add a new endpoint in
         | meaningful chunks that are feature-flagged off, if you craft it
         | thoughtfully.
        
           | thfuran wrote:
           | I don't think lines of code is much better an estimate of
           | commit complexity than it is of productivity. I could make a
           | 1,000 line change by changing the signature of something that
           | gets called a lot, but that's essentially atomic. I could
           | make a 200 line change by sightly updating 100 totally
           | unrelated functions and that's probably totally nuts.
        
             | theptip wrote:
             | Sure, it's just a rule of thumb, not a hard requirement. In
             | my experience most functional/behavioral commits benefit
             | from being in the 100-250 line range, and it's more common
             | for engineers to make things too big rather than too small.
             | YMMV.
             | 
             | As you say, non-functional refactors can be bigger while
             | still being readable/comprehensible (but I think it's
             | important to keep them scoped as such, and commit crafting
             | is important for this).
        
         | aulin wrote:
         | If you keep merge commits you can get the full diff at once and
         | see all the context you need, if you don't you can still write
         | meaningful commit messages that identify the feature you're
         | working on so that in the future you can still do a diff
         | between the first and the last commit and see it all at once.
        
           | willio58 wrote:
           | Yeah if you just use commits as they are intended then the
           | complexity of git drops off massively. I've used got for a
           | decade and want to know how many times I've rebased? Zero
        
             | aulin wrote:
             | I tend to stage everything I do in my local branches,
             | experiments, hacks, partial changes I don't have time to
             | finish right now, unfinished refactorings. No way I share
             | that without rebasing it and cleaning it up first.
        
             | __blockcipher__ wrote:
             | I am deeply suspicious of people who claim to have never
             | rebased. I've never met such a person who didn't have
             | absolutely disgusting commits: either (1) no commit body to
             | explain the context of why a chance was made, for patches
             | that clearly needed one, (2) random merge commits in the
             | middle of the actual commits because they don't know any
             | workflow besides merging master into their ongoing dev
             | branch, or (3) massive pull requests (if using a pull
             | request workflow) that touch 30 files and implement way
             | more than just the feature the branch was supposed to be
             | for.
             | 
             | It's also a big sign to me that the person probably rarely
             | if ever actually spelunks through the git log to understand
             | why a certain change was made. Because if one does, they
             | very quickly discover why a workflow involving sane
             | rebasing onto origin/master produces such a better history.
             | 
             | There's times when merge commits are appropriate, but they
             | are few and far between compared to the endless abuses of
             | merge commits by people who don't understand git in the
             | slightest (my definition of "don't understand git" is
             | someone who can't visualize the DAG)
        
             | mook wrote:
             | Isn't commits as they are intended a patch queue in email
             | with a cover letter (0/n commit)? At least, that seemed to
             | be how the Linux kernel works.
        
             | lelandfe wrote:
             | 10 years of typos in commit messages
        
         | stnmtn wrote:
         | Agreed. The first and last place I look at when doing a git
         | blame is the PR that the commit was in. That contains all the
         | useful information for me, as well as much-needed context
         | around review comments, discussion, etc that is not able to
         | find in native git.
        
           | lelandfe wrote:
           | Pull requests vanish when repos change hands.
           | 
           | If you leave unique information in PRs, that information may
           | be lost in the future. This has happened to me at 3 different
           | companies now, where we inherited another company's code
           | base.
           | 
           | Keeping commits self-contained is the only way to future
           | proof your explanations.
        
             | s4i wrote:
             | It would be great if GitHub (not sure about GitLab, Gitea,
             | etc) included the title and the description of the PR
             | (maybe up to a certain character limit) in the merge commit
             | when you merge the PR. This would be at least a minimal
             | level of backup for the PRs but it would also prevent
             | common scenario for me where I need to switch to the
             | browser from `git log` just to remind what the heck this
             | one PR was about again.
        
             | aulin wrote:
             | Also PRs belong to the review and CI system, everything
             | needed to understand the code and its history should be
             | staged in version control
        
               | darkwater wrote:
               | I agree and this sounds super neat but in reality it's
               | pretty complicated to keep that boundary and not leak
               | info from one side to the other. I mean, when you open a
               | PR you will probably describe the rationale for the
               | change and why you had to touch files A,B & C (if it's
               | not obvious). You can and you should replicate that info
               | in a multi-line commit message but sometimes through code
               | review you reshape the code structure or even some of the
               | requirements (most probably because there was some
               | initial misunderstanding). So, since we are humans, it's
               | normal to take shortcuts when we did already "a good
               | enough job" and leave out those small details.
               | 
               | Anyway I agree that we should aim at this: PRs are in the
               | CI/review land, why a commit is like it is, should go
               | into VC.
        
             | t43562 wrote:
             | IMO one should maintain a CHANGES.md file with whatever you
             | would be putting in the PR description in it. There's no
             | specific need to squash commits to do this as long as you
             | create it just before you create the PR. Even the odd
             | bugfix or review comment after that is no big deal.
        
               | lelandfe wrote:
               | I don't see the advantage of doing this over ensuring the
               | commits stay atomic, and I see several disadvantages.
               | 
               | Namely, git conflicts will happen constantly; and the
               | file size will graduate from unwieldy to unusable over
               | time. One repo I work on has >45,000 PRs merged. Good
               | luck even opening that file.
               | 
               | This approach also poses risk: people will forget to add
               | to it.
        
       | palata wrote:
       | I think people mostly don't care, but I personally sign my
       | commits.
       | 
       | And if you rebase, you lose the signature (well, maybe the person
       | rebasing re-signs it). But then it means that my commits are not
       | signed by me anymore.
       | 
       | Feels like an interesting point against rebase workflows to me,
       | but nobody mentioned it, so maybe it's just me.
        
       | MetaWhirledPeas wrote:
       | I understand _generally_ what Git is doing, but when you start
       | throwing in very specific words like  "rebase" my eyes start to
       | glaze over. Not because they aren't important concepts, but
       | because I can't stop the nagging feeling that _it shouldn 't be
       | this complicated_ (it probably should though).
       | 
       | But it isn't complicated! When you use a decent UI tool. I know
       | pretty much exactly how VSCode's UI behaves with Git, along with
       | the Git History plugin. And now I have a perfectly usable
       | workflow and never have to use the command line, and almost never
       | have any merge conflicts.
       | 
       | Maybe this is common knowledge to all of you, but it seems to me
       | a lot of people have Git headaches, so maybe they don't know
       | this?
       | 
       | 1. Pull latest from remote main branch (select the branch, hit
       | the sync button; permissions structure prevents any accidental
       | pushes)
       | 
       | 2. Create new branch based on pulled branch. If I have stashed
       | work, apply it now.
       | 
       | 3. Do work
       | 
       | 4. Use the + icon to stage individual changes and give them their
       | own local commit
       | 
       | 5. Push my local branch to remote (hit that sync button again)
       | 
       | 6. In my remote repo UI push the button to create a Pull Request
       | (I assume all shared repos have a PR button somewhere?)
       | 
       | 7. Go back to doing local work, but _don 't commit yet_, and
       | continue "not committing" for now
       | 
       | 8. After the PR has been merged into main, stash everything
       | including untracked (pick it from the VSCode menu)
       | 
       | 9. Go back to step 1, repeat
       | 
       | Steps 7 and 8 are how you avoid creating your own merge
       | conflicts. If you keep committing while a PR is in flight, then
       | later on Git will see your earlier changes to a file, and your
       | later changes to the same file, and will see them as a conflict.
       | So just do yourself a favor and never commit to a branch while
       | anything in its history is part of an in-flight PR. Obviously
       | you'll have to deal with merge conflicts with _other_ people but
       | at least you aren 't creating your own headache.
       | 
       | Git History saves me when I goof up and commit locally when I
       | shouldn't. I just pull up the history and click the soft reset
       | button prior to my commit and presto, I'm back where I want to be
       | (files uncommitted, back in pending changes list).
       | 
       | Maybe one day I'll learn the Git command line, but right now why
       | bother?
        
         | blep_ wrote:
         | Stash -> pull -> unstash is just manual rebase, though. You're
         | already doing the thing you're claiming not to do, you're just
         | doing it the hard way.
         | 
         | Which is fine, if that works for you! Just know that you're
         | using different terms for the same thing (do some work on top
         | of A, then move it to be on top of B instead).
        
           | MetaWhirledPeas wrote:
           | Now you've piqued my interest.
        
             | OkayPhysicist wrote:
             | Not the person you replied to, but what a rebase is is
             | taking a series of commits you made to one place, and
             | replaying them on top of another commit. So you make your
             | PR, then branch off of that commit, and continue doing the
             | normal edit-commit workflow on that new branch. Then, when
             | you the PR gets merged, you git rebase -i
             | (master/main/whatever branch your PR was being pulled
             | into).
             | 
             | You'll be presented with all your commits, you can choose
             | to exclude some from the rebase (useful if you had to
             | update something specifically because it gets updated
             | between every PR/build), then commit to the rebase. It will
             | then proceed to replay each commit you made, just like a
             | repeated version of your stash/unstash process, on top of
             | the new top of the master branch. Your working branch is
             | now contains all the changes you made, but instead of
             | working off your PR commit, it's like you were working off
             | of the finished PR commit.
             | 
             | If you want to make sure that your git history maintains
             | the old branch for sentimental reasons (or you want to try
             | out removing some commits and desire an easy way to
             | rollback if you get lost), just make a branch off of your
             | working branch before the rebase. That branch will be
             | identical to the branch you were working on, before the
             | rebase.                                      A---B---C
             | topic                           /        PR Branch P---R---
             | S                             \                     O---L
             | ---D---E master
             | 
             | (where commit D and E are produced as part of the PR, say,
             | the merge commit and a version number crank or something)
             | 
             | (checked out topic) git rebase master                  PR
             | Branch P---R---S       A---B---C topic
             | \     /                    O---L---D---E master
             | 
             | magic
        
               | MetaWhirledPeas wrote:
               | This is an excellent explanation, thank you.
               | 
               | Still, I have questions. When I have topic checked out
               | then run "git rebase -i main" does it first do fetch (or
               | whatever) to make sure main's latest commit history is
               | represented? Or is it up to me to do that first?
               | 
               | The rebase concept is sound, but the semantics are a bit
               | daunting.                 git rebase -i main
               | 
               | This sounds like an operation is being performed on main.
               | Terrifying! And "rebase" is a scary word choice
               | regardless. Perhaps you remember when you were new to Git
               | and can relate.
               | 
               | I may give rebase a try at some point, to see if perhaps
               | it might speed me up. The vast library of Git commands is
               | a bit much for me though. It's like using an aircraft
               | cockpit to control the television!
        
               | qu4z-2 wrote:
               | I definitely sympathise with the confusing and scary
               | command names! "reset" is the worst in my opinion. Rebase
               | is kind of the natural choice once you understand the
               | data model, but it doesn't necessarily make it more
               | approachable.
               | 
               | `git rebase main` will modify your currently checked out
               | branch to make the commits on that branch now branch off
               | of the current value of main. It won't update main or
               | modify it in any other way, only your current branch. You
               | can equally `git rebase 347ae9` to have them come off a
               | specific commit.
               | 
               | If you know what a tree is (in the general computer
               | science sense, not the git term of art) it's well worth
               | taking a little time to learn the underlying data model
               | in my opinion.
        
               | MetaWhirledPeas wrote:
               | Thanks, that's useful information!
        
       | nerdponx wrote:
       | Ugh, that `pr` alias gives me shivers. Just write a standalone
       | script that you distribute to teammates! You don't get extra
       | points for jamming it all into a single string in a config file.
        
       | corytheboyd wrote:
       | Aliases don't make git easier to understand, they make one
       | specific git command require typing fewer characters to run.
       | 
       | I am not against making aliases, but just saying, if you don't
       | have an understanding of the commands they run, you'll still one
       | day be in a state you don't know how to fix, and THAT is when
       | people "lose their code" etc.
       | 
       | You use git every day, it's worth learning and understanding. You
       | don't need to be a pro, but you need to be good enough.
        
         | throwaw20221107 wrote:
         | The only reason people lose code is because
         | 
         | 1. they didn't read this one diagram: https://git-
         | scm.com/book/en/v2/Git-Basics-Recording-Changes-...
         | 
         | 2. And then they run `reset --hard`
        
       | js2 wrote:
       | [deleted]
        
         | wruza wrote:
         | Doesn't happen ime. I understand how it works (more or less)
         | and still struggle with its CLI. It was created by aliens with
         | photographic memory and non-associative thinking.
         | 
         | Maybe you can point to a git test/quiz that doesn't ask stupid
         | trivialities 9 times out of 10? In case I have to "understand"
         | it more, would be nice to pass some informal certification at
         | least.
        
       | ilovecaching wrote:
       | Rebase (non-local rebase) based workflows are just awful. The
       | best git methodology I've seen is (surprise, surprise) in the
       | Linux kernel. I can keep everyones tree as a separate tracking
       | branch and use git work trees to develop against multiple
       | branches on the same system. I also really enjoy using git
       | request-pull, send-email, etc. and I think Github has been
       | actively harmful in teaching people bad git habits.
        
         | account42 wrote:
         | Rebasing remote feature branches after feedback in the github-
         | pull-request workflow is analogous to re-sending and updated
         | patch series in the email workflow.
         | 
         | The distinction shouldn't be if its remote or not but if its
         | something "published" that others might build their work upon.
        
         | sigmonsays wrote:
         | any pointers on where to start for request-pull, send-email,
         | etc. Ie, the linux kernel flow?
         | 
         | Everything is a PR these days in github, so perhaps we find a
         | way to do this with github.
        
           | svmhdvn wrote:
           | A really good guide to learning this is https://git-send-
           | email.io/.
        
           | tsegers wrote:
           | Sourcehut's tutorial on send-email is pretty good:
           | https://git-send-email.io/
        
       | alexb_ wrote:
       | What's the deal with squashing commits anyways? I'm genuinely
       | asking, because I've only worked with "squash everything before
       | you put it up for review" but have never really figured out why
       | past "it's what we've always done".
        
         | GuB-42 wrote:
         | There are essentially two approaches:
         | 
         | - History is sacred and can't be changed. It typically goes
         | with a merge-based workflow. The good thing is that nothing is
         | lost, what you see is what really happened and you won't make a
         | mess with inappropriate push --force. The downside is that it
         | looks messy since you are going to see every typo and you will
         | have some non functional code in your history. People using
         | that workflow usually don't squash since squashing rewrites
         | history.
         | 
         | - History is like documentation and have to be nice and clean.
         | It typically goes with a rebase-based workflow. This is what
         | the article is about. The good thing is that every commit has
         | working code, and git log can effectively replace a more formal
         | change log. The downside is that you lose information and the
         | git log doesn't represent what really happened, furthermore,
         | since push --force is often used, your local branch may not be
         | the branch you think you are on, you may even end up destroying
         | other people commits. People using this workflow usually squash
         | to make their commits nicer.
         | 
         | I prefer the "history is sacred" workflow myself, but both
         | options are valid.
        
           | __blockcipher__ wrote:
           | It's ironic that the "history is sacred" crowd contains the
           | people least likely to _actually look at and use the git
           | history to aid their contextual understanding of the
           | codebase_. Why do I say that? Well, because once you 've come
           | across a useless typo commit for the 12th time, you start to
           | very quickly see how such commits needlessly bloat the
           | history and make it far harder to understand (and make things
           | like git blame much more unwieldy), while not actually
           | offering any benefit.
           | 
           | It doesn't matter to me at all 3 months later to know that
           | you initially had a typo in your first commit and then fixed
           | it the subsequent commit. That should just be a single
           | commit.
           | 
           | There are some very rare edge cases where having the whole
           | messy history can offer some insight of how a certain mistake
           | ended up being made, but IMO in 999/1000 cases that's not the
           | case.
        
             | GuB-42 wrote:
             | That's why when you use a "history is sacred" approach, you
             | typically have several branches and use merge commits, not
             | rebase.
             | 
             | When you look at the master branches you will mostly see
             | merge commits, all the mess will be on the side, for
             | example in feature branches. Merge commits can be clean,
             | and when you are blaming, you will see the merge commit,
             | not the dozen of typo commits. If you do "git log --first-
             | parent" you will not even see the messy commits, but they
             | will be there if you need them.
        
             | Arelius wrote:
             | Squashing and rebasing don't fix the shitty commit message
             | problem. Discipline and good teamwork do.
             | 
             | All to often in rebase+squash heavy repos I start going
             | through the history and find the mega-commit that
             | introduced a change and gain zero insight. In comparison,
             | merge heavy repos have a lot of merge this, or fix this
             | typo commits, that are fairly easy to skip right over when
             | not pertaining to your actual change, but prove invaluable
             | when the problem was introduced by some weird bad conflict
             | resolution including a typo, or countless other problems
             | where just all context is otherwise lost.
             | 
             | I think it's unfair to characterize one group as not using
             | the history, but instead represent differences in how
             | groups use them. As an archaeologist vs daily change log
             | perhaps is a better characterization?
        
           | kazinator wrote:
           | Projects should rewrite their public history from time to
           | time, for instance to get rid of commits that never should
           | have happened, or move changes between commits, fix commit
           | messages and such.
           | 
           | The history should be treated as the perfect object to
           | develop. We should continuously revise how this program
           | should have been developed to its current state, by what
           | sequence of changes.
        
             | GuB-42 wrote:
             | While I think a rebase workflow where you rewrite the
             | history of _feature_ branches is a reasonable approach,
             | rewriting public history is a big no for me. Maybe it is
             | fine with some version control systems, but certainly not
             | git.
             | 
             | Git is essentially a blockchain, rewriting history is like
             | rolling back a bitcoin transaction, it is impossible
             | without breaking cryptography. Instead, when you rewrite
             | history in git, you actually create a new project to
             | replace the old one. You then have to tell everyone to
             | switch to your "new project", otherwise you will create a
             | lot of confusion and painful merges, if they don't decide
             | to say "fuck you" and keep working with the original
             | history.
             | 
             | Git is decentralized, and to work it needs some consensus,
             | and the consensus is in the history, if you break that, you
             | break the decentralized nature of git. Now, if your don't
             | open your repository to the general public and use git like
             | you would use svn or other centralized systems, it is fine,
             | but don't do that for public repositories.
        
               | kazinator wrote:
               | Rewriting public history is completely fine with git.
               | 
               | Upstream says: "master is now this SHA, deal with it".
               | 
               | Actively developing downstreams can easily rebase their
               | stuff (if any) across non-fastforward changes, and life
               | goes on.
               | 
               | For a pure consumer of a repo, it makes no difference.
               | 
               | There is only the cultural idea that it's a no-no, not a
               | technical idea.
        
         | softwaredoug wrote:
         | I think people will have a branch with like 40 dumb commits
         | like "fix typo" but when you merge it, people don't want to go
         | through all those 40 commits in main. They want to instead read
         | "Refactored frob reactor to use glom framework".
        
           | planede wrote:
           | merge commit with git log --first-parent is alright.
        
         | fs111 wrote:
         | fix typo
         | 
         | yet another typo
         | 
         | test fix
         | 
         | aaah, why is this test failing?
         | 
         | merge foobar/narf
         | 
         | revert foo
         | 
         | foo
         | 
         | Is just not a good history to preserve
        
           | vultour wrote:
           | Boggles my mind how so many people in this thread are against
           | rebasing. Have they never needed to remove these commits? I
           | do that pretty much daily, especially when troubleshooting
           | something in a CI pipeline.
        
             | Zitrax wrote:
             | I prefer rebasing too, but merging doesn't mean that you
             | have to merge in all noisy minor fixups, you can combine
             | the strategies and rebase the feature branch into a set of
             | sensible commits, then merge that branch. Preferably even
             | with a CI that checks each commit before merge such that it
             | will not cause issues later during eventual bisections.
             | --fixup and --autosquash are handy for such workflows.
        
               | __blockcipher__ wrote:
               | Using interactive rebase in that way is a great tool, but
               | we're talking about people that are against rebasing in
               | general, so it's not the most relevant point IMO.
               | 
               | i.e. the anti-rebase people are usually of the "never
               | rebase" flavor. Because they're also the "history is
               | sacred even though I never look at history because if I
               | did I would get dizzy and throw up" crowd :P
        
           | [deleted]
        
         | msingh_5 wrote:
         | So that atomic changes are consolidated in a single commit/PR.
         | 
         | Sometimes, the flow for a single feature A: - commit change AA
         | - commit change AB - fix change in AA - extend AB
         | 
         | In this case, until merged into main/master and to reduce noise
         | for the reviewer (especially if using a code review each commit
         | type process), its best to squash all commits into a single
         | "feature A".
        
         | 3np wrote:
         | So you can get a semantic and useful history before submitting
         | a patch/PR for review (or before merge).
         | 
         | Doing hacky and messy WIP commits is totally fine. Just clean
         | them up before having others read them.
         | 
         | In case you're not aware:                 git rebase
         | --interactive [remote/]ref
        
         | eru wrote:
         | So there's (at least) two uses for commits.
         | 
         | The first is to keep a log of what you are working on. For me,
         | that's lots of small and dumb commits.
         | 
         | The second is to provide a story for review.
         | 
         | Most of the time, when the change you are putting out for
         | review is small and simple, you can just put it all into a
         | single commit.
         | 
         | Sometimes, your change is more complicated and it makes sense
         | to break it into a series of related commits. Along the line of
         | 'first do the refactor that makes the complicated change
         | simple, then make the simple change'.
         | 
         | Your job as an author is to hide the ugly reality of how you
         | actually came up with the change, and present the reviewer a
         | sanitised view of reality. Reviewing code is hard, so it's best
         | to make it as easy as possible.
        
           | wackget wrote:
           | Why wouldn't you use a local branch (or something?) for your
           | ugly commits and then merge everything from that branch into
           | the main shared branch when you're done?
        
             | __blockcipher__ wrote:
             | Because then you're going to merge in the ugly commits and
             | make everyone who needs to look at the history in the
             | future have to work that much harder to understand what's
             | going on.
        
         | evandale wrote:
         | In my experience the squashing crowd is much louder and cares
         | more about squashing than the crowd who prefers to see every
         | commit. I hate squashing, but I've been beaten down into doing
         | it many times because in the end it doesn't actually matter.
         | 
         | The merge commits everywhere argument falls apart if you use
         | log --no-merges. The shitty commit messages argument is solved
         | by not allowing shitty commit messages. The "fixed typo", "oops
         | left TODO", "another typo" chain of commits argument is solved
         | by telling people to not do a million commits like that and IMO
         | those should be squashed. The clean history argument is solved
         | when you don't allow the useless "fixing typo" commits in
         | feature-xyz branches. Your history should be clean and contain
         | a history of the progress that was made.
         | 
         | But ultimately the easiest way to solve all these problems is
         | to force everyone to squash. You only have to police people on
         | a single commit and people don't have to learn about options
         | like --no-merges.
        
           | Izkata wrote:
           | > I hate squashing, but I've been beaten down into doing it
           | many times because in the end it doesn't actually matter.
           | 
           | For those of us on maintenance teams, who actually have to
           | dig in to the history to figure out what happened, _not_
           | squashing matters a _lot_.
        
             | evandale wrote:
             | You'll have to elaborate with specifics because in my
             | experience it doesn't matter if there's 100 or 10000
             | commits - git bisect works great in both instances.
        
               | RadiozRadioz wrote:
               | Bisect will let you find the big squash commit that
               | caused the regression, but lots of the information about
               | why the change happened was lost during the squash. Often
               | it's sufficient to just know the broad feature that the
               | change was in aid of, but you're out of luck if you're
               | diagnosing anything subtle. Bisect works better with
               | smaller commits.
        
               | Izkata wrote:
               | It works, but it works _better_ when you have the
               | original 10000 commits. You can tell exactly what the
               | committer was attempting when the bug was introduced. It
               | may have been as a fix to something else, it may have
               | been a typo when linting, it may even have been been
               | intentional and the bug report is wrong.
               | 
               | Other comments I made on another recent git post:
               | 
               | https://news.ycombinator.com/item?id=33395616
               | 
               | https://news.ycombinator.com/item?id=33392624
        
               | evandale wrote:
               | Hah, I must admit I thought you meant that you preferred
               | squashing! Agree 100% that a huge number of small commits
               | are easier to find bugs in than a small number of huge
               | commits.
        
               | groestl wrote:
               | It may be the last thing they did on this day and the
               | commit message reads "wip".
        
               | Izkata wrote:
               | And if that's where we end up while bug-hunting, we know
               | it was caused by an unfinished thought, is akin to the
               | typo case above, and should be fixable without much
               | concern over what else it may break since it wasn't
               | introduced while fixing something else.
        
               | evandale wrote:
               | That's exactly why I like multiple commits similar to how
               | I described. Maybe this is the silver bulletpoint that
               | can convert squashers?
               | https://news.ycombinator.com/item?id=33536876
               | 
               | >One of those small typo fixes could introduce a bug and
               | multiple commits makes it easier to track down. Blame
               | would pinpoint it exactly - you'll see Bob's "Fix a typo"
               | commit instead of being buried in Bob's "Add trucks to
               | the game" commit. That saves you from having to go look
               | at the PR or diff and to figure out why Bob renamed cares
               | to cars.
        
           | groestl wrote:
           | > is solved by telling people to not do a million commits
           | like that
           | 
           | > don't allow the useless "fixing typo" commits
           | 
           | This sounds like a much much more heavy handed approach than:
           | I don't care what you do on your feature branches, just
           | squash your commits to master and write a nice commit message
           | explaining what you did.
           | 
           | IMHO, all your rules do is increase inertia of people to fix
           | typos.
        
             | evandale wrote:
             | It's a bit heavy handed, but I believe the rules are more
             | like best practices.
             | 
             | If you're fixing typos in new code I see no reason to have
             | the history of introducing the typo and then fixing it. If
             | you've come across a typo in a file you're editing then by
             | all means make that typo fix in its own commit.
             | 
             | It gets worse when you start fixing typos in files
             | unrelated to your fix. One of those small typo fixes could
             | introduce a bug and multiple commits makes it easier to
             | track down. Blame would pinpoint it exactly - you'll see
             | Bob's "Fix a typo" commit instead of being buried in Bob's
             | "Add trucks to the game" commit. That saves you from having
             | to go look at the PR or diff and to figure out why Bob
             | renamed cares to cars.
        
       | throwaw20221107 wrote:
       | Modern Git workflow is very simple on its own:
       | 
       | 1. Your codebase has a `main` branch which is write-protected
       | 
       | 2. Devs submit changes to `main` from their own branches using
       | PRs
       | 
       | 3. Devs can do whatever the fuck they want on their own branch
       | 
       | 4. PRs are merged one at a time
       | 
       | 5. When merge happens a dev's PR is squashed into one commit that
       | gets appended to `main`
       | 
       | 6. If next dev wants to merge their PR with a conflicting change
       | they have to resolve the conflict first and then they merge
       | 
       | 7. The end result is that `main` is a linear history of all PRs
       | with the time they were committed to the `main` branch i.e., when
       | they could've started to break prod.
       | 
       | This is a solved problem and it works great in industry. Why
       | break it? If you want interactive rebase then make 2 PRs.
        
         | throwaw20221107 wrote:
         | You don't even need git for this. Your main branch could just
         | be a folder with all the diffs with sequence numbers,
         | timestamps, and who's responsible for each one.
         | 
         | The only reason people use git is because it has industry
         | traction and because of nice features like blame.
        
       | amelius wrote:
       | The paradoxical thing about Git is that it saves all history so
       | you can undo anything, yet at the meta level this is quite hard
       | and you can still get in a lot of problems if you are not
       | careful.
        
       | distcs wrote:
       | How is push origin HEAD --force-with-lease different from normal
       | git push? Can someone please explain this to me?
        
         | ok_dad wrote:
         | It will overwrite the tree on remote as long as remote hasn't
         | changed since you last fetched it. Like --force, but can help
         | to prevent overwriting other people's changes when they push in
         | between you fetching. It doesn't always work, particularly if
         | you have a tool which continuously fetches remote, like an IDE
         | configured to do so such as VSCode. In that case, you will have
         | fetched the other person's changes, and --force-with-lease will
         | happily blow-away anything on remote that might not be in your
         | tree yet.
        
           | FPGAhacker wrote:
           | Oof, thanks for that warning. So it will blow away changes
           | you haven't merged (only fetched)?
           | 
           | I guess git can't tell the he difference between "not merged
           | yet" and "don't want to merge, please destroy"
        
             | rawling wrote:
             | If you don't want to blow away changes you haven't merged,
             | you shouldn't be doing force at all?
        
               | FPGAhacker wrote:
               | Well, the article presents a seemingly nice workflow that
               | lets you handle local rebases. I was considering it.
               | 
               | However, we use vscode, and I rather like auto fetch. But
               | apparently this workflow would destroy something auto
               | fetched that I might not have even noticed.
        
         | tcoff91 wrote:
         | Force with lease is like force push except if the branch you
         | are force pushing to has changed since you last fetched then it
         | will cancel the force push.
        
         | [deleted]
        
         | dljsjr wrote:
         | When you work with a rebase-oriented workflow, it's very common
         | to submit a PR for review and then address incoming review
         | comments as fixup commits: https://blog.sebastian-
         | daschner.com/entries/git-commit-fixup...
         | 
         | This necessitates force-pushing to your feature branch after
         | all the fixup commits have been approved and then squashed. At
         | that point you can merge the cleaned up feature branch in to
         | your develop or trunk.
         | 
         | `--force-with-lease` is slightly better than `--force` because
         | in the event that you're also working on a collaborative
         | feature branch you won't overwrite any commits that somebody
         | else pushed up that you haven't fetched yet.
        
           | Izkata wrote:
           | This is the kind of workflow that makes me headdesk. Those
           | fixup commits weren't obvious, and will be useful context if
           | a future maintainer ever has to go back to these - they
           | shouldn't be squashed.
        
         | whatsdoom wrote:
         | It's not really, but there are a couple minor differences in
         | practice.
         | 
         | First, it assumes the name of your upstream repository is
         | "origin" which is fine in most cases as that is what `git
         | clone` defaults to naming the remote.
         | 
         | Second, using `HEAD` always pushes your current checked our
         | branch to your remote with a remote branch of the same name.
         | It's a neat trick to skip the "`git push` -> you need to set
         | your upstream branch -> push command the git outputs" loop.
         | 
         | Lastly, `--force-with-lease` is a safer version of `--force` or
         | `-f` because it tries to ensure that you don't overwrite
         | history accidentally. The `--force-with-lease` flag will fail
         | if a coworker for example pushed a commit to your branch that
         | you didn't know about. Where a regular `--force` would just
         | overwrite that change.
         | 
         | I assume that the command is meant to be "safe" and
         | "foolproof", in that this command should always work.
         | 
         | Since the parent post recommends a lot of rebasing in their
         | other commands, you'll need a `--force` or `--force-with-lease`
         | to push new commits because they won't be "fast forwardable"
        
           | eru wrote:
           | If git ever got a redesign from scratch, they should make -f
           | be --force-with-lease, and make -F be --force[-with-
           | prejudice].
        
         | js2 wrote:
         | A normal push will only advance the remote branch if your local
         | branch has the tip of the remote branch as an ancestor. This
         | ensures you're only adding commits to the remote branch and not
         | replacing any commits on the remote.
         | 
         | But if you've pulled the remote branch, rebased, and now wish
         | to push, the tip of the remote branch is longer an ancestor of
         | your local branch. In this scenario, to update the remote
         | branch you have to do a force push.
         | 
         | But now imaging that another developer has added new commits to
         | the remote branch in the mean time. If you do a force push, you
         | will overwrite those new commits.
         | 
         | Using "--force-with-lease" ensures that the tip of the remote
         | branch hasn't changed since you last pulled it, so that your
         | force push isn't erasing any commits on the remote by accident
         | (i.e. it ensures the remote branch has not changed in between
         | when you last pulled it and your current force push.)
        
       | andrewvc wrote:
       | Rebase should never be used. Or, if it is used, it should be
       | treated as a dangerous thing to do that's well outside the norm.
       | 
       | Most of the arguments in favor of rebase are by people fanatical
       | about having a git history organized just so. It's not worth the
       | headache and effort. PRs are a better unit of work than commits
       | in practice.
       | 
       | Configure GitHub or whatever you use to squash merge only and
       | you'll be good.
       | 
       | Since moving to this workflow I've had zero issues losing data
       | due to a confusing git situation.
        
         | cntlzw wrote:
         | ...here we go again.
        
         | seba_dos1 wrote:
         | This is like throwing away 90% of usefulness that git provides
         | you. That's what you get if you don't wish to spend some time
         | learning one of the most important tools in your career.
        
           | opsy_ wrote:
           | Can you expand on what that 90% is? I'd guess more the other
           | way around.
           | 
           | Squash merges are perfect to me for the bulk of PRs- atomic
           | test-passing iterations on the working product. Exactly what
           | I want to see in my history. Useful for bisection. Good for
           | reviewing line-based code changes as I can find all the
           | related work for that feature.
           | 
           | They don't seem appropriate for long lived feature branches,
           | or merging into release branches, but those aren't really
           | being discussed here.
        
             | seba_dos1 wrote:
             | Forcibly squashing PRs just loses information and doesn't
             | bring any benefits in return.
             | 
             | In my experience, only the simplest PRs boil down into
             | what's logically a single commit. Many PRs are simple,
             | sure, but often you end up with bunch of logically
             | connected atomic changes instead.
             | 
             | Let's take Mesa, an established and fairly high quality
             | project, as an example. Look at its open MRs.
             | 
             | You can find bunch of single commit MRs, but some of them
             | consist of approx. 2-4 commits, all of them with proper
             | commit message. See for example https://gitlab.freedesktop.
             | org/mesa/mesa/-/merge_requests/19... or https://gitlab.free
             | desktop.org/mesa/mesa/-/merge_requests/19.... It wouldn't
             | make any sense to squash them when merging.
             | 
             | You can also get monster MRs consisting of 10-20 commits,
             | like https://gitlab.freedesktop.org/mesa/mesa/-/merge_reque
             | sts/19... or https://gitlab.freedesktop.org/mesa/mesa/-/mer
             | ge_requests/19.... Splitting them out into separate MRs
             | would serve nobody, only increasing noise and review
             | turnaround time. Squashing them would lose _a lot_ of
             | useful information that you definitely want to retain for
             | things like blame or bisect.
             | 
             | Now, Mesa actually doesn't utilize git as well as it could
             | - it doesn't encode the commit's relation to merge request
             | in any way other than commit message (`Part-of:` tag).
             | Personally, I would merge a rebased branch using `git merge
             | --no-ff` option, which would create a merge commit. This
             | way, you get best of both worlds: by using tools like `git
             | log` or `git bisect` with `--first-parent` flag you get
             | what's essentially a list of merged MRs, filtering
             | individual commits out; and if you don't add that flag, you
             | get every single individual commit considered, useful for
             | stuff like `blame` or single file `log`.
             | 
             | Also, before pushing a MR for review, my work branch is
             | usually a mess. Lots of poorly divided up commits, without
             | proper commit messages, sometimes undoing each other. `git
             | rebase -i`, with squashing and rewording, is part of my
             | everyday workflow. It allows me to use git as my personal
             | undo and "let's-try-it-in-CI" tool without putting that
             | baggage onto the reviewer. I get to be as messy as it's
             | useful during my work, and the reviewer gets properly
             | curated list of commits that's ready to be merged into the
             | repository as-is. It's a win-win.
             | 
             | Not using rebases when working with git is fine when you
             | work alone or when you're just learning how to use git,
             | say, during a university project or internship. Otherwise,
             | you're doing yourself a big disservice if you don't put
             | that tiny effort into getting comfortable with tools you're
             | using every day in your work.
        
           | dlp211 wrote:
           | People don't want to learn git because it's a bad tool. There
           | are better source control systems, that are far easier to
           | reason about, but they don't have the proliferation that git
           | does.
        
             | __blockcipher__ wrote:
             | That's nonsense. Git is the best version control history of
             | all time. It has some regrettable UX difficulties, but as
             | far as the system itself, there is no better decentralized
             | development tool.
             | 
             | There's a reason git came into existence for linux kernel
             | development. The linux kernel is a project so massive and
             | so decentralized that it needed a fitting tool to be able
             | to tame the chaos. And git did that perfectly.
             | 
             | Out of curiosity though, what to you is a better source
             | control system?
        
         | throw827474737 wrote:
         | Not shared much opinion by something like half of all git users
         | likely... as any absolute opinion. Also can only counter the
         | insults by responding: you are a fanatic by using git for
         | backup and work tracking, which in contrast to you, I wouldn't
         | condemn you for ;) everyone/team can use a tool for what fits
         | best and is their use case.
         | 
         | So far I had never lost data ever with git, just confusing git
         | situations from people who never rebased, but still shoot into
         | their own foots with duplicate commits added by helplessly
         | merging around multiple branches too much, all with much too
         | many "fix typo" commits and then unresolvable conflicts :D
         | 
         | (Oh, and btw, when people end up there and I'm asked to get
         | them back to sanity, it usually involved rebasing or cherry-
         | picking them out of their messes).
        
         | Cthulhu_ wrote:
         | Rebase is fine as long as it's your own unshared work. The
         | alternative is https://xkcd.com/1296/
        
           | Forge36 wrote:
           | Don't rebase main.
           | 
           | Don't rebase shared branches.
           | 
           | It's amazingly powerful at making clear annotated changes.
           | And removing small fixup commits for work in progress.
           | 
           | When someone says "never do x" there's probably a missing
           | understanding of nuance.
        
             | eschneider wrote:
             | THIS. Rebasing and squashing local/private changes allows
             | for easier experimentation/rollback while you're
             | implementing. BUT, rebasing anything shared will cause pain
             | to others and should be avoided.
        
         | Arelius wrote:
         | > Most of the arguments in favor of rebase are by people
         | fanatical about having a git history organized just so.
         | 
         | Seems to be a bit of an OCD compulsion.
        
         | codyb wrote:
         | Disagree.
         | 
         | No one maintains change logs in their repos most times, so a
         | linear git history where you rebase existing branches on top of
         | their base branches allows for a clean commit history on new
         | features to be merged in which can then be squashed down for a
         | linear commit history on the trunk branches.
         | 
         | Then you can use things like bisect, and just... ya know, read
         | through your change log when you need to.
         | 
         | Shoot, you can even add a few details in the notes while you're
         | at it. How about a link to the ticket and PR at the very least
         | with some notes on implementation.
         | 
         | That's my approach, it really doesn't take much time.
         | 
         | But hey, if civil engineers had the level of rigor software
         | engineers do we'd all be dead.
         | 
         | So you live with what you've got, do what you can on your own
         | branches, and just accept that no one cares about having a
         | clean git history cause we can't be bothered as a profession to
         | spend a couple hours learning how one of the most important
         | tools we use every day works.
        
           | andrewvc wrote:
           | I think you misunderstood my post, if you squash merge as I
           | suggested your main branch is linear as with a rebase. Your
           | PRs and the the working branches behind them should just use
           | merged however. Come merge time the diff is turned into a
           | single commit
        
             | __blockcipher__ wrote:
             | If you squash into a single commit upon merge, ignoring for
             | the moment the fact that as a blanket rule that's a bad
             | pattern, you've now eliminated one of the core arguments
             | against rebasing. The merge commit adds no value if the
             | branch itself is a single commit. Just rebase your
             | squashed-into-one-commit branch ontop of latest master and
             | push that to master instead. Now you have one commit
             | representing your whole PR, with no pointless merge commit.
             | 
             | I really discourage the squashing upon merge approach
             | entirely though, because that's just a bandaid for lazy
             | and/or misinformed developers to cover up the fact that
             | their whole git workflow is completely borked.
        
         | dogleash wrote:
         | Your perspective is one I've only recently come to understand
         | after migrating a team to git and being the "source control
         | guy."
         | 
         | The lesson I learned was: Prescribe everything about the
         | workflow because nobody is going to learn git.
         | 
         | All the nice flexibility of git just becomes risk. By the time
         | you have enough structure in place, you're back where you
         | started: rigid source control, and you're using git locally on
         | the sly.
         | 
         | The only person who bothered learning git well was a summer
         | intern. And he mastered it, so I remain frustrated.
        
           | andrewvc wrote:
           | For what it's worth I know git fairly well and have used more
           | git strategies than most. I just happen to have found that
           | simple usage actually works better for me personally and most
           | teams I've been on.
           | 
           | Knowing a tool also means knowing what not to use:
        
         | __blockcipher__ wrote:
         | > Since moving to this workflow I've had zero issues losing
         | data due to a confusing git situation.
         | 
         | Nobody who understands git will ever lose data, because once
         | committed you can never lose it (it's in the reflog). Indeed,
         | even just adding a file means you will never lose it, although
         | it's not as convenient as having an actual commit.
         | 
         | So yeah, you kind of revealed the anti-rebase case quite
         | tellingly there. It's for people that understand git so poorly
         | that they regularly shoot themselves in the foot and lose work
         | or make other similar mistakes.
         | 
         | > Most of the arguments in favor of rebase are by people
         | fanatical about having a git history organized just so. It's
         | not worth the headache and effort. PRs are a better unit of
         | work than commits in practice.
         | 
         | PRs and good git commit history are not mutually exclusive. But
         | there are many drawbacks of trying to make PRs themselves your
         | source of truth. A big one being that it's not actually stored
         | in git, so if you ever migrate from github to gitlab or some
         | other system, that context is gone.
         | 
         | > Configure GitHub or whatever you use to squash merge only and
         | you'll be good.
         | 
         | See, now this becomes even more absurd. What's your fear of
         | rebasing if you're going to do the equivalent of a `git rebase
         | -i` upon every merge anyway?
         | 
         | This is a very confusing and nonsensical ideology.
         | 
         | For those who want to improve their grasp of git, I highly
         | recommend https://git-scm.com/book/en/v2. That book changed the
         | game for me, because I finally understood how to visualize git
         | history in terms of the DAG, and furthermore learned about how
         | git actually works under the hood (blobs and the like) which
         | made me confident I would never lose anything I've ever
         | added/committed ever again.
        
         | [deleted]
        
         | ltbarcly3 wrote:
        
           | account42 wrote:
           | That's because they know how to use git so that they don't
           | have to pick a child when they bisect.
        
             | ltbarcly3 wrote:
             | My point on my now flagged and dead?? post was that people
             | think git history is linear, so they believe they have to
             | do special stuff so it's a 'good' linear history when this
             | is pointless.
        
           | TeMPOraL wrote:
           | I use rebase, for two reasons:
           | 
           | 1. (major): it lets me commit at my pace, and then publish my
           | work at the pace the team prefers (which is a combination of
           | what the team wants and what won't choke the CI, but that's a
           | story for another time). The ratio of my local commits to
           | commits sent to code review is often 5-10:1.
           | 
           | 2. (minor): because I hate to see a Git history that's over
           | 50% made of "Merged X, Y into develop". It's pure noise. I
           | guess there's probably a command line flag to filter them
           | out, though.
        
         | derefr wrote:
         | So _you 're_ the one making me code-review 10000-line PRs
         | because you just dumped your WIP branch -- with three PRs'
         | worth of code, plus formatting changes -- directly into a PR,
         | rather than factoring apart said WIP branch either during or
         | after the fact.
         | 
         | The designed unit of a (distributed) git workflow is a _patch_
         | -- i.e. a _locally_ rebase-squashed set of cherry-picked
         | commits from development branches, with `git reset --soft` +
         | `git add -p` (or even `git format-patch` + manual editing) used
         | to prune the patch to a minimal size. Everything you do in your
         | local repo should be with the intention of producing readable
         | patches for code review (whether that patch is then done via PR
         | or mailing list.) It 's not about creating a pretty history
         | (retroactive); it's about making it easy on the people who will
         | _discuss_ and _reformulate_ your changes, one at a time, before
         | accepting them upstream.
         | 
         | To be clear, you can do whatever you want when your git
         | workflow _isn 't_ distributed (i.e. if you're committing to
         | only your own private projects, not proposing changes to other
         | people's projects.) But if your workflow isn't distributed,
         | then why be opinionated about git? You can simplify your life
         | at that point by using something with central-repo-oriented
         | semantics, e.g. Subversion. There's no rebasing in Subversion.
         | :)
        
           | twobitshifter wrote:
           | Nobody should have long running WIP branches with these
           | massive commits full of unrelated stuff. That's an
           | antipattern.
        
           | G3rn0ti wrote:
           | If you regularly need to review 10000 lines of code per PR
           | your dev workflow is seriously broken. It's got nothing to do
           | with git and its implementation's complexity.
           | 
           | Sometimes features do require large changes. But usually you
           | can break a feature into different parts (e.g. database,
           | backend, frontend) and merge them in separately.
        
             | derefr wrote:
             | Not regularly, no. But sometimes a feature change requires
             | a dependent architectural change -- a refactoring of the
             | internal library code that the feature will be implemented
             | into. Or sometimes the language of choice doesn't have a
             | pre-commit-hookable CLI auto-formatter, only an IDE auto-
             | formatter, and the dev editing a file triggers formatting
             | changes to be applied that should have been done in a
             | previous change. And sometimes, a dev thinks it's a good
             | idea to change the representation and decoding logic for a
             | data file or embedded data-structure literal at the same
             | time that they're adding an entry to it (usually because
             | they can't represent the added item's additional semantics
             | without said change.)
             | 
             | > But usually you can break a feature into different parts
             | (e.g. database, backend, frontend) and merge them in
             | separately.
             | 
             | So you've already written all that code, because you
             | couldn't get anything to "work" for end-to-end testing
             | until you wrote all parts of it. The patch _set_ as a whole
             | is inherently large.
             | 
             | Now what? _How_ do you  "break [the] feature into different
             | parts" when it's already all written and committed on a WIP
             | branch?
             | 
             | That's right: cherry-picking and rebasing.
             | 
             | The GP is arguing _against_ bothering with this process.
             | Presumably because git-rebase(1) is unintuitive to them,
             | _and_ they don 't realize that you should start this
             | workflow with a _copy_ of your branch, or a new branch with
             | cherry-picked commits from your WIP branch, to guarantee
             | non-destructive rebasing. Like making a copy of a layer in
             | Photoshop. (Yes, you can always restore your branch from
             | the reflog, so it 's technically _always_ non-destructive;
             | but `git checkout -b foo` is something you learn in Chapter
             | 1 of the Git book.)
        
         | anonuser123456 wrote:
         | How do you lose data from a rebase?
        
           | mattarm wrote:
           | A rebase creates new commits from old commits semi-
           | automatically. Git then has no permanent record of the old
           | commits, and even if you want to get back to them right away
           | it requires some delicate git surgery.
           | 
           | This is why you can't generally share work using a rebase
           | workflow.
           | 
           | It is not a big deal in practice in most every case, but in a
           | version control system it is a little bit odd that rolling
           | back such a fundamental operation isn't a first class
           | feature.
        
             | seba_dos1 wrote:
             | > and even if you want to get back to them right away it
             | requires some delicate git surgery.
             | 
             | `git reflog` to get the old commit ID, and then `git reset
             | --hard <commit>`. Seems more like "basic everyday git
             | operations" than "some delicate git surgery".
        
               | opsy_ wrote:
               | Many past confused teammates of mine I've dropped in to
               | help would disagree. reflog and reset, for better or
               | worse, require what seems to be above-average comfort
               | with git.
        
               | seba_dos1 wrote:
               | I don't think you can call yourself "using git" if you're
               | not comfortable with such simple concepts. Pointing a
               | branch to a specified ref is one of the most basic
               | operations you can reason about when using git!
               | 
               | I'm perfectly aware that many people don't think when
               | using git at all and instead merely copy'n'paste
               | memorized commands hoping that they'll do what they want
               | to accomplish, but this is something you should move past
               | when you want to stop calling yourself a "junior". This
               | is one of the most important and helpful tools in your
               | field of work, you can either take advantage of it or
               | suffer.
        
             | anonuser123456 wrote:
             | > even if you want to get back to them right away it
             | requires some delicate git surgery.
             | 
             | The reflog tracks rebase commit history. No surgery
             | required.
             | 
             | >This is why you can't generally share work using a rebase
             | workflow.
             | 
             | Rebase of public facing commits is not discouraged due to
             | data loss. It is discouraged due to the possibility of
             | someone creating change sets off the published work, and
             | then the update re-writing the history to change the merge-
             | base, requiring a re-merge of their changes.
        
               | Arelius wrote:
               | They might be exaggerating a bit the amount of work to
               | recover it immediately, but resetting a tag to a commit
               | in the reflog might be considered at least a minor git
               | surgery. And that's assuming no public pushes have been
               | made. Then all bets are off and it's surgery's time.
        
         | eloff wrote:
         | I really like squash merges because then you know tests passed
         | at every commit. Makes bisect easier, and thus more likely to
         | be used. And no headaches when you can't rebase or you screw up
         | a rebase, which will happen.
        
           | sampo wrote:
           | > I really like squash merges because then you know tests
           | passed at every commit. Makes bisect easier
           | 
           | Here is a script (just 3 lines) that tells git bisect to
           | ignore commits in the feature branches, so you can bisect
           | only the commits (usually the merge commits) in the main
           | branch. Best of both worlds.
           | 
           | https://quantic.edu/blog/2015/02/03/git-bisect-debugging-
           | wit...
        
       | [deleted]
        
       | user3939382 wrote:
       | .gitconfig:                 [alias]       add-commit = !git add
       | -A && git commit
       | 
       | .bash_profile:                 function save ()       {
       | git add-commit -m "$*" && git push       }
       | 
       | Use like:                 $ save This is a commit message
       | 
       | This adds changed files to a commit with this message and pushes
       | it to remote.
       | 
       | Also:                 alias mkpr='git push && gh pr create -d -f
       | -B develop | grep https | xargs printf -- '%s/files' | xargs
       | open'
       | 
       | Open a PR from current branch based on develop and open it in
       | GitHub in my browser.
       | 
       | Merge upstream changes from develop:                 alias
       | mduc='CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) && git
       | checkout develop && git pull && git pull --tags && git checkout
       | ${CURRENT_BRANCH} && git merge develop'
       | 
       | I have a few more, whereby I skip most of the ceremony with git.
       | Works for me.
        
         | horsawlarway wrote:
         | Commit accepts the -A flag. You can simplify it to just
         | function save ()       {         git commit -am "$*" && git
         | push       }
        
         | afefers wrote:
         | Those are really good! Thanks for sharing. Curious to see the
         | others. Are they available somewhere?
        
       | a3w wrote:
       | So, like easy git (egit), but even more minimalistic?
        
       | ltbarcly3 wrote:
       | Don't use this, just learn how git works. Bookmark this page and
       | refer to the commands in the aliases if that helps. These
       | commands are quite opinionated and as likely to cause you to do
       | something you didn't mean to do, possibly destructively, as they
       | are to help.
       | 
       | What happens when you have a million conflicts trying to rebase
       | and you need to give up? You need to know how to abort a failed
       | rebase or merge. You shouldn't insist on using a tool if you
       | refuse to learn the basics of using it.
        
         | wruza wrote:
         | _You need to know how to abort a failed rebase or merge_
         | 
         | g abort a failed rebase or merge?
        
       | lifeisstillgood wrote:
       | but we have such inventive idiots ...
        
       | Joel_Mckay wrote:
       | Nothing is idiot proof, as people greatly underestimate the
       | destructive power of a motivated idiot. =)
        
       | krossitalk wrote:
       | Just learn Git. It's really not that bad. Don't _ever_ make
       | someone use Rebase without their understanding of what that
       | really means.
        
         | [deleted]
        
         | wyclif wrote:
         | It is worth the investment to learn advanced Git if you're a
         | software engineer. Start by reading the Chacon book cover to
         | cover. It is a major tool you use every work day, so it's
         | important to understand it.
        
         | Someone1234 wrote:
         | Git like Regular Expressions I've "just learned" half a dozen
         | times already but then forget everything and have to "just
         | learn Git" top-to-bottom again and again.
         | 
         | It really is a shame, Git has a great under-the-hood design
         | (excluding poor binary file support), and such a terrible
         | interface/UX that seemingly can never be outright replaced, so
         | we're stuck with a good tool surrounded by needless confusion
         | forever.
        
           | G3rn0ti wrote:
           | The way to get ,,git" is to think about version management as
           | a concept i.e. starting top down. It's the implementation
           | details of git that many developers get confused about. But
           | they don't matter.
           | 
           | It's similar to recursions: You don't try to understand a
           | recursive function by mentally evaluating it -- instead you
           | reflect on its desired return value and how to construct it
           | in the base case.
        
           | seba_dos1 wrote:
           | My experience is that once you understand the (high level)
           | data structure you're manipulating by using git, you have
           | already made 80% of the way there. I barely know basics of
           | git's interface and have to use tools like `git gui` for
           | anything more complex in my everyday workflow, yet I can
           | manage just fine even when presented with complicated
           | problems, since once I know _from the data structure
           | perspective_ what I want to do, finding a way to do that in
           | git 's interface by searching manpages and/or the Web is
           | hardly ever a big issue.
        
       | stevage wrote:
       | For me this is another painful reminder of what git could have
       | been. Imagine if it had been this ergonomic from the start.
       | Everyone would have the same set of commands. Whereas if you
       | adopt these aliases you can't easily discuss any git related
       | issue with someone who doesn't use them.
        
       | jovial_cavalier wrote:
       | It is an unforgivable crime that Mercurial has been muscled out
       | of the consciousness. It's so much better, on literally every
       | level. Implicit branching + the ability to truly divorce the
       | repo's state from the actual files on the disk (in a simple way,
       | I'm sure you can do the same with git, but it's going to involve
       | a lot of subcommands and flags) are simply too good. Every time I
       | have to use git, I feel like I'm fighting it. I end up coming up
       | with a command that has ten flags and a subcommand that I've
       | never heard of until just now. And when I try to ask people who
       | know better, they agree it's the best way to do it.
        
       | dmuth wrote:
       | I wrote an open source project that may be useful to people here:
       | 
       | https://github.com/dmuth/git-rebase-i-playground
       | 
       | It lets you create a Git repo with synthetic commits and has
       | sample exercises for doing different things within that repo,
       | such as removing commits or squashing commits. (along with hints
       | and answers)
       | 
       | Building this project helped me understand the ins and outs of
       | Git much better and I suspect there will be value for anyone else
       | who works through the examples.
        
         | sixstringtheory wrote:
         | This seems like something that should be used in hiring
         | filters, maybe right after fizzbuzz.
        
       | jcon321 wrote:
       | Idiot proof git is handled by protecting ALL branches and
       | requiring a merge/pull request. Not a fan of aliases unless
       | created and used personally.
       | 
       | I'm a tech lead for 2 large scale web projects. Rarely will I
       | traverse git log for anything besides the last few commits. If I
       | ever wanted to see the history of something I would just lookup
       | the merge/pull request, or look at the blame on individual files
       | or lines within that file. Having a non-rebased commit history at
       | that point is much more clearer on why/what changed.
       | 
       | I guess anyone who would care for a pretty git-log does not have
       | adequate tracking outside of the source code for requirements -->
       | implementation. Guess I'm used to more stricter guidelines,
       | because I could never see myself working on a project where
       | something is committed that didn't derive from some type of
       | identified requirement.
        
         | pierrebai wrote:
         | I fail to see what anything you state has to do with rebasing.
         | 
         | Rebasing ensures all commits from a feature branch are
         | contiguous. Rebasing + squash ensures the main branch is not
         | polluted with a myriad of useless intermediate commits no one
         | is interested in. It also allows combining multiple commit
         | message into a more coherent explanation of what changed
         | instead of multiple tid-bits.
        
           | hqudsi wrote:
           | yea I do interactive rebase all the time on my local git to
           | clean up my commits before I push them up.
           | 
           | I also started doing `git commit --fixup` when doing cr fixes
           | so I can just autosquash the fixes - `git rebase
           | --autosquash`
           | 
           | So yea I think rebase and merge commits both have their place
           | within a workflow.
        
       | ricardobeat wrote:
       | This doesn't make git any easier. The _synced_ and _update_
       | commands are redundant. If you have                   [pull]
       | rebase = true
       | 
       | in your .gitconfig, which you should, both are the equivalent of
       | a simple _git pull_. Naming a command `squash` when it does
       | interactive rebase is also pretty confusing.
        
       | huimang wrote:
       | The problem with git is hardly anyone reads the fucking manual.
       | Git is not hard. The UI is inconsistent, but documented. When you
       | just foist commands onto people, you can't be surprised when they
       | fall off the happy path and don't have the mental model to
       | understand how to fix it. There's no such thing as "idiot-
       | proofing" for people who don't RTFM.
       | 
       | --force-with-lease as a default is a really bad idea. Copying
       | random aliases is a bad idea.
        
         | mmmmmbop wrote:
         | If one user uses a tool wrong, the user may be at fault. If
         | many users are using a tool wrong, the tool probably doesn't
         | have great UX.
         | 
         | Saying "the tool is great, users just need to RTFM" sounds an
         | awful lot like "you're holding it wrong".
        
           | huimang wrote:
           | Industry-specific tooling is different than a consumer
           | product explicitly marketed as "intuitive". This comparison
           | doesn't hold, for me.
           | 
           | While I agree that git's UI could be made less cumbersome in
           | some cases, many people in this industry want to use
           | sophisticated tooling without doing due diligence such as
           | reading a manual. Handling code versioning in a distributed
           | manner is not an easy task!
           | 
           | I don't expect much from junior developers, but if I have to
           | fix trivial git problems from more "senior" developers, I
           | will have some disdain for them.
        
           | weaksauce wrote:
           | I disagree... git has a fundamental complexity that you can't
           | improve that much on the command line and still have the
           | flexibility and power that it has. I use magit that makes
           | those options a hell of a lot more palatable than they would
           | be on the command line while still affording all the power
           | that you want from pure git. The git-cli has to do everything
           | and there is a fundamental nature of that. I do agree that
           | there are some things that could have been made better with
           | hindsight but that's any project.
        
             | Arelius wrote:
             | Sure can, for instance a hg-like commit stages system for
             | rebase would prevent a lot of rebase caused issues.
        
               | weaksauce wrote:
               | > hg-like commit stages system
               | 
               | not familiar with what you're referring to... can you
               | elaborate?
        
               | Arelius wrote:
               | I got the name wrong, it's phases https://www.mercurial-
               | scm.org/wiki/Phases
               | 
               | In short, every commit can be in one of three phases,
               | secret, draft, and public. Commits transition to public
               | when you push them somewhere someone else might depend on
               | them, and rebase won't allow you to rebase any public
               | commits.
               | 
               | Commits can of course be manually transitioned back as a
               | "I know what I'm doing step" but this provides a lot of
               | safety for casual rebases.
               | 
               | (Secret just prevents the commit from being accidentally
               | pushed)
        
               | mmmmmbop wrote:
               | It refers to Mercurial, another really popular
               | distributed revision control system.
        
           | deathanatos wrote:
           | UX can affect incidental complexity, but essential complexity
           | cannot be removed from the problem; this is the same as what
           | some of the sibling comments are getting at.
           | 
           | When I interrogate users who aren't grokking git, it's not
           | really git's UX that's the problem, it's far more
           | fundamental: like not understanding (and thus not being able
           | to conceptualize and visualize) that the commit graph is a
           | DAG. Not understanding what "rebase" is, because they have no
           | concept of what the word "base" means: rebase follows
           | trivially from that understanding, if they had it.
           | 
           | CLI git has these presentations; it can present the commit
           | graph, though oftentimes companies do such a crap jobs of
           | approaching git history that git is left to render spaghetti.
           | UI tools exist, but face the same spaghetti in, spaghetti
           | out. It's like asking your IDE to make bad code less bad.
           | Worse is people actively promulgate broken "methodologies"
           | that result in these spaghetti graphs, such as the ironically
           | named "A Successful Git Branching Model".
        
         | lelandfe wrote:
         | As a counterargument, git is quite hard, and I see smart
         | engineers make seemingly simple errors frequently. Its
         | documentation is sprawling and verbose, and its UI "porcelain"
         | is frequently terrible.
         | 
         | Did you know you can use `git fetch origin master:master` to
         | update an un-checked out local branch? Go find where that's
         | documented: https://git-scm.com/docs/git-fetch
         | 
         | Spoiler, here's all you get:
         | 
         | > _The format of a <refspec> parameter is an optional plus +,
         | followed by the source <src>, followed by a colon :, followed
         | by the destination ref <dst>. The colon can be omitted when
         | <dst> is empty. <src> is typically a ref, but it can also be a
         | fully spelled hex object name._
         | 
         | Just a _truckload_ of jargon. There 's thankfully one code
         | sample to give context, but it's at the bottom of the page -
         | nearly 7,000 pixels of scrolling away from the description of
         | it.
        
         | gardenhedge wrote:
         | The problem is that it has badly named commands
        
         | nerdponx wrote:
         | > The UI is inconsistent, but documented.
         | 
         | The problem is that the inconsistency means that you need to
         | constantly refer back to the manual until you have a huge
         | amount of arcana memorized.
         | 
         | Not only that, but it's not always easy to find what you're
         | looking for in the manual.
         | 
         | Yes, programmers should all at some point read the first few
         | chapters of Pro Git, and at least skim through the "internals"
         | chapter.
         | 
         | But idiot-proofing goes beyond babying people who don't want to
         | read docs. Even people who do read docs and care a lot about
         | learning their tools make mistakes and forget things
         | occasionally.
         | 
         | > --force-with-lease as a default is a really bad idea.
         | 
         | Agreed.
         | 
         | > Copying random aliases is a bad idea.
         | 
         | Agreed, but looking at other people's aliases to get ideas and
         | borrow useful snippets is a great idea.
        
         | stcroixx wrote:
         | I've read the manual several times, but it reads to me more
         | like an in progress design document filled with implementation
         | details, not things an end user should need to even be aware
         | of. I get by fine with 5 or so memorized commands.
         | 
         | I made a list of other version control systems I've used in the
         | past and out of the 7, I can only remember one that was
         | complicated enough from an end user perspective to require
         | reading a manual(ClearCase).
        
       | teo_zero wrote:
       | Git's interface is like the 'find' UNIX command: it makes complex
       | things possible, but does nothing to make common ones easy. 99%
       | of times I want to find a file in the current directory or below:
       | find . -name foo -print
       | 
       | Can you spot the 3 obvious arguments that find shouldn't require
       | me to type?
       | 
       | Similarly, if so many users add -a to their git commands, why is
       | this relegated to such an ugly flag?
        
         | throwaw20221107 wrote:
         | Ya, the three arguments are
         | 
         | 1. `|`
         | 
         | 2. `grep`
         | 
         | 3. `"my actual filter"`
        
       | thesuitonym wrote:
       | I'm reminded of the saying, "if you make something idiot proof,
       | someone will make a better idiot."
        
         | wruza wrote:
         | This is misleading. There are all sorts of "idiots" on a bell
         | curve _already_ and making something easier simply widens the
         | stripe of effectiveness. It is a good thing because you now
         | have more  "idiots" who could do the job just fine.
        
           | opsy_ wrote:
           | I think the implication is often efforts towards "idiot
           | proofing" don't actually improve effectiveness at the end of
           | the day. They simply add something else to trip on.
           | 
           | I'd roughly say that's the case with OPs aliases. Useful if
           | you know what you're doing, or maybe would work with a strict
           | team policy. Otherwise are just going to create more trouble
           | (especially with that force pushing bit in there...).
           | 
           | ETA: I fully support usability! "real programmers just read
           | the manual" arguments be damned.
        
         | softwaredoug wrote:
         | As I get older, I become the next dumber idiot :D
        
       | gabrielgio wrote:
       | I like those aliases if you are doing for yourself, but I dislike
       | for beginner (to git) using them to make git "easier". Git UX is
       | confusing and has growing pains I won't deny it, but git is
       | widely used and imho one should take some time to at least
       | understand the basics.
       | 
       | I dislike even more the default of many IDE and some git server,
       | they seem to push for the worse git habits.
        
       | uwemaurer wrote:
       | With https://www.highflux.io/ we try to make this git workflow
       | even easier by automating the necessary steps with a simple UI.
       | 
       | You can just work in your feature branch, your changes get
       | automatically rebased and when your done your branch gets merged
       | as a single commit.
       | 
       | We are still in early development, always looking for feedback :D
        
       | throwup wrote:
       | After reading this post, I have another tip - instead of adding
       | `alias.pr` to your gitconfig, you can create a shell script
       | called `git-pr`. Then you can write readable code instead of
       | having to sprinkle extra quotes and backslashes everywhere.
        
       ___________________________________________________________________
       (page generated 2022-11-09 23:01 UTC)