Live data from Hacker News

The git history command

lalitm.com

291–300 of 330 posts

Re: The git history command

#291
post #2

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.

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.

The implication seems to be that `git history` is the higher level, safer `git rebase` for common scenarios. If you are already comfortable with `git rebase` you might just keep using it and never need `git history`. If you are learning git as a junior developer (or teaching/mentoring a junior developer on it) `git history` becomes a good, safe stepping stone for a handful of common tasks.

I've been in workplaces where I wished I could disable `git rebase` for all junior developers because they kept learning its footguns faster than its capabilities. A stepping stone seems like a really good idea to me.

Re: The git history command

#292

Earlier quoted context omitted.

> 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 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 o…

Switching branches involves: updating the field marking "current branch", and then updating the working copy to reflect the objects referenced. So for all trees/files, recursively restore wc to match the referenced blobs. Restoring a different version of a specific file/tree, involves recursively restoring wc of those files/trees to match the referenced blobs. So both are actually primarily the same task. Knowing a l…

you can use git switch to change branches

Re: The git history command

#293
post #127

Earlier quoted context omitted.

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.

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.

A PR is an atomic thing, but at a higher level. It's an integration point. Merge commits are a great representation of an integration point. `git log --first-parent` gives you an integration log. Without `--first-parent` you have a "conversation log" with details about how PRs were formed.

`git bisect --first-parent` lets you start with your integration points (your PR merge commits), and because presumably you have Continuous Integration and make sure integrations points build and test successfully that should be a rather quick discovery run, and then when you discover the PR that introduced the issue, you have an opportunity to drill down into the even smaller specific change inside that PR that introduced the issue.

Merge commits are a navigation tool and an integration log. It seems useful to me to prefer them over rebases and squashes.

Re: The git history command

#294

> 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 upda…

> 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.

One of the GitHub blog posts of git changelog highlights implied that this new power of `git history` was certainly under discussion for a possible feature addition to `git rebase` but it is partly still a discussion because it is a higher-level function and if the goal is to keep `git history` the "high level" and `git rebase` the "low level" then such features probably make sense to remain only in `git history` for now.

It also sounds like there are camps thinking `git history` is only the learning path to make a better `git rebase` UX and eventually the commands will reconverge somehow.

Both sides of that conversation sound worth exploring to me, and I'm curious to hear how that conversation continues.

Re: The git history command

#295

Earlier quoted context omitted.

Switching branches involves: updating the field marking "current branch", and then updating the working copy to reflect the objects referenced. So for all trees/files, recursively restore wc to match the referenced blobs. Restoring a different version of a specific file/tree, involves recursively restoring wc of those files/trees to match the referenced blobs. So both are actually primarily the same task. Knowing a l…

you can use git switch to change branches

I know, I use switch and restore now (for the most part). I'm explaining how knowing the internals does help understand the 2 use-cases being originally implemented via 1 command, i.e., checkout. The post I was responding to said the checkout case ran counter to the idea that knowing the internals helps use the commands, when it's actually a pretty standard case where it does help.

Re: The git history command

#296
post #18

Earlier quoted context omitted.

What does it mean to split a branch in two?

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 gi…

Fun fact, you can also automate more of that existing workflow with the rebase interactive TODO list. Roughly something like:

    pick $ACOMMIT1
    edit $ABMIXEDCOMMIT # split out A parts
    pick $ACOMMIT2
    exec make test # test everything compiles
    update-ref bugfix/A
    exec git switch --detach main # new branch point
    pick $BCOMMIT1
    edit $ABMIXEDCOMMIT # split out B parts
    pick $BCOMMIT2
    exec make test
    update-ref bugfix/B
    exec git merge bugfix/A
    pick $FOLLOWUPCOMMIT
    exec make test
    update-ref intermingled-branch # or bugfix/C
It's been a while since I've attempted a rebase TODO list that wild, so I may have forgotten something, but rebase interactive is pretty wild what it will let you try to automate.

Re: The git history command

#297

Earlier quoted context omitted.

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.

