Live data from Hacker News

Git-absorb: Git commit –fixup, but automatic

github.com

231–240 of 278 posts

Re: Git-absorb: Git commit –fixup, but automatic

#231
post #18

As a frequent user of fixups, this feels like a solution for already broken workflows. > Instead of manually finding commit SHAs for git commit --fixup Assuming you are using fixups, is this actually a problem? I could see this being a possibility if you are: A. not practicing atomic commits or B. have so many commits in your branch that this is a chore. A. seems unlikely if you are already using fixups and B. seems…

> Assuming you are using fixups, is this actually a problem?

No. They made a whole tool around a not-actually problem.

Sure you can have a 30-commit branch. Find some OSS project where someone has been doing a large project on a branch for two months because the maintainer hasn’t accepted it yet.

Re: Git-absorb: Git commit –fixup, but automatic

#232
post #101

Earlier quoted context omitted.

I wasn't aware of this particular workflow, but I've heard of similar ones before. The late Pieter Hintjens, of ZeroMQ fame, advocated for a strategy called "optimistic merging"[1], which essentially abandons the standard code review process in favor of merging changes ASAP, and fixing any issues as they arise later. I'm not a fan of this. It allows contributors to abandon any established coding standards, while plac…

After having done a few thousand CRs, I've come to believe that CR is of mixed value. Not always good, nor all good. Removing the bad CRs and doing CR when it is useful IMO helps maximizes productivity. First, I assume a few constraints on "ship, show, ask." First constraint is that all changes go for at least one, if not multiple self reviews. Second, the ability to ship is not outright granted. Until someone has de…

Thanks for your perspective. It's interesting to hear a different take on this.

I do think there's no right or wrong answer with these things. Everyone will have different opinions about their ideal workflows, especially senior engineers. The important thing is to find a good balance that everyone on the team is satisfied with, but there will always be concessions, as in any relationship.

What I have found, though, is that the more uncertainties a workflow has, the higher the chances of misunderstanding, or someone not following it in the way someone else thinks they should. So with the way "ship, show, ask" is described, and what you mention here, is that there are many constraints, and decisions to be made about what constitutes an "interesting" change, or what is worthy to be shipped without a CR and what isn't. If the team is mostly senior, and there's a lot of trust involved, this workflow might work, and it might reduce the friction of blocking CRs. But there are a lot of variables involved there.

