Git as a debugging tool
lucasoshiro.github.io
lucasoshiro.github.io
My opinion: Write readable messages, scope your commits to simple changes, put them on a branch, use `--autosquash`, put the ticket ID in the merge commit's message. It really isn't hard.
> Also, if you have mandatory squash and merge, congrats, you’re destroying history all the time that can help you debug things.
Well the alternative is 100s of commits like this:
fix bug
added file
fix typo
fix typo
update test
test
test
test
fix typo
added file
Of course, that assumes a you're already got a workforce that is able to do resolve minor conflicts when something else near the typo got tweaked in a separate commit, so I'll grant that `--amend` is easier when starting out.
My opinion is that a PR should be small enough that it’s desirable to have it squashed into a single commit at the end anyway.
A `git commit --fixup` commit can be made which does that. Then when the review is done `git rebase -i --autosquash`. Like squashing but with fine-grained control.
It's even better if there's some system that ensures authors remember to do the squashing, such as by prohibiting actions that would bring fixup commits into the main development branch.
Personally, I use `--fixup` even before making a PR, particularly if there's some work that I want to split into "refactoring prep" versus "the new feature."
If the change is in response to PR feedback, this is definitely a meaningful concern. The history in the comment I was responding to seemed to imply it was presented for review in the form it was created with lots of little commits along the way; fixing up the history into a small number of meaningful commits before requesting review should be easier on the reviewer, not harder.
Whether to fix up commits before requesting review, during review, and after approval are three separate questions somewhat separate from the question of whether to squash everything at the end.
> My opinion is that a PR should be small enough that it’s desirable to have it squashed into a single commit at the end anyway.
I mostly agree directionally, or for a sufficiently weak "should", but as we get stricter we get into tradeoffs and it gets more subjective and/or context sensitive. If the code base and desired change are in a state such that making the change you need to make is easily split into several conceptual pieces, but they do not make sense on their own, then either you combine them into one commit and wind up with a big PR that's harder to follow, you keep them separate but clean, or you merge them in separate PRs. Some downsides of that last are that it's less clear to the reviewer what motivates the early changes, it may require redundant work to keep everything working (and the code clear) with some of the changes and not others of the changes, and related work moves further apart in the commit history. On the other hand, it should mean smaller merge conflicts as incompatible changes are addressed sooner.
I'd also caveat "one single commit" in that sometimes one commit changing behavior and then a separate commit formatting (or one commit with some preparatory reorganizing and then another changing behavior) can make it clearer what the real changes are, and the intermediate step might not pass linting/format checks if you try to do it in separate PRs.
Now you can make like five PRs for each of those commits. But that seems similar to making five <issue tracker> issues for those commits. You’re already there in the PR. You might not need the overhead of N external items for N commits.
I expect we're agreed that most PRs should be a single commit with a small number of changes in a small number of places, but IME it's not rare to have situations where dividing the changes into groups makes things clearer but where elevating those groups to the level of PR would make things less clear.
The tickets often don’t have meaningful information in them apart from ‚for details see the attachments‘
Attachments are often either not uploaded or nowadays we do not have read access as they were created by a different team working for a different customer but forwarded to the ‚central backend team’ and for know how protection purposes we are not even allowed to see the attachments.
Effectively resulting in the information that is available telling us: ‚we did stuff‘
In my perfect world people would write self-contained commit messages. Links to non-essential elaborations is fine.
But what we have is often (ticket + some bare-bones explanation of what the code change does without explaining why). Okay, so that’s annoying that I have to click through to a slow issue tracker instance for every commit.
But maybe people just want an easily changeable (unlike immutable commits) place to write down what this is about. Is the issue tracker that? Ideally (or second-to-ideally; see first paragraph) the title and description explain what the problem is. If this was a long back and forth issue then hopefully someone has updated the description to point to exactly what the PR/commits are supposed to do. More likely though is that the issue is a stream of consciousness:
- Naive title
- Naive description
- Back and forth troubleshooting in the comments
- The tech lead shoots in with “so, i guess <discard everything> and do X”
And that’s the average good case. I’ve been complaining recently (maybe on two occasions) that I as a secondary (to the tech lead) PR reviewer can’t even easily figure out what the PR is supposed to do based on the issue.
So there is no curation or editing. Even though the issue tracker is elevated to be the source of code change truth by mandating that commits need to have the issue id in the title but almost nothing else is demanded of the commit message.
Now compare all of that to—no matter what is in the issue tracker, no matter if it has good or bad information—taking five minutes in order to write a commit message (or just a PR description which you can use in the merge commit) on a change which took in total three hours to work on with all the back and forth and testing and debugging. Now the snapshot of your understanding of the issue at the time of writing the commit/PR stays there forever, without any need for hyperlinks or external tools.
I find it quite rude to change a codebase and not leave an explanation in the version control metadata. Over the lifetime of the application that's the source of truth. You can type in whatever in Jira or Trello, what's in version control will be built and shipped anyway, and they're unreliable. Sooner or later someone will think it's a good idea to 'clean up' and delete stuff, or someone decides to migrate to another project management supplier and issue-tags in commit messages become dead links.
Using squash when appropriate is good. But then it should be generalized to “rebase” since that doesn’t ever imply a certain strategy like “squash everything”.
> Blindly squashing every branch down into one commit is stupid, though.
Yep, which is what OP is complaining about (mandatory squash).
You can also use it to split and individually pick changes if you want to clean up your commits.
You can automatically fix up commits after review commits using git absorb [1].
There are a few options that help you out with this:
-M Detect moved or copied lines within a file
-C In addition to -M, detect lines moved or copied from other files that were modified in the same commit.
--ignore-rev <rev> Ignore changes made by the revision when assigning blame, as if the change never happened
--ignore-revs-file <file> Ignore revisions listed in file
https://magit.vc/manual/magit/Commands-for-Buffers-Visiting-...
nnoremap <leader>gc :Gshow <C-R><C-W><cr>
command! -nargs=1 Gshow enew | set ft=diff buftype=nofile | 0r!git log -p -n 1 "<args>"
command! -nargs=0 Glogf tabnew | set ft=diff buftype=nofile | 0r!git -C "#:h" log -p --follow "#:t"
command! -nargs=0 -range Glogr tabnew | set ft=diff buftype=nofile | 0r!git -C "#:h" log -L "<line1>,<line2>:#:t"I use short options interactively on the command line, but in scripts and when communicating with other people, I prefer longer options because they are self-documenting and can catch most typos. (For a long option, typos are more likely to result in an invalid option, and thus an error message. For one-letter options, a typo could result in anything..)
Basically git checkout -p until things fail
Other than bisect though, I do think a lot of the practices outlined in the article (checking the blame, logs, search, etc) is way easier to do in a web UI, at least for someone like me who hasn't tailored their workflow for the command line. The tooling is so ubiquitous that it's easily available. I personally think GitHub does okay in those regards.
These features (except blame) are more advanced features, that may be hidden in those interfaces. Instead of remember where they are behind some menus or shortcuts, I prefer to remember their CLI as it is faster.
I've never tried automating it. That'll be fun to try next time I'm in trouble.
- git
- regex
The return on investment is huge.
I wouldn't call myself an expert on neither, but just having a good understanding has often felt like a superpower, and made me the one who "fixed the difficult problem".
To me, Git is like vim: you've to "get it" to love it. I say that as long-time Vimmer and ex-Git hater.
This should read "That command lists all the files in the _working directory_"
https://codeconstruct.com.au/docs/bisect-intractable-rebase-...