A PR is an atomic thing, but at a higher level. It's an integration point. Merge commits are a great representation of an integration point. `git log --first-parent` gives you an integration log. Without `--first-parent` you have a "conversation log" with details about how PRs were formed. `git bisect --first-parent` lets you start with your integration points (your PR merge commits), and because presumably you have…

> you have an opportunity to drill down into the even smaller specific change inside that PR that introduced the issue.

But what would be the point?

Let’s say you found an issue in the first commit of the PR (assuming it’s curated and every commit can compile). But the PR is atomic, and later commits rely on the assumption made in the first one. You would need to replay the later changes as well to figure out the impact.

Squashing PR means you consider changes at an holistic level regardless of the workflow that created them. If a PR fails with a regression test, the whole thing is suspect, and I don’t really care when in the workflow it was introduced.

If I have a PR titled “Add support for flac files” that introduced a regression, I don’t really want to know if the bug is on the commit “extract sampling information” or the commit “support flac tags”, because what got released was the PR, not individual commits. Just like no one care if a typo was introduced in draft 5 or draft 8. The only things that matters is when it got published.

For me PR are releasable patches. Individual commits in them are the engineer’s workbench. Whether you want to curate the latter is up to you, as long as the PR is atomic.

Re: The git history command

#298

Earlier quoted context omitted.

A PR is an atomic thing, but at a higher level. It's an integration point. Merge commits are a great representation of an integration point. `git log --first-parent` gives you an integration log. Without `--first-parent` you have a "conversation log" with details about how PRs were formed. `git bisect --first-parent` lets you start with your integration points (your PR merge commits), and because presumably you have…

> you have an opportunity to drill down into the even smaller specific change inside that PR that introduced the issue. But what would be the point? Let’s say you found an issue in the first commit of the PR (assuming it’s curated and every commit can compile). But the PR is atomic, and later commits rely on the assumption made in the first one. You would need to replay the later changes as well to figure out the imp…

The point is your ability to find needles in a haystack increases. A PR often is bigger than a 10-line change, but is often made up of smaller 10-line changes.

The ability to drill down with a second `git bisect` run (now with a known base and end commit, and even the ability to again use `--first-parent` to ignore merges inside the PR commit range) into the original contents of the PR is the ability to automate finding your needle in a 10-line change with its own git commit message and its context in the original conversation flow in the original PR.

That's a powerful ability.

Sure, you can probably comb the complete 100 or 1000 or 10,000 line PR to find the exact lines that caused that regression, you've narrowed down already to one useful haystack, but it's nice to have an optional second layer to break your haystacks down further sometimes.

(Especially if it turns out to be a regression from a merge commit inside that PR. Accidental bad merges happen all the time. Spotting them is hard sometimes. Spotting them after a rebase/squash happened is sometimes impossible because there's no unique record of the conflict resolutions unlike with a merge commit.)

Re: The git history command

#299

Earlier quoted context omitted.

If you ignore gravitation, a sphere earth can be very confusing.

If your system's public API requires me to understand all the internals to use it, then it's indeed confusing.

The common stance is that people try to use said API without reading the docs. Like the first paragraphs of the git-rebase description

  Transplant a series of commits onto a different starting point. You can also use git rebase to reorder or combine commits: see INTERACTIVE MODE below for how to do that.
And then later

  Rebasing interactively means that you have a chance to edit the commits which are rebased. You can reorder the commits, and you can remove them (weeding out bad or otherwise unwanted patches).
Those are obvious IF you know what a commit is and how they relate to each other (a DAG). But most people don’t. Instead, their only knowledge is what they’ve seen the operation do (tutorial or youtube video).

Git itself has a glossary[0] of the terms used in the docs.

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

Re: The git history command

#300

Earlier quoted context omitted.

Hence GP's advice, > Just squash everything before merging and call it a day.

For a change small enough to fit in one commit, that works. For a larger merge, you might still want multiple commits merged together. For example "make the foobar extensible" and "extend the foobar to add the baz" are really two separate changes that may be merged as part of a single PR to add the baz.

“make the foobar extensible” has no value without also “adding baz”. If I need to remove baz, I can’t just revert “adding baz”. The extensible foobar needs to go as well because it’s a unused abstraction.
Post reply on HN