OTOH, by always requiring CRs and approvals for shipping, there are far less decisions to be made. The workflow is simple, fixed and known to everyone. Sure, sometimes CRs step into nitpicky territory, but this is usually solved by having some conventions, such as making clear what is a nitpick, what is a minor/major suggestion, and what is a blocker. This way nitpicks and minor suggestions can be safely ignored (as long as they're ackgnowledged in some way), and they're not blockers for merging.

In practice I've found that while this workflow does take considerable time and effort, in the vast majority of cases it leads to higher quality code. Even addressing nitpicks and typo fixes is an improvement in most cases. These can be easily automated by suggestions in GitHub, which can be batched and committed directly from the web UI, so it doesn't take much effort at all.

> Last, post merge reviews can still be done by the maintainers to ensure things are going smoothly.

Sure, but is this diligently done? And how well does it scale if the project has many contributors, but few maintainers? Placing the burden on maintainers to ensure certain quality standards is unrealistic. Moreover, it assumes that maintainers have the final say in these matters, instead of their changes also being worthy of discussion, which happens during a CR. I think that the responsibility for ensuring things are running smoothly should be shared by every member of the team, including external contributors.

> Most projects I've seen are written quickly and in large chunks. If they are reviewed at all, it is a lot of 2000 line "LGTM", zero comment reviews.

Those are examples of not doing CRs correctly, not a testament that CRs are not worth the time and effort. You can just as well run into this issue with the SSA workflow. As with any issue with team dynamics, this should be resolved by communicating and aligning on core values and practices the team finds important.

> The CR debates the absolute best naming, original intent, spending magnitudes more time than was originally put into the code in the first place.

Yes, this is to be expected. It takes much more effort to read and understand code than it does to write it. It takes additional time and effort to leave a written comprehensible review, and communicate all of this asynchronously. This scales linearly for every member in the team, and there's no way around it. But the question is whether deciding to invest the time and effort in a well established CR process ultimately results in higher quality software being shipped. In my experience, it does, and it's worth it.

That said, CRs are not the only or, even failproof, method of quality assurance. As mentioned in the SSA article, pair programming is another method, but it has its own drawbacks and limitations. All of these things help, and are best used in combination. They can be uncomfortable, tedious and seem pointless at times, but deciding to not do them because of this is doing a disservice to the final product.

Re: Git-absorb: Git commit –fixup, but automatic

#233

Earlier quoted context omitted.

The term Stacked PRs already sounds like a term that was invented specifically in order to communicate in a GitHub-influenced context. Because Stacked PRs are just a reinvention of being able to review a commit at a time (the stack part is straightforward).

Stacked PRs are like being able to review a commit at a time, but add an additional layer of sequencing. It's most simply thought of as a patch series, where the evolution of each 'patch' is retained. That additional layer allows finer grained history and to mostly avoid (unreviewed) rebasing. Many teams find those properties valuable.

In this day and age I don’t understand why we just can’t call tings commits instead of patches or changesets.

I guess another pet peeve for me.

https://news.ycombinator.com/item?id=41659650

Re: Git-absorb: Git commit –fixup, but automatic

#234

Earlier quoted context omitted.

I have this one in mine: https://github.com/paul/dotfiles/blob/master/git/.gitconfig#... # make a fixup commit for the last time the file was modified cff = "!f() { [ -n $@ ] && git add $@ && git commit --fixup $(git last-sha $@); }; f" # Get latest sha for file(s) last-sha = log -n1 --pretty=format:%h --grep 'fixup!' --invert-grep Given a file like `git cff path/to/file.rb`, It'll find the last commit that touched t…

It won't matter until it does, but $@ expands arguments into separate words but those expansions are themselves only word-preserved if the $@ is itself quoted. The [ will probably get away with what you want, but its use in $(git add) and $(git last-sha) almost certainly will not $ cat > tmp.sh

Yeah, you're probably right. I guess I haven't run it on any files with spaces in the 6 years since I added it to my dotfiles.

Re: Git-absorb: Git commit –fixup, but automatic

#235
post #93

Earlier quoted context omitted.

> The PR is the thing that gets signed-off on, and the thing that goes through the CI build/tests, so why wouldn't that be the thing kept as an atomic unit? Because it often isn't. I don't know about your experience, but in all the teams I've worked in throughout my career the discipline to keep PRs atomic is almost never maintained, and sometimes just doesn't make sense. Sometimes you start working on a change, but…

> Because it often isn't. I don't know about your experience, but in all the teams I've worked in throughout my career the discipline to keep PRs atomic is almost never maintained, and sometimes just doesn't make sense. Sometimes you start working on a change, but spot an issue that is either too trivial to go through the PR/review process, or closely related to the work you started but worthy of a separate commit. O…

I don't have time to reply to all your points, but regarding this:

> I don't need to know that a typo was fixed in iteration 5 of feedback in the PR that was introduced in iteration 3. It's not relevant once the PR is merged.

I agree, these commits should never exist beyond the PR. But I go back to my point about atomic commits being misunderstood. It's not about keeping the history of _all_ changes made, but about keeping history of the most relevant ones in order to make future workflows easier. A few months from now you likely won't care about a typo fix, but you will care about _why_ some change was made, which is what good commits should answer in their commit message. Deciding what "atomic" truly means is often arbitrary, but I've found that making more granular commits is much more helpful than having fewer and larger commits. The same argument applies to the scope and size of PRs as well.

Re: Git-absorb: Git commit –fixup, but automatic

#236
post #93

Earlier quoted context omitted.

> The PR is the thing that gets signed-off on, and the thing that goes through the CI build/tests, so why wouldn't that be the thing kept as an atomic unit? Because it often isn't. I don't know about your experience, but in all the teams I've worked in throughout my career the discipline to keep PRs atomic is almost never maintained, and sometimes just doesn't make sense. Sometimes you start working on a change, but…

> I find conventional commits helpful when deciding what makes an atomic change. I already know if I’m doing a fix, a refactor, a “chore” etc. Conventional commits just happen to be the ugliest way you can express those “types” in what looks like English.

Yeah, well, that's just, like... your opinion, man.

But I've worked with many, many developers who don't strictly separate commits by type this way. I myself am tempted to do a fix in the same commit as a refactor many times. Conventional commits simply suggest, well, a convention for how to make this separation cleaner and more explicit, so that the intent can be communicated better within a team. I've found this helpful as a guide for making atomic changes. Whether or not you write your commit messages in a certain way is beside the point. But let me know if you come up with a prettier way to communicate this in a team.

Re: Git-absorb: Git commit –fixup, but automatic

#237
post #123

Earlier quoted context omitted.

The point of history is so that other people (or your future self) can look back at the history of the code and understand how it changed and why changes were made. There's zero value in retaining mistakes that were never merged into `master`. In fact there is negative value because it makes the history harder to follow. For example would you rather see "review fixes" in Git blame, or the actual useful commit message…

> There's zero value in retaining mistakes that were never merged into `master`. Not to be too pedantic about this, it sounds like you mean flawed commits that were merged into master, but never had a chance to be the HEAD of master? (In other words, they always arrived along with a fix-commit too, so that nobody checking out code could've hit the bug.) > In fact there is negative value because it makes the history h…

