The git history command

(lalitm.com)

372 points | by turbocon 13 hours ago

34 comments

  • bad_username 7 hours ago
    I was uncomfortable with git until I read (the first 3 chapters of) the pro git book ( free here : https://git-scm.com/book/en/v2 ). It provides a great mental model of how git works under the hood. The UI of git - for better or worse - directly reflects its internals. And when I understood them, everything clicked into place.
    • Hendrikto 4 hours ago
      Git is not nearly as confusing as people make it out to be. They just never take the few hours it takes to understand it. Which is a sad state of affairs for such an essential tool in the belt of any software engineer.

          git commit -am “Changes”
      
      just does not cut it, if you call yourself a professional.
      • jchook 2 hours ago
        Obligatory git joke.

        Git gets easier once you understand branches are homeomorphic endofunctors mapping submanifolds of a Hilbert space

        https://softwareengineering.stackexchange.com/questions/2564...

      • hackrmn 4 hours ago
        My observation has been that those who have never learned Git properly -- disregarding for a moment the issue with what "properly" means here -- just don't think they need to, sticking to very simple workflows that produce linear graphs featuring squash-rebased work throughout. Because they don't know Git's fundamental model (including what you'd think was the obligatory piece of information that commits are essentially immutable), they don't venture farther than their confidence suggests, keeping it within the circle so to speak.

        The tragedy, if you ask me at least, is rather that they then start imposing the "keep it simple" culture onto everyone else, which frankly turns Git into what SVN and CVS were accomplishing before it, with all the drawbacks of those. This keeps 90% of the team satisfied 90% of the time because there's nothing wrong with strictly linear graphs and the pro's that are asked to produce these, can always squash-merge their intricate local development history before they push to Github (which some Git users also think is part of Git proper).

        Something about using Git in the aforementioned way just bugs me strongly. I admit it's a me problem, very likely, but lately I've also had to admit that it's not just that either.

        For instance, if I need to fix a bug I use `git blame` to find the commit where I have learned the bug originated. I do a `git checkout -b ... <commit>` to start working on a fix, creating a branch starting at the problematic commit. Already that is head and shoulders above what many people I work with do or know _what_ does (or why would one want to do that).

        I do it because it creates a _trail_, certainly more so than just committing on top of `master`, even with a good commit message.

        But my practice doesn't produce linear graphs, even as pushed to Github (which we have to use, for better and for worse) and shared with everyone. I then get people coming to me and complaining they can't merge and it becomes obvious they don't understand Git sufficiently to do anything else but `git reset --hard` or worse, `rm -rf * && git pull` and hope for the best.

        Not sure where I was going with this, something about why use Git when it's the new SVN with everything SVN had and none of what SVN didn't have...

        • andawaywego 12 minutes ago
          can you elaborate what concrete value you've managed to extract from doing things like this? my gut reaction is that any benefit would be overshadowed by multiplying effort for other team members to catch up on their work, and if it makes it harder to work when even one person does it I can't imagine it scaling on a full team (or worse, something like a monorepo)
        • BigTTYGothGF 59 minutes ago
          > creating a branch starting at the problematic commit

          Code always lives in a context, and when you're fixing a problem that exists in top-of-main the context of the fix needs to be top-of-main, not some commit way back in history. Also if you do it that way, you'd better hope that no later commit also touches that same line.

          > I then get people coming to me and complaining they can't merge

          A team needs to agree on git practice in advance, and not have one wildcard go off and do their own thing.

        • nixon_why69 3 hours ago
          Ok but the final outcome, most of the time, is a linear graph unless you're maintaining extremely long-lived branches for some reason.

          Setting practices so that linear graph will be easy to understand in history is still a good idea, no? I'm not religious about squash-merge on master but when I look at master's history, I'd expect each individual commit to have a good message and be releasable.

          • hackrmn 3 hours ago
            A linear graph doesn't do any developer in the team except Github (which isn't a developer in this context) any good because they have to pull down the graph at some point and when they have to fix something, although they will be able to track the blame to some commit in the middle of the graph, when they fix it and merge it it has to be squashed again (by hard or soft enforcement), which like I said negates much of the point with Git -- there's no usable history left.

            Point being that branches aren't something to avoid, implying that complicated graphs are not to be avoided either, but embraced and knowing how Git works it's not a problem at all (unless your "bush" is accidentally complex in a bad way) -- except that if noone bothers to learn Git, it _becomes_ a problem, solved at the cost of the value that Git provides -- branching (not just ephemeral branching for your local convenience). Exacerbated by Github since everyone pulls from there -- meaning that production-grade code is not a true graph but a linked list, on average.

            • nixon_why69 2 hours ago
              > the value that Git provides -- branching (not just ephemeral branching for your local convenience).

              I think this is the disconnect. I could see big libraries maintaining branches for each major release and I understand why linux does it. But if I'm maintaining FooService at work then I actually do just want a linear graph of all the commits that have been in production, in commit order.

              • hackrmn 2 hours ago
                If you want that, mandate developers use prefixes like `!fixup` and do `git rebase` _on your end_ -- why force upon everyone your ideas especially if it also squashes all development history? This also removes development friction because people can work with Git on their end the way they like without regard to some convention that can be avoided -- save for the "!fixup" thing which can be considered useful metadata.
                • BigTTYGothGF 50 minutes ago
                  I want development history to be squashed. I want to have a nice clean `git log` that I can look back thru and not see a mess of 'WIP' and 'fix' and other noise.

                  Unless you're saving every keystroke from your editor you're already squashing history, we're just arguing about degrees.

                • nixon_why69 1 hour ago
                  I do enforce rebased, releasable merges to master on my end, I'm not campaigning to remove branching from git for everyone.

                  Just saying, in the common case, the simple approach actually is pretty good.

      • kreco 4 hours ago
        > Git is not nearly as confusing as people make it out to be.

        The people are confused, it's a fact. So it is confusing. Stop gaslighting people.

        • ninkendo 3 hours ago
          There’s this important word in the sentence you seem to be ignoring: “as”

          GP isn’t saying “git isn’t confusing”, they’re saying “git isn’t as confusing as people make it out to be”

          The point being, people exaggerate git’s confusingness when discussing it. There’s an element of irrationality here that’s worth bringing up, especially when it comes to comparing it to competing software. Once it has a reputation for being confusing, you’re more likely to be scared of certain workflows, you avoid them, and the problem compounds. Similarly if a VCS has a reputation for being “simple”, people might gravitate to it, learn it first, then parrot conclusions that git is too complicated because they never really gave git a chance in the first place (often they do take the time to read the other VCS’s documentation, and if they would have done the same for git they would have had no problems.)

          It doesn’t help that there are so many bad tutorials out there that simply give you what commands to run, and tell you dumb stuff like “just make another clone if you get stuck”, and that makes the problem so much worse, and isn’t git’s fault.

          Git is a bit confusing sometimes, but it’s mostly for reasons like “the reset and checkout commands do too much”, and “some low level commands are easy to confuse with high level commands” not because it’s a fundamentally confusing tool.

          • kreco 3 hours ago
            > Similarly if a VCS has a reputation for being “simple”, people might gravitate to it, learn it first, then parrot conclusions that git is too complicated because they never really gave git a chance in the first place (often they do take the time to read the other VCS’s documentation, and if they would have done the same for git they would have had no problems.)

            I don't think I need to reply to a comment that illustrate the main point of this sub thread.

            • ninkendo 3 hours ago
              You just did though…

              Maybe try and explain in more than one-sentence quips why you think git deserves its reputation? Otherwise you’re just coming off as a bit of a troll. Have a nice day.

        • xelxebar 3 hours ago
          Interesting. "A is X" is different than "I experience X from A". The former employs an objectivist lens while the latter a subjectivist one. I have had the pleasure of witnessing debates about whether a room really, truly is cold or not, which all resulted from a simple "it is cold in here" comment. In my experience modern English speakers tend to bias toward the objectivist register while Japan tends the other way. One of the joys in my life is how absorbing languages and cultures elucidates previously-unperceived distinctions. This discussion makes me want to try picking up Ithkuil again.

          /r

        • xeyownt 4 hours ago
          If you ignore gravitation, a sphere earth can be very confusing.
          • andawaywego 5 minutes ago
            plenty of models do fine with assuming a flat earth. git is an incredibly competent swiss army knife for building VCS but I'm not convinced it's the best we can ever do (nor we have ever done) for the simple linear history we expect from your usual corpo crud.
        • dspillett 3 hours ago
          But not as many people are as confused as is sometimes made out. And those who are confused are not as confused as people make out¹. Implying that a great many people are very confused because some are is far more gaslighty than suggesting it isn't that hard in the majority of circumstances, IMO.

          --------

          [1] many (and I'd include myself here) are fine using the basics, perhaps with some less as-simple-as-possible workflows, but might need to scan the docs if they hit a conflict merging two branches that have developed independently for a fair few commits and have overlaps

        • Thanemate 4 hours ago
          >The people are confused, it's a fact. So it is confusing. Stop gaslighting people.

          I don't think this sort of aggression is warranted, as the fact that I find something confusing doesn't directly imply an intrinsic feature of the object that I'm confused with. One can reach that conclusion by observing that, not everyone who learns about the object finds it equally confusing.

          All that to say: "The people are confused" doesn't mean that "All people are confused".

          • kreco 3 hours ago
            There is no aggression.

            If your product has a reputation to confuse users compared to other products, your product confuses users.

            Let's not start to bend reality just to back up some narrative because after reading a N hours documentation everything is OK.

            • dspillett 3 hours ago
              > Let's not start to bend reality just to back up some narrative because after reading a N hours documentation everything is OK.

              If you expect everything to be as easy as pie without needing to make a little effort to read a bit of documentation, then perhaps the problem is not the product but the fact that you are in the wrong industry, or the wrong role within that industry, for you. Have you considered a management track?

              Git is intended to make certain patterns possible, and practical. “Easy for people won't read some documentation” was never one of its design goals.

              • kreco 3 hours ago
                You conveniently cherry picked the least relevant part of my message.

                No one said everything should be easy as pie.

                There are other software similar to git that have not such reputation. Version control is not new.

                • account42 2 hours ago
                  > There are other software similar to git that have not such reputation. Version control is not new.

                  Yes, there are alternatives that aren't used by anyone except dedicated fans. If they had the wide user base that git enjoyed you'd hear just as many complaints about them.

                • jamesnorden 3 hours ago
                  Because people actually use Git instead of whatever you mean.
                  • kreco 3 hours ago
                    This is irrelevant to the topic.

                    I didn't ask why git was widely used. I didn't say git was useless.

                    Again, there were version controls before git came out.

                    • echoangle 2 hours ago
                      I think the point was that a lot of people are confused by git because a lot of people use it. Meaning that the other software where people don’t complain would get the same amount of complaints if it had as many users as git has.
            • ninkendo 3 hours ago
              > If your product has a reputation to confuse users compared to other products, your product confuses users.

              Is your contention that all reputations are deserved, by definition? That’s certainly an interesting take. It leaves zero room for the concept of an “unfair reputation” for example. Maybe you should rethink your argument here.

              • twister2920 52 minutes ago
                do you think everyone who claims to be confused by git is making it up? or do you just think you're better than them?
                • ninkendo 37 minutes ago
                  I've elaborated on why I think git's reputation is undeserved in sibling comments. kreco's contention is that "it has a reputation of being confusing, therefore it is confusing", which I think is bollocks. They're throwing accusations of "gaslighting" around.

                  It's valid to think "yes it has a reputation for being confusing, but much of it is undeserved". It's not black-and-white.

                  • kreco 3 minutes ago
                    > "yes it has a reputation for being confusing, but much of it is undeserved"

                    This is not what is written here:

                    > Git is not nearly as confusing as people make it out to be. They just never take the few hours it takes to understand it. Which is a sad state of affairs for such an essential tool in the belt of any software engineer.

                    > just does not cut it, if you call yourself a professional.

              • kreco 53 minutes ago
                You are moving the goalposts.

                I could show you thousands of message backing up the confusion.

                But you can keep nitpick irrelevant part of messages and pretend you are very smart.

                • ninkendo 34 minutes ago
                  You've made one and only one point in this thread so far: I'm addressing only that point. You've provided no other elaborations. You're saying "it has a reputation for being confusing, therefore it is confusing." That's a bullshit statement, IMO.

                  If you made any other elaborations on why you disagree with the post you were arguing against, we'd have something else to discuss. But right now you're just posting shallow dismissals with fallacious arguments. You can do better.

                  • kreco 7 minutes ago
                    > You've made one and only one point in this thread so far: I'm addressing only that point. You've provided no other elaborations. You're saying "it has a reputation for being confusing, therefore it is confusing." That's a bullshit statement, IMO.

                    I'll repeat myself, I can show you thousands of messages point out how git is confusing. I can show you plenty of message saying "I used X it was fine, but I used git and it's cumbersome", please show me the same amount of messages telling "I used git it was fine, but I used XXX and it's cumbersome."

    • Someone 28 minutes ago
      > The UI of git - for better or worse - directly reflects its internals.

      I disagree. For example, we have, from “git checkout —help”:

         git checkout has two main modes:
      
         1. Switch branches, with git checkout <branch>
      
         2. Restore a different version of a file
      
      The first variant never loses changes you made that aren’t in git yet, the second is explicitly designed to revert them. How does that directly reflects git internals?

      (And of course, there are many inconsistencies in the CLI that do not have to do with git internals that, even if you know what you want to do internally and which command to use, make figuring out the CLI incantation to do it harder than needed. That’s a different subject, but still contributes to “git is difficult to use”)

    • hnfong 6 hours ago
      Same here. The git commands were confusing to me until I actually saw a Linus video on youtube explaining how the git data structures worked under the hood. It was dead simple, and one could easily mentally map the tools' functions onto how they operated on the data structures.

      Once I understood that, as you said, everything clicked into place.

      Somehow the "higher level abstractions" that git tries to do makes the things ever so more confusing.

    • vasco 6 hours ago
      Mercurial had by far the best UX, never had to read anything to learn it. I just pretend that I'm using mercurial when using git and nuke local repo if I mess up. Been doing it for my whole career.
      • black_knight 5 hours ago
        I love darcs! Somehow its interface just vibes with me. It is interactive by default, and the commands like “record”, “rollback”, etc, are somehow intuitive. Darcs also tried to put more semantic content in the patches, like file operations or search replace parches.

        It is always satisfying to rename something, then merge in some work where someone used the old variable name in the meanwhile, and the merge would go through automatically applying the rename!

      • yurishimo 5 hours ago
        I've often found that many problems when working in teams can be traced back to `rebase`. I understand the benefits, but if you're already working on a team where history is not used in any serious way, then you cut out a lot of foot-guns by only using `merge`.
        • Hendrikto 4 hours ago
          > if you're already working on a team where history is not used in any serious way

          Then you are doing it wrong. Sadly this is very common.

        • zwischenzug 4 hours ago
          Except the "merge mess" footgun.

          I got into training people in Git (I now do it for O'Reilly) because I worked with 12 teams that merged _everything_ into sub-branches. The result was that the `git log --oneline` command resulted in screensful of just pipes.

          My initial training goal in training was getting my students to understand a rebase to avoid that mess.

    • xyzsparetimexyz 6 hours ago
      No it doesn't. Half the git commands are low level, half are high level. It's not 1:1 at all.
      • palata 6 hours ago
        So when someone tells you "understanding X helped me a lot", your answer is "no, it did not"?

        > It's not 1:1 at all.

        I don't see any mention of "1:1" in the parent.

        • debugnik 6 hours ago
          They're replying to

          > The UI of git - for better or worse - directly reflects its internals.

          • palata 3 hours ago
            > Half the git commands are low level, half are high level.

            Can't we say that the low level level commands reflect its internal? ...

            • twister2920 50 minutes ago
              of course we can, that's not what the original comment said though
        • jesse_ash 6 hours ago
          > The UI of git directly reflects its internals

          Maybe?

  • jolmg 12 hours ago
    > scary rebase -i commands that can leave your tree in a half-broken state if you so much as sneeze

    `git rebase --abort` exists. One can also set a tag or something before doing the rebase, do whatever, then `git reset --hard $set_tag` to go back. Nothing to be scared of. Not like the prior state is lost.

    • rmunn 12 hours ago
      I have so many branches named `temp` or `before-rebase` for exactly that reason; I'm using them effectively as tags, but branches can be moved around with less ceremony than tags (since tags are designed to be for things like v1.2.3, placed once and then almost never moved again), so I usually just do `git branch before-rebase/some-feature` before running a big `rebase -i`.

      I've almost never needed to run `get reset before-rebase`. But I have often done `git log -p before-rebase` and compared that to the post-rebase state of the branch, to ensure that the merge-conflict resolution(s) that came up during the rebase haven't accidentally introduced an unintended change.

      • chrismorgan 9 hours ago
        Diffing diffs is so valuable for that reason, seriously underrated. Once I even found a use case for diffing diff diffs.

        I also often wish to edit commits or resolve rebase conflicts or whatever by editing the patch rather than the files.

        • amarant 6 hours ago
          Hey yo,I heard you like diffs, so I put some diffs in your diff so you can diff your diff while you diff!

          Sorry, couldn't resist. The xzibit was too strong in your comment.

      • bjackman 5 hours ago
        After a rebase, mybranch@{1} refers to the previous location of mybranch, so you don't need to manually track these before-rebase branches etc.

        (In practice I find this syntax super annoying and usually end up typing `git reflog mybranch` and then copy-pasting the commit hash from the output).

      • jolmg 11 hours ago
        > but branches can be moved around with less ceremony than tags

        `git tag -f` to move a tag.

        Personally, I just do `git show` when I'm feeling cautious, but I can generally just scroll up to find the last `git commit` I did with the hash in the output. `git reflog` should also have record of it, so everything else is kind of extra.

        • rmunn 11 hours ago
          Good point, that's no more ceremony than moving a branch. I guess I've just gotten "branches are movable tags" so deep into my hindbrain that I absorbed "tags are hard to move". But that's not actually true, and for what I'm doing (save this point in history for a while) a tag makes slightly more sense, semantically, than a branch.
      • hack1312 8 hours ago
        This is the exact same thing I do, though with the prefix "pre-rebase/"
    • account42 2 hours ago
      You don't even need to set a safety tag like that anywhere in git, the reflog does that for you automatically.
    • catlifeonmars 12 hours ago
      Do you use git reflog?
      • jolmg 12 hours ago
        One can also use that, or just `git log -n1` and taking note of the commit hash. So many options.
        • jmholla 8 hours ago
          Fun fact: you don't even need the `-n`. `git log -1` does the same thing, for any number.

              -<number>, -n <number>, --max-count=<number>
                  Limit the output to <number> commits.
      • ibizaman 8 hours ago
        I do when I forget to run the git branch comment before. But I find it still hard to understand exactly which commit to reset to in the reflog.
        • _ikke_ 7 hours ago
          The branch reflog (git reflog <branchname> or git log -g <branchname>) is a lot easier to follow in the case of rebase than the HEAD reflog (which gets an entry for each commit that gets checked out / applied).
    • dalmo3 6 hours ago
      > `git rebase --abort` exists

      Exactly. 50% of the times I type git rebase it is followed by --abort.

    • andrepd 8 hours ago
      No need for that even. Just git reflog and rewind back to any spot your want!
  • nativeit 11 hours ago
    I don’t consider myself a coder or programmer, but learning git was like an organizational superpower for my particular brain wiring. I use it for websites, design projects, electronics engineering, music composition, personal knowledge bases, remote administration scripts, config management, snippets, so many applications and so many features for one system. It’s not always perfect, but I tell everyone I work with they should learn it.
    • m463 8 hours ago
      I also took a leap in organization. But I don't think you're responding to git in particular, just a source control system.

      git (and other version control systems) take what you made, organize and preserve it, and you can get any number of copies at a moment's notice.

      It is good for people to be able to do work and not worry about it.

      I remember reading David Allen's book Getting Things Done years ago. It takes effort to read through his writing, but he had good ideas.

      One thing he mentioned is that you need a 'trusted system' where you can collect and organize your thoughts. It lets you offload what you're worrying about until the time you need to do something with it.

      I actually use omnifocus to do this for my tasks/projects/lists, but for what I actually do on a computer, I trust git to organize and preserve the software (and some data) I have written.

    • quacked 9 hours ago
      How do you use it for music composition?
      • tunesmith 8 hours ago
        I use it for lilypond for notation. I always considered it superior to Finale and Sibelius anyway. Not sure how it stacks up against the more modern commercial notation apps. But I love having a real trackable version history of my pieces.

        What's also cool is the more advanced llms know lilypond and music theory too, so they can do things like... I don't know, check for counterpoint errors. I've used it with limited success to expand my jazz lead sheets into two-hand piano arrangements just for practice exercises.

        • quacked 2 hours ago
          I've considered using Lilypond, but I really like the autoplay feature in Musescore, as well as the lack of delay between placing notes and seeing the result.
      • knodi123 9 hours ago
        there are plenty of text-based digital music notation systems. Then, you commit periodically as your composition evolves, and you can have all the history/fork/undo whatever that you might want.
        • seba_dos1 9 hours ago
          Also, files don't have to be text-based at all to version them with Git. When you're versioning things for your own sake, there's often not much difference between keeping text and binary files there, as it's not like you'll have to resolve an unexpected conflict.
          • rmunn 8 hours ago
            I find it really useful to be able to diff two commits, which if you're using a binary format is only possible if you have a meaningful-diff tool for that format. Some formats have one already created, more formats don't. (Though these days, an LLM might be able to produce something suitable).
  • chandlerswift 10 hours ago
    I've been theoretically a big fan of these commands; I use the `jj` equivalents all the time. The roadblock I've run into is that I as far as I can tell (from the man pages and the git source code) there's no way to get `git history` commands to sign commits they modify:

        $ git log --oneline --show-signature  # look ma, I signed my commits!
        3a1dd8f gpg: Signature made Mon 13 Jul 2026 10:45:50 PM CDT
        gpg:                using RSA key FBF32CDBCC134B44FD29B66FA851D929D52FB93F
        gpg:                issuer "chandler@chandlerswift.com"
        gpg: Good signature from "Chandler Swift <chandler@chandlerswift.com>" [ultimate]
        Second commit
        03c3f6e gpg: Signature made Mon 13 Jul 2026 10:45:16 PM CDT
        gpg:                using RSA key FBF32CDBCC134B44FD29B66FA851D929D52FB93F
        gpg:                issuer "chandler@chandlerswift.com"
        gpg: Good signature from "Chandler Swift <chandler@chandlerswift.com>" [ultimate]
        Initial commit
        $ git history reword HEAD~
        $ git log --oneline --show-signature  # oops! where'd they go?
        5662b2c (HEAD -> main) Second commit
        6bf6830 Initial commit amended
    
    This has pushed me back to the time-honored `git rebase -i` since I do want to keep my commits signed.
    • jmholla 8 hours ago
      Woah! That feels like a huge oversight and like it bypasses standard commit logic. The man pages do say `git history` is experimental. Sounds worth a bug report.
  • jonathanlydall 6 hours ago
    I've been doing regular significant re-writes to my local Git commit history with relative ease for over a decade even without this new Git command.

    I'm convinced that a big part of people often finding Git and rebase difficult is a user interface issue, having to know all the correct command line options and having to make your own mental model of what's happening and what you want to do, all makes it difficult to get a firm grasp on things.

    I can't comment on what equivalent alternatives (especially on macOS/Linux as I'm a Windows user), but in terms of a UI for Git which exposes enormous power in an easy-to-use way I've found TortoiseGit to be spectacular and I especially like its rebase dialog:

    https://tortoisegit.org/docs/tortoisegit/tgit-dug-rebase.htm...

    Which you kick off from a context menu option from the commit line on the commit log you want to rebase onto with a simply named "Rebase <current reference> onto this" option:

    https://tortoisegit.org/docs/tortoisegit/tgit-dug-showlog.ht...

    It's super easy to re-order, split, combine, edit commits from here and it's obvious that will happen. If for whatever reason you decide you want to back out midway, you just abort and you're back to where you were.

    I will concede there are aspects of a TortoiseGit I find a bit annoying, particularly that I feel I have to click around too much, instead of a shell extension I would prefer an app you launch with tabs or something, but I think this is a fundamental design principle of TortoiseGit, which followed the same principle as TortoiseSVN.

    There is Git Extensions for Windows which seems nice at a glance, I tried it briefly, but I think I didn't stick with it either due to being unable to find an option I regularly used or I was just so used to TortoiseGit already.

    • Cthulhu_ 6 hours ago
      Same, but at the same time the existing workflow is a bit more clumsy / these commands are a bit more ergonomic.

      Fixup was already possible through `git commit --fixup`, and before that through `git rebase -i`; reword also through `git rebase -i`. I suppose the developers got enough feedback that editing a file to decide what to do with each commit was a bit frustrating for some users.

      It's a higher level command on existing functionality I suppose.

    • crabbone 5 hours ago
      In terms of UI for Git, I've never seen anything getting remotely close to Magit. It's both in-depth and a simplified stateful interface.

      Here's what I mean by "stateful": one of the huge problems with command-line tools is that their output becomes mostly inaccessible upon subsequent invocations. Suppose you ran git-log, and now you want to apply the knowledge gained from reading its output to your next action (say, you want to cherry-pick a commit). But you are lucky if the hash of the commit in question is still somewhere in the terminal. Otherwise... you aren't writing that from memory...

      Stateful UI to command-line tools allows multiple interactions in parallel and preservation of information obtained in previous interactions.

      Git needs a lot of state. You need to remember facts s.a. what branch you are on, what branch did you switch from, what files have been modified, what commits haven't been pushed etc. The requirement to remember all of this is overwhelming and makes the effective use of the tool difficult. This is where various tools come to help (eg. Shell plug-ins that provide auto-completion or modify the prompt to incorporate some of that state info).

      I believe that people complaining about difficulties of using Git are often handicapped in their use of surrounding tools that would otherwise mitigate the problems above: they don't know how to add Shell plug-ins that display the current branch, they don't know how to have multiple tabs/panes open in a single terminal session, how to copy text between those tabs/panes, they don't know how to invoke / search auto-complete options.

      Genuinely, if you don't have tools to help you use Git, something that people who are used to navigating the world of terminal UI, using Git becomes very unpleasant.

  • klibertp 1 hour ago
    IME, the only real pain point with JJ is Git integration. I love it, it's great in almost everything it does. Formalizing all the DSLs and using them consistently throughout the config and CLI is exactly how filesets, revsets, and templating should be implemented. The focus on exposing concepts as interfaces (without "directly reflecting internals"[1] in the UI) is only as good as the concepts themselves, and in JJ's case, they are powerful. The problem is that they are too flexible, so Git interop relies heavily on convention and discipline... which is fatal. The fact that (almost?) all states of JJ are representable in Git makes it easy to mess up your remote, and then you need a very solid understanding of Git to fix it.

    If you can give `jj` a try on a greenfield, single-developer project, you probably should. It feels exactly like Git felt compared to Subversion (when you focus on JJ's strengths and use it in favorable conditions - it is young, after all). Get acquainted with `jj` on its terms, and if things click for you, you'll be a bit better prepared for the bumpy road that is Git interop later on.

    [1] https://news.ycombinator.com/item?id=48903054

    • steeleduncan 50 minutes ago
      In princple JJ has non-Git backends, but the only backend they state as being production ready is the Git backend. JJ without the Git interop is more a concept than a reality right now.

      I love JJ, and the mental model of source control it presents, and I will continue to use it. However, still needing to "drop down" to Git every now and again to get something done makes it feel very much like a convenient wrapper on top of Git rather than a new SCM.

      If Git adds commands to support the JJ workflow, it would be hard to justify having JJ installed any more.

      • klibertp 18 minutes ago
        The backend itself is fine, it's just trying to use JJ as a Git frontend for projects developed on Github (among 20 other devs using git, where each of them uses git through different interface and/or in different style) that's currently not ideal :(

        > However, still needing to "drop down" to Git every now and again to get something done makes it feel very much like a convenient wrapper on top of Git rather than a new SCM.

        Yeah, but I think that's fine. Git is a solid foundation; it's not wrong to try to build on it initially. It gets you a usable implementation faster. It is a pain point, though.

        > If Git adds commands to support the JJ workflow, it would be hard to justify having JJ installed any more.

        Is that a danger? I don't see Git as a fast-moving target. And among all the "convenient wrappers on top of Git", JJ seems to have the design least tied to Git, so I think it has the highest chance of breaking out of the Git dependency in the future.

  • rom1v 5 hours ago
    > `git history fixup` fixes an old commit that has something wrong in it, then autorebases all your branches to match.

    Simplifying `git rebase -i` is a great idea, but unfortunately, that does not match my workflow.

    I always keep an history of my branches. For example, when I develop a feature, the first version of the branch is `myfeature.1`, then `myfeature.2`, and so on. This is useful because I can retrieve an old version when something behaves differently in a newer one. (And no, `git reflog` will not help)

    This has saved me multiple times. For example, I can determine that a problem was introduced between `myfeature.58` and `myfeature.59`. If the "feature" contains 15 commits, I do:

        git range-diff myfeature.58~15..myfeature.58 myfeature.59~15..myfeature.59
    
    This lets me see the changes between the 2 versions, commit by commit (even if they don't have the same base).

    I don't want all the branches containing a commit to be rebased automatically (I already try using tags for old versions instead, but this does not quite fit).

  • nine_k 13 hours ago
    In short, newer versions of git implemented three really frequent use cases of `git rebase --interactive` as separate lower-friction commands. Apparently they only work when there are no conflicts.
    • BobbyTables2 12 hours ago
      Wonder if the history command is all that useful.

      I prefer the interactive rebase and use it frequently.

      Would much rather “visually” move commits around than accidentally aim “git history” at an orphaned commit hash no longer in my local branch.

  • paxys 11 hours ago
    I don't get all the effort people spend in perfectly curating git history. No one is ever going back and reading individual commits. Just squash everything before merging and call it a day.
    • jxf 10 hours ago
      > No one is ever going back and reading individual commits.

      I violently disagree with this.

      At a minimum, when I review PRs I look at the commit history to understand what's up. If the path that was taken to commit this is full of "oops" and "fix" messages, it's an immediate reject for me. The commits tell the story and it's a kindness to your human reviewers to not make them work harder to understand the point you're trying to get across.

      • nl 10 hours ago
        > If the path that was taken to commit this is full of "oops" and "fix" messages

        great way to encourage people to rebase then!

      • GrandfatherTECH 10 hours ago
        What's up with the fix commits? Maybe I misunderstood you, but there ain't nothing wrong in fixing stuff you offer in your PR. And there can also be multiple commits even before the PR while you're developing your PR.
        • locknitpicker 9 hours ago
          > What's up with the fix commits?

          They shouldn't show up in the commit history. In a PR, you merge them in the commit that they actually fix. Otherwise when you use git blame to get the context of why a line of code was changed, all you see is a useless "fixup" message that is worse than having nothing.

          Anyone can do better than a fixup commit. And doing metter means merging them into the actual commits that are fixed.

          • dooglius 1 hour ago
            Hence GP's advice,

            > Just squash everything before merging and call it a day.

          • gbalduzzi 8 hours ago
            > Otherwise when you use git blame to get the context of why a line of code was changed, all you see is a useless "fixup" message

            Isn't this solved if you squash the commits when merging the PR? I personally don't care that much about the commits inside a PR, the are just temporary because when a PR is merged they are squashed and you only get one commit for the whole feature on the main branches

            • NateEag 7 hours ago
              I once root-caused a revenue-losing bug that had the entire rest of my team stumped with ten minutes of git-bisect.

              It only worked that well because the team had all internalized my advice to write small, coherent commits, so the bisect landed on a ten-line change.

              I strongly dislike the recent trend towards squashing every branch into a single monster commit.

              • LtWorf 7 hours ago
                Most people who squash things have never used git bisect, cannot solve a merge conflict and when there is one will just delete the directory and clone everything again. I've worked with such people. They can go on like this for an entire lifetime.
                • user43928 6 hours ago
                  I used git bisect once in 10 years, and it was when I learned about its existence.

                  I am convinced that very few know about git bisect, much less use it regularly.

                  • locknitpicker 6 hours ago
                    > I am convinced that very few know about git bisect, much less use it regularly.

                    Yes, unfortunately not all companies have a high hiring bar. Some

                • skydhash 2 hours ago
                  For me (I know you used most, not all). A PR is an atomic thing. Either one bug or one feature. Commits inside it are mostly time snapshots, and fixing formatting and linting errors. If I where to properly present the PR, it will also have been a single commit.
                  • LtWorf 58 minutes ago
                    Good for you that we don't work together, because for sure I'd reject all of your pull requests until you learn :D

                    This could probably be helpful https://mtlynch.io/code-review-love/

                    • skydhash 32 minutes ago
                      The only point not addressed by reviewing changes at a PR level instead of a commit level is

                        7. Break up large changelists
                      
                      First a PR shouldn’t introduce scope screep, where you are actually introducing more than one change. And second.

                        Instead of changing everything at once, can you change the dependencies first and add the new feature in a subsequent changelist? Can you keep the codebase in a sane state if you add half of the feature now and the other half in the next changelist?
                      
                      When the only reason to change a dependency is for a new feature, you keep everything together. That way, we can revert a feature at once without needing to hunt down related commits. I abhor unused code in the main branch.

                      And I say that if you can’t review a PR as a single patch, there’s bigger problem. As a reviewer, the only thing that matters is the change and its purpose, not a particular workflow/ritual.

            • xorcist 5 hours ago
              > if you squash the commits when merging the PR?

              You tidy up and rebase before making a PR. Anything else is really disrespectful of your reviewer's time. That is also how all the larger open source projects operate.

              > you only get one commit for the whole feature

              If you are doing one logical commit per PR, you are doing way too many PRs.

              Alternatively you don't have a working review process.

              • account42 2 hours ago
                Yes, often you have separate logical changes that should still be reviewed together.
              • skydhash 2 hours ago
                Not really, because that one commit represent a logical changes to the codebase. It’s either in or not. Splitting it would be only cosmetic. That’s what a good PR in my opinion.

                Presenting a series of patches is good in an email format because when I’m adding them, I can evaluate each and decide whether I want it or not. But GitHub (and forges that copies it) is lacking in that regards without me taking over the branch.

                So the word is to make the PR the unit of changes, and only review the whole diff, not the individual commit.

            • Cthulhu_ 5 hours ago
              That's one approach, sure, probably works best if your units of work (e.g. everything inside of a PR) are small and atomic though.

              Other use cases exist where each individual commit adds value / changes something important / is atomic. Which one is best depends on the use case.

              What should definitely be avoided (or, what should not end up in main) is "work log" commits. Many people use git commit like a save / checkpoint operation, that's the kind of thing nobody needs to read. That's the "fix" commits.

              Succinct guideline:

              Good commits: "When applied, this commit will <commit message>"

              Bad commits: "I did <commit message>"

              Then whether it's one commit or the result of a squash merge it doesn't really matter much anymore.

            • locknitpicker 6 hours ago
              > Isn't this solved if you squash the commits when merging the PR?

              In theory, yes. Squashing is an extreme approach to merging fixup commits.

              It also throws the baby out with the bathwater by removing individual commits that explain and clarify how and why some changes were introduced as part or a PR.

              If your PRs are tiny and don't introduce major changes then squashing is ok. Instead, you should do the right thing and curate the set of commits featuring in your PR.

              • CuriouslyC 3 hours ago
                Making small atomic commits as you go in the age of AI tends not to go great because it forces too much human in the loop in a lot of cases, and the percentage of AI code rework is significantly higher than manual code, so the history tends to be harder to keep clean.

                It's ironically easier to create a messy agent work branch then have the agent cherry pick independent PRs from it into atomic commits post-work.

                • locknitpicker 1 hour ago
                  > Making small atomic commits as you go in the age of AI tends not to go great because it forces too much human in the loop in a lot of cases (...)

                  You seem confused. In the age of AI your ai code assistants already do task-specific commits. In fact, you can easily create a skill to have ai do that for you. It can even use git history split.

                  You see where this is going?

      • fcarraldo 10 hours ago
        Mine aren’t full of “oops” and “fix” messages, because I squashed them.
        • bonzini 8 hours ago
          So you're "spending effort in perfectly curating git history" and agreeing with your parent comment.
          • ozim 7 hours ago
            Just squash everything before merging and call it a day

            That is also a line from top comment. Everyone read „perfectly curating git history” and went rage commenting instead of reading and understanding what OP wrote.

            • bonzini 7 hours ago
              Nope. Perfectly curating history is indeed the opposite of squashing—you squash because you couldn't be bothered to curate your commits. Squashing is a workaround not an alternative solution.
              • ozim 1 hour ago
                You just contradicted your previous comment that was pointing out that fcraaldo is „spending effort in perfectly curating history” … or your comment was a joke with no indication it is a joke.
                • skydhash 21 minutes ago
                  Yep, the curated history is the main branch, which the PR targets. The commit log in the Pr reflects the workflow of the author, which I have no interest in. As the reviewer, I’m only interested in the content (the description and the composite diff of the whole PR). I don’t review commit by commit.
      • ozim 8 hours ago
        But parent wrote:

        Just squash everything before merging and call it a day.

        He didn’t write „leave a mess”. So it feels you wrote knee jerk comment or just writing whatever you wanted to write disregarding whatever was written.

      • InvertedRhodium 10 hours ago
        Depends what the git history is supposed to show. Personally, I prefer people to leave their mistakes and reversions - though I'd require more description messages than "oops" or "fix", something that explained why it was being reverted or swapped out would be the minimum.

        Sometimes you try things one way and they don't work out, so you go in a different direction. Capturing why this happened and when can go a long way towards explaining downstream decisions that might seem confusing to someone with a fresh perspective.

        • bonzini 7 hours ago
          The why for a commit belongs in the message or code comments not in the history.
      • JohnMakin 9 hours ago
        yea I look at commits several times a week at least, especially when commits are tied to a ticketing system/project it helps a lot going back months later on a large codebase going “how/why did this change happen”

        I do tend to squash or make my entire change in one commit though so maybe I misunderstood your comment. If I have a fix commit often I’ll just tag a separate PR/ticket to keep the change history/change control clean

      • crabbone 2 hours ago
        Parent doesn't have experience of working with codebases with slightly high than average code quality requirements.

        In products s.a. storage, avionics, medical appliances etc. it's very typical to have a requirement for each commit to compile and to apply tests retroactively. I.e. once a test is added against an existing feature, it is run against every commit since the feature creation (this is also why git-bisect exists).

        However, it's true that a lot of companies would probably do better with just rsync instead of Git. Their Git history is in such a bad state that it's basically useless. It just doesn't make sense to use such a complicated tool as Git to deal with the average workflow.

      • ansgar77 5 hours ago
        I think that the path that was taken should include mistakes. It's natural that code at some point would contain bugs and mistakes. If anything, your approach would encourage to squash those commits into one just to make it being review-worthy, but that misses the point then.
        • account42 2 hours ago
          It shouldn't be that path that was taken but the path that will be taken when the PR is merged, split up into as many self-contained steps as possible to ease review now as well as triage if problems are found later.
      • CuriouslyC 3 hours ago
        You sound pleasant to work with. I bet your coworkers route around you when they can, and when they can't they cherry pick from their working branch to deliver monolithic commits while rolling their eyes.
        • account42 2 hours ago
          No, he sounds like a professional with standards.
          • CuriouslyC 2 hours ago
            A professional with standards who wasn't also unpleasant would put the time in to review the content of the commits with a request to clean up the history. Someone who looks at the history, thinks to themselves "not how I like it" and just auto-rejects the entire PR without any further thought is just a bad coworker.
            • account42 2 hours ago
              No the bad co worker is the one who is trying to offload his job on the reviewer.
              • CuriouslyC 2 hours ago
                A programmer's job is to deliver business value to their employer. If you're slowing down PR turnaround by mindlessly auto-rejecting on stuff that the suits don't care about, you better have a rock solid case for why that is going to deliver business value down the line, otherwise you're actively sabotaging your employer to bikeshed your personal preferences, which is the hallmark of a bad employee.

                Rejecting an obviously bad PR after scanning the code quickly is one thing, burning business cycles on PR turnaround/latency to bikeshed bookkeeping without spending any time on the actual value producing portion of the PR is just bad. At the minimum you wasted an opportunity to give feedback on the proposed solution, thus probably necessitating another round of reviews, with the associated org latency.

                • account42 1 hour ago
                  You are assuming that the only thing the business in question cares about is moving fast without any consideration for long-term health. I'd consider that a bad place to work at.
                • skydhash 1 hour ago
                  In most business settings, the ticket is the unit of value to the business. If a ticket is to big, the best way is to split it into several ticket. Then you create a PR for each. There can be some automation that update the status of the ticket alongside the PR. Splitting a PR futher into commits doesn’t make any sense, because the whole business operates with tickets.

                  When I do it, it’s for my convenience. I expect the reviewer to review the diff at the PR level, not at the commit level. And when it’s approved, I’ll squash and merge, because only the whole PR matters.

                  When the commit is the unit of work (email workflow) I curate locally.

      • danieltanfh95 10 hours ago
        NGL AI usage is driven by friction in presentation and communication over petty details.
      • bobbylarrybobby 10 hours ago
        Do you really care if someone forgot to format before committing? They can always squash and push locally if they need to.
        • LtWorf 7 hours ago
          I really really really do not want the autoformatter stuff happening in the same commit as where the real thing happens. I don't care to review if the autoformatter is working properly.
        • locknitpicker 9 hours ago
          > Do you really care if someone forgot to format before committing?

          Not OP but yes I definitely do. If you expect others to spend time reviewing your code, you are obligated to start off by reviewing it yourself. Posting a mess helps no one and makes code harder to audit.

      • gofreddygo 10 hours ago
        Oh that is such a bad heuristic ! The commits and history of how a PR was put together is no indicator of the quality of the PR or the thought process that led to it. Thats the equivalent of rejecting a (handwritten) essay for having too many corrections. ridiculous.

        The code is all that should matter. Maybe comments for being nice to others and my future self. thats it.

        • locknitpicker 9 hours ago
          > The commits and history of how a PR was put together is no indicator of the quality of the PR or the thought process that led to it.

          It is, because it means the person posting the PR didn't even bothered to review the changes they are forcing others to review.

          Just clean after yourself before asking others to read your stuff.

    • jhealy 11 hours ago
      > No one is ever going back and reading individual commits

      I do, regularly! In a repository where care has been taken, it can be super valuable when tracking down a bug or regression, and understanding the intent of the author

      • bad_username 7 hours ago
        The debate between these who don't squash and these who do is the debate between these who use the history for bugfixing and those who don't. And I think not using it is throwing away a super valuable tool that can reduce the fix ETA by an order of magnitude.
    • jolmg 11 hours ago
      > No one is ever going back and reading individual commits.

      Straight from the git-log, maybe not, but sometimes you see code that makes you wonder how it came to be and it can help a lot to see it in context of the commit that introduced it. That'd be less helpful if that commit were some huge thing making lots of different changes at once.

      • paxys 11 hours ago
        Seeing the individual change in the context of the larger feature is actually more helpful. Otherwise you find a tiny commit that changes A to B and then have to chase down 13 other commits around it to figure out why that change was even made.
        • jolmg 11 hours ago
          Yeah, there's a balance. I try to make my commits so they make sense on their own.

          > commits around it to figure out why that change was even made.

          A commit should be such that the message can articulate the why.

    • nextlevelwizard 9 hours ago
      How do I know you don’t work in a big team from this?

      First thing I do every time I come back from vacation is to read through our git history to see what has happened.

      It is also very useful when CI breaks. In fact I probably use some form of git history reading every day at work.

      Also if your code base is so tiny and the features you work on are so small that you can just squash everything then maybe that is fine for you. I definitely love being able to actually see what is going on and selectively cherry picking or reverting commits

    • broodbucket 11 hours ago
      Having a well curated one-logical-change-per-commit history is incredibly valuable when bisecting a regression.
      • efilife 10 hours ago
        Didn't you mean "dissecting"?

        Edit: thanks guys, that's very useful knowledge! Could have saved me many times in the past

        • psadauskas 10 hours ago
          Nope, `bisect`: https://git-scm.com/docs/git-bisect

          Figure out a command to test it, a known-good sha and a known-bad sha, and it will binary search its way through the history to find the commit that introduced the failure.

        • seba_dos1 10 hours ago
          Check out "man git-bisect".
        • jolmg 10 hours ago

            man git-bisect
    • Hendrikto 4 hours ago
      I am always aghast at how proudly people pronounce that they don’t know how to use one of the most central and essential tools in the belt of a software engineer.

      Maintaining history is well worth it, and allows you to use tools like

          git rebase
          git revert
          git bisect
          git blame
          # …
      
      It also makes reviewing and understand your code much easier.
      • fragmede 4 hours ago
        git bisect, connected to a script that outputs good/bad, is one of computing's crowning achievements, imo.
    • Izkata 9 hours ago
      I do multiple times a week, with repos that have barely been touched in a decade and all the original devs are gone. Squashing would make figuring out why something is the way it is a lot more painful, so I'm glad these repos are svn where squashing wasn't an option. Several times I've discovered bugs that were introduced in linting commits that would have been squashed, so the fix ends up trivial since the intention is already there in the previous commit.
    • aardvark179 6 hours ago
      Having maintained internal forks, and having needed to pull in and rebase upstream changes I do read a lot of commits. Projects that take care with their commits are much easier to work with.

      This is also true when creating with security patches and other things that need to be backported to multiple releases.

    • CuriouslyC 3 hours ago
      Squashing everything has a significant downside compared to functional atomic commits: git-bisect gets WAY less useful.
    • christophilus 2 hours ago
      I’m with you, but it’s obviously a sensitive topic for a lot of folks, based on the replies. Some people’s brains are just wired differently, I guess. I rarely look at history, other than git blame. For me, history does not need to be granular at all. The replies make it sound like curating git history is the job, rather than shipping solutions to customers’ problems. I guess, if it helps you ship faster / better, more power to you.
    • msteffen 10 hours ago
      One use-case for curating commits other than git history is carefully structuring code reviews to be easy to review. Eg "commit 1 just rearranges existing code, no business logic changes"..."change 2 modifies business logic, but in one localized place as the refactoring has already been done"..."change 3 only modifies comments"
    • Cthulhu_ 5 hours ago
      I have a more nuanced view of this; in libraries and software projects that span years like Linux, curl, etc, this happens all the time. Bugs get fixed and they can point to the exact commit where it was first introduced, and that commit contains all information necessary to figure out why it was introduced in the first time.

      But that's projects like Linux, which is a whole different use case than for example what I do for a living, front-end applications that have at best a lifespan of 10 years and whose individual features / screens / components have less than that, and it's much more rare that an older commit is still relevant today.

      (that said, looking history up has made me dislike squash commits. I get it from a pragmatic point of view but it's not ideal)

    • seba_dos1 11 hours ago
      Of course we do and it helps tremendously when the graph is reasonable.
    • smcameron 9 hours ago
      Disagree. You need small, git bisectable commits. Use stgit to do it and it's nearly effortless.
    • EPWN3D 10 hours ago
      Sorry, no. Just because you've never done it doesn't mean that no one ever will.

      Beyond the archival benefits, I've found plenty of bugs by going back through my "wip" commits and creating a sane history from them.

    • sitkack 10 hours ago
      That is like saying once the program is done, throw away the source.

      Lemme guess all your for commit say "wip"

      • yjftsjthsd-h 10 hours ago
        It's really not. Source code, even with no history, can be modified, adapted, ported, fixed, and improved. Having history is nice, but it's way lower marginal utility.
    • Myrmornis 11 hours ago
      One good reason is to keep your tests separate from the fixes that make your tests pass. That way you can check your test fails before the next commit makes it pass, eliminating the risk of a false negative (test passes that would have anyway).
      • Cthulhu_ 5 hours ago
        That's one approach I suppose, it leaves evidence of "I wrote a test first" and such.

        However, it also feels more like a "work log" than a "commit log"; I like to make my commits atomic (test + code at the same time), so that in theory, each individual commit will pass CI. If you separate them, you can't just revert one commit, you need multiple.

      • assbuttbuttass 11 hours ago
        That sounds like it would break bisect
        • Myrmornis 12 minutes ago
          You could reorder so that the test comes in a commit after the fix rather than before if you want to be able to use plain git bisect, so that no commits are failing. The important thing is that you can use git (i.e. revert in this case) to edit the history to remove the fix and verify the test fails.
        • bonzini 9 hours ago
          You can develop with failing tests and reorder them after the code change before publishing your branch.
          • assbuttbuttass 1 hour ago
            Of course, but this thread was in the context of someone "carefully curating" their git history
        • Myrmornis 10 hours ago
          Fair. I think what I'd say is that we don't have to use plain git bisect -- it would be quick to make a bisect script that doesn't land on the failing-test commits. Especially seeing as most teams squash before merging, we should have the freedom to create failing-test commits.
        • jolmg 10 hours ago
          Right, maybe a better way to get what they're going for would be

            git checkout @~ ^tests
          
          where ^tests is zsh's way of saying * except for tests. So you get the tests/ of the current commit and the code of the prior.
        • locknitpicker 9 hours ago
          > That sounds like it would break bisect

          Nonsense. First off, you can pick the starting commit, and nothing forces you to pick the test one. Second, bisect is designed to tracks changes from good state to bad state based on your personal criteria of what good and bad is. This means that you are free to put up tests that make sense to you (i.e., all tests except the one that was added as a red test) and even not run a test at all.

          • account42 2 hours ago
            And you can also use bisect by first figuring out the broken commit some other way and then marking everything as good if its before that one or bad if its after - but that's not a very productive use of bisect and if its the only available one I think its fair to call it broken.
            • locknitpicker 1 hour ago
              > And you can also use bisect by first figuring out the broken commit some other way (...)

              Bisect exists to be a tool you can use to fix the problems you are facing.

              It you are faced by problems you create for yourself and you are unwilling to work around the problems you are creating then there is no tool on earth that can help you.

          • assbuttbuttass 1 hour ago
            Suppose we have a failing test. For many commits, gp carefully separated their change that would break our test, from the change that would fix the test. At some point, someone forgot to run the tests, and introduced a commit that broke the test without adding a second commit to fix it. Now it's treated as a "pre-existing failure," and many more commits are added on top.

            How would you identify the commit that broke the test?

            • locknitpicker 1 hour ago
              > How would you identify the commit that broke the test?

              You're asking how to use bisect.

              You start with a range of commits you picked. All that bisect does is help you search for a commit within that range that introduces a regression. The responsibility to specify which commits you cover is yours, not the tool.

              • assbuttbuttass 1 hour ago
                And then bisect fails because it finds one of the many commits that broke the test before the actual regression
    • dkdbejwi383 5 hours ago
      I could count the number of times I've written a detailed summary in the body of a commit message, and had it read by my colleague reviewing who then didn't need to leave a comment on the PR asking why I did _x_ on zero hands.
    • fragmede 8 hours ago
      > No one is ever going back and reading individual commits.

      Hell yes we are! Just because you aren't going to doesn't mean nobody else is going to.

    • locknitpicker 9 hours ago
      > No one is ever going back and reading individual commits.

      Your assumption doesn't match the real world practices I've experienced for years across multiple jobs. Even at the PR stage a clean commit history is of critical importance. Nowadays, with ai coding assistants assuming a central role in developing software, commit history is even used as input with context signal, allowing for flows such as "evaluate the changes in commit X and Y and apply the same pattern to project Z".

      Just because you don't use a tool properly that doesn't mean everyone around you makes the same mistake.

    • penguin_booze 7 hours ago
      Might as well go back to the tar.gz days, eh?
    • vcf 10 hours ago
      I almost never went back to read the history, but now I often have Claude go through the history when I wonder how we got to a certain point. It can point me to the relevant issues as well. Squashing is fine, up to a point.
    • LtWorf 7 hours ago
      Spoken like a guy who really really doesn't understand how git works and has never bothered to learn!
    • ex1fm3ta 10 hours ago
      I do not agree at all. When you have multiple repos accross different services, commits are the best way to follow up with differents changes. We adopted conventional commits guidelines a few months ago and everyone is happy. Even ClaudeCode is able to keep up and auto fix stuffs with the proper commit messages. The changelog is dynamically updated. Everything so smooth when those commits messages are perfectly synchronized.
  • shepmaster 12 hours ago
    > That last part goes further than git rebase --update-refs, which only moves refs sitting inside the range you’re actively rebasing. git history instead finds and rewrites every local branch descended from the commit (while also having an option to limit it to only the current branch).

    I'm reading that to mean that when I use `git rebase --update-refs` in this situation, where I've currently checked out `D` and update `B` to `B'`:

      A ──► B ──► C ──► D  
            │              
            └───► E        
    
    I'll end up with this state, where `E` remains untouched?

      A ──► B' ─► C' ─► D'  
      │                   
      └───► B ──► E        
    
    (EDIT: Originally I had `E` point to `B'`, which doesn't make sense)

    If I use `git history fixup`, it would also update `E` and end up with this?

      A ──► B' ─► C' ─► D'  
            │              
            └───► E'        
    
    If that's the case, is there a way to get `git rebase` to have the same behavior? I've got decades of `git rebase` burned into my fingers at this point.
    • jolmg 12 hours ago
      > I'll end up with this state, where `E` remains untouched?

      Can't, because a commit's hash takes into account the parent hashes.

      Haven't used --update-refs, but reading it, it should result in your third graph. So,

      > is there a way to get `git rebase` to have the same behavior?

      is already the case.

      • shepmaster 11 hours ago
        > Haven't used --update-refs, but reading it, it should result in your third graph.

        I don't think it does. I tried locally:

          mkdir test; cd test; git init
          touch a; git add a; git commit -m 'a'
          touch b; git add b; git commit -m 'b'
          touch c; git add c; git commit -m 'c'
          git checkout -b branched-feature HEAD~
          touch d; git add d; git commit -m 'd'
          git checkout main
          echo 'change' > b; git add b; git commit -m 'fix b'
          git rebase -i --root --update-refs
        
        And ended up with this graph (`git log --graph --all`)

          * commit (HEAD -> main)
          |
          |     c
          |
          * commit 
          |
          |     b
          |
          | * commit (branched-feature)
          | |
          | |     d
          | |
          | * commit
          |/  
          |       b
          |
          * commit 
          
                a
        
        Replacing the `git commit -m 'fix b'; git rebase -i --root --update-refs` with `git history fixup HEAD~` produces what I'd like:

          * commit (branched-feature)
          |
          |     d
          |
          | * commit (HEAD -> main)
          |/
          |       c
          |
          * commit
          |
          |     b
          |
          * commit 
          
                a
        • jolmg 11 hours ago
          Huh.. That's a shame :(. Maybe what it refers to is if you had a branch on B rather than D, it might update that.

          EDIT: Yeah, this seems to be it. `git branch b` on b, then `git rebase -i --update-ref @~3` from main caused branch ref `b` to move from d86229e to 02fcaf7:

            * 1e354fb (HEAD -> main) fix b
            * 40e6f70 c
            * 02fcaf7 (b) b
            | * f4188e0 (branched-feature) d
            | * d86229e b
            |/  
            * 5fe78fa a
        • Izkata 8 hours ago
          > And ended up with this graph (`git log --graph --all`)

          Add --oneline to get the compact version from the other reply.

      • seba_dos1 11 hours ago
        It won't result in the third graph on its own as E isn't reachable from D, but it could if you first merged D and E together and then used --update-refs with --rebase-merges. You could then just discard the merged branch and only take care of D' and E' on their own (and since you don't care about the merged branch, you don't have to care about resolving conflicts while preparing it either).
      • rmunn 12 hours ago
        Unless E remained untouched because it was not rewritten, and ended up staying parented on B instead of getting reparented onto B'.

        Which is usually not what you want; most of the time you want E', which is E reparented onto B'. But sometimes you want E to remain untouched and stay parented on the original B. Depends on the situation.

        • jolmg 12 hours ago
          Exactly, but the second graph where untouched E is reparented to B' is not something that git would allow.
          • shepmaster 12 hours ago
            Ah, good catch. That's more of a graphic issue and not what I was trying to express. Updated the OP.
    • lelandfe 12 hours ago
      • shepmaster 12 hours ago
        I'm not sure that answers my question. That shows a linear set of branches (my-feature-v3 depends on my-feature-v2 depends on my-feature-v1 depends on main). I'm asking about the case where two or more branches fork from a common ancestor and you want to fix the common ancestor.
    • m463 11 hours ago
      off-topic, but that is a very clear readable comment you left with those line-drawing characters.
  • eviks 7 hours ago
    > Every 3 months, for the last 1.5 years, I try it out for a few days, really trying to make it part of my workflow but eventually I give up and go back to git.1

    That's not really trying, let's assume you need 1 week to change ingrained workflows, so you just waste time every 3 months stopping right before the threshold. Better try once every year, but for a few*4 days...

  • paularmstrong 12 hours ago
    `git history split` is really going to help me help juniors break up their large PRs into smaller more concise changes. If only it had the option to split an entire branch in two easily.
    • jolmg 11 hours ago
      Maybe the issue is they think of a PR as an expensive thing. Would be best if they could just do the small thing and make a PR of that from the get-go. If they want to base future changes on the ones they just did, they can just create a new feature branch from right there, and just not create the PR of the second feature until the first is merged, or create it and add a note to the reviewer that it includes the changes of the other PR so they should review that one first. Should they want to add changes to the first feature, they just need to checkout that branch, do the changes, and merge to the second feature branch so they're available there.
      • CuriouslyC 3 hours ago
        Small stacked PRs are a NIGHTMARE unless your org is consistently turning around PRs in low single digit hours, and team members are working on decoupled code so you don't have any stack weaving. You end up in a situation where the engineering director and some tech leads really like tools like Graphite, while the entire team working under them mutters irately under their breath daily.
      • ellefire 6 hours ago
        It's expensive when you factor in each PR having to wait for someone to come and review it - it's easier to get your work done in larger PRs when that's the case, although it's a perverse incentive
        • account42 2 hours ago
          Even with low review turnaround, having each PR get to a defined "goal" makes it clear if the early commits that prepare the co-debase for the goal are going in the right direction. If they were submitted as individual PRs the reviewer can only check that they don't break things but has to trust the submitter that the design is right for what will follow.
          • twister2920 46 minutes ago
            easy solution is to design ahead of PR time
    • catlifeonmars 12 hours ago
      What does it mean to split a branch in two?
      • rmunn 12 hours ago
        Probably to take a series of commits and decide "this one goes on branch A, this one on branch B", e.g. if you intermingled fixing bug A and B in the same branch, you could more easily go through and assign each commit to a new branch.

        The existing workflow for that would be (there are several possible workflows, but this is what I would do):

          git checkout intermingled-branch
          git branch bugfix-A
          git branch bugfix-B
          git checkout bugfix-A
          git rebase -i
          # Edit the file, keep commits that fix bug A, drop commits that fix bug B
          git push origin bugfix-A:bugfix-A
          git checkout bugfix-B
          git rebase -i
          # Edit the file, keep commits that fix bug B, drop commits that fix bug A
          git push origin bugfix-B:bugfix-B
        • LtWorf 4 hours ago
          So git cherry-pick?
  • whilenot-dev 4 hours ago
    Cool, didn't know about `history fixup`! I only ever did the manual dance with `rebase -i` and `rebase` for all other branches. That and `history split` will sure come handy!

    What happens with a conflicting fix though? Do I still need to resolve all conflicts on the base branch and `reset --hard` all other branches?

  • quibono 5 hours ago
    > scary rebase -i commands that can leave your tree in a half-broken state if you so much as sneeze

    I'm glad to hear it, I thought that was just me. It gets especially hairy when moving commits around...

    Plus I have 3-way diffs enabled and I usually get confused by which section is which at least once a day.

    Also: does anyone know if `magit` has history support?

    • seanc 38 minutes ago
      Not as such, but out of the box you get reword and fixup as first-class rebase macros. I use them all the time.

      If you wanted to split a commit you'd still have to use a magit-assisted rebase.

      So if magit added explicit 'history' support I just about wouldn't notice, it would mostly be under the hood.

  • hahahaa 12 hours ago
    I like to be like an accountant. No editing history. Create a new "journal entry" (i.e. commit) to fix.
    • account42 1 hour ago
      There is history that has already happened (e.g. what has been merged to master) and history that will happen (e.g. unmerged pull requests).
    • seba_dos1 12 hours ago
      Commit graph is just a data structure. Sometimes it represents a "history", sometimes other things.

      Personally, I like it when project's repository represents the history of the project rather than the history of random things developers do on their machines, but you do you.

      • hahahaa 11 hours ago
        I am thinking of remote. Edits before pushing OK with me (they ate equivalent of recloning and redoing anyway)
        • seba_dos1 11 hours ago
          Remotes aren't equal either. Sometimes the remote is my other machine, sometimes it's a fork on a forge used for producing CI artifacts.

          It's a good rule of thumb to consider shared branches to be append-only, but not every remote branch is "shared" and, as with any proper rule of thumb, you can always find exceptions.

          • hahahaa 5 hours ago
            Ok I amend to what I think I really mean: don't edit history for anything deployed to prod (or released to public or customers) already.
    • what 12 hours ago
      You probably shouldn’t be committing things that are broken…
      • plorkyeran 8 hours ago
        You should be committing things that are broken all the time. Git works great as a persistent navigatible undo buffer, and you should commit every time you're in a state that you might want to return to.
      • normie3000 11 hours ago
        This is likely saying you shouldn't save a word document that contains spelling mistakes.
      • moezd 11 hours ago
        With tools like GitHub Actions and some added constraints, it's not always possible. You literally need a commit to trigger the CI workflow and it starts to trash your branch. Besides, aren't we all familiar with git commit -m "typo"?
        • ninkendo 1 hour ago
          > With tools like GitHub Actions and some added constraints, it's not always possible. You literally need a commit to trigger the CI workflow and it starts to trash your branch

          I'm with you on your overall point, but as a side note: this state of affairs is so tragic. It's been normalized for there to be test suites that nobody can run except the CI runner, and the only real way to run all the tests is to have GitHub do it. It's pure lock-in, and it's very sad that everything's moved this way.

          CI actions should be a simple file of "action: command" lines, with at most a separate file that describes when given actions should run. All actions should be runnable locally just as easily as they are in CI. Or if the actions are so complicated they need a complex-ish environment, that environment should be the kind of thing you could run locally too with your hypervisor of choice, without having to think about it. But every VCS host that has an actions/pipelines product is financially incentivized to encourage you not to set things up this way, to preserve their lock-in.

      • hahahaa 11 hours ago
        Commit yes you absolutely can. Merge to trunk? Probably not, depends on your strategy.
  • krick 8 hours ago
    > scary rebase -i commands that can leave your tree in a half-broken state if you so much as sneeze

    Complete bullshit. Might as well say "scary screwdriver that can turn up in your recturm if you so much as sneeze". Sure, I believe that might have happened to you (heard stories from friends that work in the emergency room), but I run rebase -i 10 times during the time I work on each branch (literally: I don't even care to write "proper" commit messages while writing the code, will reorganize and clean them up later anyway), and it never happened to me.

    • eviks 8 hours ago
      > commit messages while writing the code, will reorganize and clean them up later anyway

      That's just too primitive of a workflow, so repeating it will not run into the risk. You need to add an actual conflict in some feature branch and get stuck being forced to resolve it to compete the rebase to appreciate the op warning

  • runtime_lens 7 hours ago
    git reflog is probably the Git command that has saved me the most stress. At some point you stop worrying about experimenting because you realize it's surprisingly hard to lose work permanently. Git is muuch more forgiving than it first appears.
  • bentt 12 hours ago
    Granted, I have a perspective of a game dev, but this kind of repo defiling just gives me the willies. IMO instead of finding a common ancestor and altering it, just make the desired change upstream and merge it to where it’s needed. If you can’t do that then you have already made a deal with the devil and might reconsider your approach. KISS
  • _nivlac_ 11 hours ago
    I like `git history reword`, would've found that useful in the past (e.g. fixing a bad typo in an older commit).

    It sounds like there was probably an equivalent using an existing command but this is easier for me to understand. Thanks for sharing!

  • froh 9 hours ago
    TIL, thx :-)

    somewhat related Q:

    how do you give two files the same ancestor? so git log will for each show the history to the beginnings of the originally unsplit file? useful for splitting large files.

    • bonzini 9 hours ago
      That's not possible, because files don't have ancestors in git. Each commit's tree is tracked independently and copy/move is just something that's detected via heuristics.
      • account42 1 hour ago
        But those heuristics could be better than they are now so that a git log <file> will show the shared history for both copies.
  • anuramat 5 hours ago
    is there a way to use it with lazygit? unfortunately I'm addicted atp, and "autorebase branches" is exactly what I was missing the entire time
  • SCUSKU 6 hours ago
    These graphics are great. Makes for a skimmable high signal article, nice work!
  • rushil_b_patel 8 hours ago
    the "reword" option is same as git rebase -i HEAD~n, and then instead of pick replace it with reword to change the commit messsage.

    BTW I have made a notion doc on git commands: https://rushilpatel.notion.site/git

  • kazinator 7 hours ago
    The thing is, when you are rewriting history to change an old commit, you have to solve the little problem that git commit messages refer to hashes such as:

       This regression was caused in <hash> on December 19, 2017.
    
    The fixup and rewrite of history has to ferret out these has references and fix them to the new hash of the same commit.

    I have scripted this before!

  • Sharlin 5 hours ago
    Huh, TIL about `git commit —fixup`.
    • Cthulhu_ 5 hours ago
      Yeah I learned that one a few months ago, before that I'd use interactive rebase and shuffle the commits around manually in the editor that opens.

      I appreciate that these commands are just utilities / conveniences on top of a stable base though.

  • smcameron 9 hours ago
    > Working with lots of changes in parallel on git can be painful. You end up juggling branches and commits, and running scary rebase -i commands that can leave your tree in a half-broken state if you so much as sneeze.

    I mean, just use stgit[1] to maintain a stack of patches instead of parallel branches, it's so much better. You can easily wrangle thousands of patches (aka commits) with stgit.

    A lot of people, on first encountering stgit, read a bit about it, think "why do I need this? I can do the same thing with just plain ol' git.". Yeah, you can. But not at scale. Not practically. Not with thousands of commits. And it makes the case when you just have a few tens of commits absolutely trivial. Try it for awhile and you'll find it indispensible.

    [1] https://stacked-git.github.io/

  • blackcube42 0 minutes ago
    [flagged]
  • skydhash 12 hours ago
    > Working with lots of changes in parallel on git can be painful. You end up juggling branches and commits, and running scary rebase -i commands that can leave your tree in a half-broken state if you so much as sneeze.

    I think that only happens when you work on code as text files (i.e character streams) instead of code (i.e structured content with meaning). Like you have commit A and commit B that is in conflict, you should be glad because that's a rough signal that the intent of A and B differs. Your goal should be to think about how to compose A and B so that both intent survives (unless one supersedes the other). Which means you should be at least familiar with A and B.

    The issue I found with people that fears conflict is that they often don't understand either A or B (or both). So they are a bad candidate to actually do the operation. It's not a matter of git's cli interface, it's a matter of codebase comprehension and how well you're familiar with the changes in question.

    • thfuran 12 hours ago
      Git is the one treating code like a text file instead of code.
      • UnfitFootprint 12 hours ago
        I pull out difftastic when it’s all too hard for this. Diffs based off tree sitter
        • NateEag 7 hours ago
          Don't forget mergiraf, for tree-sitter-based conflict resolution:

          https://mergiraf.org/

          • klibertp 6 minutes ago
            I absolutely love the images on the landing page. "Inappropriate use of blame, push and pull to resolve a conflict" is pure genius. Even the name had a lot of thought put into it (didn't know about "Giraffe language" before). Beautiful! :)
      • skydhash 11 hours ago
        Git store whole files. The diff and the merge algorithm works by line by default, but that's because line is a rough unit of code (statement, expression, and definition happens mostly within one line).
    • bulatb 12 hours ago
      I can fully understand a conflict, know it's coming, and fear it anyway because I'll have to deal with Git's behavior to fix it.
      • seba_dos1 12 hours ago
        Such as?

        When you merge a commit in that changed a file that has been already changed since the common ancestor, Git runs a tool of your choice on this file. If the tool fails, it marks the file as needing a merge and doesn't let you commit it until you unmark it to confirm that you have merged it manually. In case of octopus merges, it will just abort early. That's basically its whole behavior when it comes to conflicts.

        • bulatb 11 hours ago
          Such as moving down a fixup during interactive rebase when it's going to conflict with parents, or I've added more commits mid-rebase, or the rebase started in a tool and now I need to think about the tool's command and understand how many times the rebase point is view is backwards to interpret which is "ours" and which is "theirs" and whether it's the tool, my editor, or my own experience I should ignore because it's going to mislead me.

          None of that word salad should matter, but it does. Git will ruin everything with glee and there is always an excuse for why that's fine and it's the user's fault.

          • seba_dos1 11 hours ago
            There's nothing "backwards" in "rebase point of view". It's just automated cherry-picking - it's like applying patches, it's as forwards as it gets. People who think it's "backwards" usually just have holes in their mental model of the repository. And yes, I find tools doing what you're asking them to do to be rather fine. In fact, Git makes it easy to notice when you're adding commits mid-rebase, which is something I often do intentionally, as it tells you what the HEAD is (and even shows a detailed state of the in-progress rebase) while authoring the commit message.
            • bulatb 11 hours ago
              I understand how rebase works and use it many times a day. Thanks for trying to explain but I won't respond further.
              • seba_dos1 11 hours ago
                These aren't troubles of someone who understands. If anyone else reading this has these kinds of troubles too - don't worry, understanding abstractions takes time and effort, you'll get there eventually (not if you'll keep blaming others though).
                • bulatb 10 hours ago
                  Let me eat the crow of getting drawn back in and cap this conversation with a summary. I think this is important because criticizing Git's UX is always like this.

                  OP: No one should be worried about using Git to do a thing.

                  bulatb: I'm worried it will be unpleasant.

                  seba_dos1: Here is what will happen when you do the thing.

                  bulatb: I know, but doing it will be unpleasant.

                  seba_dos1: You must not understand what's going to happen.

                  bulatb: I do. The process is unpleasant.

                  seba_dos1: You must not understand what's going to happen.

                  • seba_dos1 10 hours ago
                    Had you actually read what I wrote, you would rather summarize it as "Git is showing exactly what's going to happen when you attempt to do it, all you have to do to make is pleasant is to not ignore it". Reading things requires unpleasant effort though, I get it.
                    • bulatb 9 hours ago
                      I'm sorry (like actually sorry) if I'm getting into counter-condescension here, but, like...

                      > all you have to do to make is pleasant

                      This is an assumption about what I find unpleasant and why. I take it you think "reading information" and "understanding instructions" are some of those things I don't like. Your conclusion that I must not understand is based on that assumption.

                      The assumption is wrong.

                      If you can grant me that, my problem looks different. If you can't or won't, my summary was right.

                      • seba_dos1 8 hours ago
                        If the assumption was wrong, then your first comment was pretty much useless, and the second one didn't help either as it just describes doing things carelessly and without proper understanding. So if that reading of it is wrong, then it was just complaining for complaining's sake and not about Git at all, but rather about what you happen to find scary for some undisclosed reason?

                        People do have genuine troubles with these behaviors when they don't grasp what's going on well enough. These troubles go away pretty much entirely once they do. I think explaining them is the only thing one could write in such thread that will be useful to anyone, as the Git's UX already does make a pretty good effort to help the user orient themselves in these cases and has been visibly improving in this regard over time.

                        • bulatb 4 hours ago
                          My point to the OP is the same thing I'm saying to you. "I understand the thing and think it's fine" does not imply that nobody who understands the thing can think it isn't fine, or anyone who doesn't like the thing just doesn't understand it.

                          It's not some deep or interesting idea, but it needs to be repeated any time "git gud" is used as an excuse for Git's UX, which is always.

          • skydhash 11 hours ago
            > which is "ours" and which is "theirs"

            "ours" is always HEAD, usually meaning the state of the working_tree, "theirs" is always the commit that is going to change the working_tree.

            When merging, you are taking change from another branch (theirs) to create a new commit on the current branch (ours) that ties the two together. When rebasing interactively, you switch to the new base (ours) and replay the changes of the branch (theirs) according to the edit file.

            Etymology matters. The conceptual model of git is simple, but people only focus on the operations. That's like trying to learn algorithm and data structures and focusing on the words "insert", "remove", "find", without trying to learn "list", "stack", "tree",... first.

            Instead learn about Git's glossary [0], then how the operations use and modify those concepts.

            [0] https://git-scm.com/docs/gitglossary

  • cnxiaom 4 minutes ago
    [flagged]
  • tangsoupgallery 2 hours ago
    [flagged]
  • jocelyner 10 hours ago
    [dead]
  • xyzsparetimexyz 6 hours ago
    Tldr; use jj