> flawed commits that were merged into master, but never had a chance to be the HEAD of master

Yeah exactly.

Re: Git-absorb: Git commit –fixup, but automatic

#238
post #232

Earlier quoted context omitted.

After having done a few thousand CRs, I've come to believe that CR is of mixed value. Not always good, nor all good. Removing the bad CRs and doing CR when it is useful IMO helps maximizes productivity. First, I assume a few constraints on "ship, show, ask." First constraint is that all changes go for at least one, if not multiple self reviews. Second, the ability to ship is not outright granted. Until someone has de…

Thanks for your perspective. It's interesting to hear a different take on this. I do think there's no right or wrong answer with these things. Everyone will have different opinions about their ideal workflows, especially senior engineers. The important thing is to find a good balance that everyone on the team is satisfied with, but there will always be concessions, as in any relationship. What I have found, though, i…

> what constitutes an "interesting" change, or what is worthy to be shipped without a CR

FWIW, I have not seen much trouble in the ambiguity. Things like "move method" refactor, typo fix, add additional test cases, comment clarification, are just shipped. If the update makes an important clarification on a comment that the team should know about, show is interesting. If the code fixes a bug, would be mentioned in a stand up- show is good. Ask is good for a large refactor where there is room for error, when something does not seem clean, merits any type of double check or second opinion, or and especially when it is a first foray into a different part of the codebase.

> Sure, but is (post merge reviews) diligently done?

The beauty I would say is that it does not have to be diligently done. Feature, not a bug.

If the lead maintainers are super busy, it is okay. Perhaps they will have time later and can do things in bulk, or even not at all. The process is no worse and does not stop when the majority of lead maintainers are on vacation.

Interesting changes are still notified via email (thru PRs). This highlights what a person should be looking at.

I think this attitude gives more trust to the team and contributors. It is not the responsibility of just the maintainers and seniors to (pre or post) review everything. No blame game of: "how did this bug get through, and more importantly, how did it get through review??"

> And how well does it scale if the project has many contributors, but few maintainers

Good question. Offhand I would say no worse. Contributors would all be required to ask, which is no different than 'review everything.' The difference would be for maintainers, they would not be required to always have other maintainers do CR in every case. A second potential difference, contributors might be promoted more quickly to have write permission. That in turn helps scale the efforts of the maintainers.

I think this shines on the other extreme when there are very few maintainers. OSS requiring week long turn around times will have trouble onboarding contributors to be regular maintainers. In industry, trusting developers relatively quickly I think is healthy.

The mentality to be looking to give people write permission sooner rather than later IMO is good.

> Those are examples of not doing CRs correctly, not a testament that CRs are not worth the time and effort.

My apologies for not conveying the example clearly. The examples I'm thinking of usually had no review. These are older code bases written long ago before CR. Or, these are startup quality code bases where a few founders jammed out tons of code. Or, code that was put out during a crunch, almost always successive crunches, where the constant pressure to ship was everything. Or, some Greenfield project that was jammed out and then handed over for maintenance and enhancement. Just large codebase that were never great. I'm also implying there is often a different standard for originally authored code compared to changing existing code.

My point is there is a quality bar that is suddenly higher, a lot higher, than the existing code.

> But the question is whether deciding to invest the time and effort in a well established CR process ultimately results in higher quality software being shipped. In my experience, it does, and it's worth it.

I agree, though not sure if actually always worth it. Projects are rarely labelled a failure, but many are. That can manifest as simply too much time going by without enough being shipped.

Though, good CR culture is indeed very valuable. I think it is more an exception than the rule.

I think that complements SSA at the same time. A strong CR culture with review everything might be hard to distinguish from SSA. In that sense, "ask" could be thought of as "second opinion." When a team gets crunched, there is more flexibility. Or, if the team is immature w.r.t to CR, or if there is a significant lack of reviewers- SSA removes barriers.

The idea is to capture 95% of the benefit of CR with 50% the cost.

> Sure, sometimes CRs step into nitpicky territory

Pointing out typos IMO is useful. Though, I've learned to personally delete any CR feedback I write that starts with "nitpick." I no longer believe it to actually be all that helpful or productive. It is a signal that a style discussion is due. It is important I think to respect that a CR is a blocking thing. Keeping someone an extra whatever amount of time for nitpicks is missing the bigger picture of what is important IMO

----

I very much appreciate the dialog and perspective! Thank you for your considered feedback here. I largely agree with your points, particularly the ones I did not respond to.

I suffer a bit too from the lesson of things taking too long is it's own failure mode. Success is not at all guaranteed, even if quality and solid code is shipped. At the same time, solid and quality code is required to scale, and is required for most success. That is to say that projects do fail very much in spite of quality engineering.

Re: Git-absorb: Git commit –fixup, but automatic

#239

FWIW, I've been using this alias for the past couple years for fixup commits, and I've been happy with it: > gfx='git commit --fixup $(git log $(git merge-base main HEAD)..HEAD --oneline| fzf| cut -d" " -f1)' It shows you the commits on the current branch and lets you select one via fzf. It then creates the fixup commit based on the commit you selected.

Funny that I've been doing something nearly identical, but with way more boilerplate.

    fzfCommit() {
      local FZF_PROMPT="${FZF_PROMPT:=Commit: }"
      git log --oneline | fzf --border --prompt="$FZF_PROMPT" --height=10 --preview="git show {+1} --color=always" --no-sort --reverse | cut -d' ' -f1 | tr '\n' ' ' | sed 's/[[:space:]]$//';
    }
    function gfixup {
      local commit=$(FZF_PROMPT='Fixup Commit: ' fzfCommit)
      if [[ -z "$commit" ]]; then
        return 1
      fi
      set -x
      git commit --fixup "$commit" --allow-empty > /dev/null || return 1
      git rebase --interactive "$commit"~ --autosquash || return 1
    }

Re: Git-absorb: Git commit –fixup, but automatic

#240
post #124

Earlier quoted context omitted.

Patch series comes from the linux kernel workflow, which git was developed to support. https://kernelnewbies.org/PatchSeries In this workflow you review every commit and not just the branch diff. Each commit is crafted carefully, and a well crafter series of commits can make even very large changes a brief to review. It takes a certain skill to do this well. As the page above says > Crafting patches is one of the cor…

That’s a nice summary. What I don’t like about the Git documentation as I’ve read it is that they go between “patch” and “commit” in some places without stopping and explaining what the difference is. It makes sense to them. It’s obvious. But it isn’t necessarily obvious to most people. A patch is a patch proper plus a commit message encoded in a format that git am understands. That’s fine. And the core developers un…

I think part of the confusion is because 'patch' and 'commit' (really snapshot) are duals of each other, but in practice have important technical differences. When speaking abstractly about 'changes' it often doesn't much matter which term is used, but most interactions are with 'commits' so that tends to be the default term to use.

However, sometimes the details matter. For example, a 'patch' (diff + description) tends to be small enough to transfer conveniently, and human friendly. Patches do not describe their relationship to other patches, so it makes sense to talk about a series of patches which must be applied in sequence to accomplish some larger goal. 'patch' doesn't imply any particular storage format, so sometimes saying 'attachment' or 'patch file' or 'email body' is an important distinction. Git documentation assumes you know what you want. It might help to think of patches as "outside time", though of course any particular version of a patch will only apply to a subset of all snapshots.

A 'commit' (snapshot + description), on the other hand, tends to be large in that it describes the entire state of the codebase and contains (implicit or explicit) metadata describing its predecessor(s) -- possibly a large graph of them. People talk about a 'commit series' all the time, but use the terms 'history' and 'branch' instead.

Stacked PRs are built on top of commits and branches to gain the advantages of a patch series while retaining the advantages of snapshots. There's no industry consensus on if they are preferable, let alone how to best implement them (eg. rebase, rebase+squash, merge-squash, merge+first-parent, etc.), so different people have different ideas about what they look like. It isn't correct to say they are just a series of commits, because sometimes they are implemented as a series of (implicit or anonymous) branches. One of the few agreed-upon features of stacked PRs (or its other names) is that it is a sequence of 'changes' which are ordered to both satisfy change dependencies and broken into smaller pieces which "tells a story" to reviewers.

Post reply on HN