5 ms·
One of the best things I ever did for my git usage was installing this ridiculous thing in my .gitconfig aliases: [alias] l = log --date-order --da
by yebyen 8y ago
One of the best things I ever did for my git usage was installing this ridiculous thing in my .gitconfig aliases:
[alias]
l = log --date-order --date=iso --graph --full-history --all --pretty=format:'%x08%x09%C(red)%h %C(cyan)%ad%x08%x08%x08%x08%x08%x08%x08%x08%x08%x08%x08%x08%x08%x08%x08 %C(bold blue)%aN%C(reset)%C(bold yellow)%d %C(reset)%s'
It lets me type 'git l' and get this kind of commit graph:
* 8264cf2a 2018-06-28 yebyen (origin/dev, dev) ...
|\
| * df6e4c49 blabla commit messages
| * 195d8924 commit messages
|/
| * 96e74a5c (branch-label) commit message
| |\
| | * b2786c07 blabla
| | * 85721288 blabla
This is semi-related but not nearly as interesting from a technical perspective. But it's one of the missing features in Git, to visually help people understand why it's helpful to rebase occasionally, and keep your commit history clean.
I think I found it here[1]
[1]: https://stackoverflow.com/a/16735971/661659 https://stackoverflow.com/a/16735971/661659
- WorldMaker 8y agoI had a similar alias for a while at a past job, but realized I was just using `gitk` anyway, and `gitk` is installed by default everywhere and doesn't need an alias setup, so it's also especially easier to teach to junior developers. Also, I don't encourage rebasing, especially to junior developers. I realize everyone has different preferences, but a messy graph is useful and there are other tools like `git log --first-parent` for getting "clean" baselines from the graph. The great thing about using a graph in the first place is there are a lot of traversal options and you don't have to micromanage where the trees are to still see the forest.
- yebyen 8y agoYes! I agree with you mostly, except that we try to keep from having junior developers for too long. Nobody is really a junior developer, and everyone should get a turn as release manager. The main benefit of this is that people can see directly how their work style impacts the release engineering process, if they do know exactly what that process involves and actually get a turn at it. (You have to stub your own toe in order to know how bad it hurts.) Our team is actually really small, and we like to make sure everyone knows about the hassles involved in putting together a release and doing a complete code review when it's needed. The main reason I encourage rebasing is because it helps avoid a messy graph, and a messy graph makes it immediately much harder to do a rebase across any number of merges, or any non-trivial span of time. So in other words, I like to selfishly expect the other developers on my team to do rebases at the appropriate times, in order to preserve my own capability to easily do rebases when needed. (We also learned last week that git rebase has a --preserve-merges option that I feel foolish to not have known about sooner. We've wiped out so many merge commits unnecessarily.) We treat the master branch as carved in stone like anyone should, but other branches should clearly flow their merges only one way (features into releases, or features into environments), and if a branch hasn't actually been included in a release tag, it's considered fair game for rebasing. It helps us to prevent our three developers' sometimes too many concurrent trains of thought from resulting in equally too many confusing merges, or an intractable number of HEADs to manage and organize into releases. One of the places we struggle is that we're not all-the-way onboard with CI/CD processes, but we do the best we can so that whenever support for that kind of thing materializes, we will mostly not need to change our processes at all and can obtain the benefits of that kind of tooling as quickly as possible.
- WorldMaker 8y ago> other branches should clearly flow their merges only one way I tend to disagree on this as well. The best person to merge a conflict is the developer creating the conflict in the first place, as soon or nearly as soon as they create the conflict, because they are most likely to know why the conflict exists in the first place. "Merge early, merge often." Delaying "reverse" merges until the last possible second means you often don't have the integration expertise needed without research involved, even if it was "you" that introduced the conflict you may have moved on to other problems since and not recall why you did something one way or another, or which bits are important to integrate. Delaying those merges as rebases I feel is even worse, because not only do you not have the resources to know why an integration needs to be made, you also aren't recording a history of the merge conflicts you saw in the rebase such that you can easily revisit the integration if you made an integration mistake (which does happen, because we are, after all, only human). My advice tends to be to use a good PR system of some sort that makes your proper, code reviewed "forward" merges clear and obvious, and then don't worry about a mess of other merges "underneath" that top-level of strong PR merges. (Hence the key suggestion is that `git log --first-parent` is your best friend if you want a "clean" view of the DAG. It gives you a linear list of just your PR merges in master, or branch work and PR merges to that branch in any other branch.) Also, yes, CI/CD are really good ideas.
- yebyen 8y ago> you also aren't recording a history of the merge conflicts you saw in the rebase This is a good point. Mistakes are made during merge conflict resolution. But if you are tracking your upstream when you develop a long-lived feature branch, and rebasing when there are changes to the base, and actually comparing your rebased feature branches to the version that you had before you force push over the old remote version, then the only thing you really need to track is "does my diff still look like the change I intended to make." The most valuable skill we are learning from Git is how to avoid merge conflicts altogether, and it tends to be more a human problem than a technological issue. (You don't avoid merge conflicts with some special commit strategy, you do it by ensuring that two people are not actively changing the same part of the codebase unless it's absolutely necessary.)
- linkmotif 8y agoRebasing is fundamental to a proficient local workflow. Interactive rebasing with git rebase -p lets you craft and recraft your commits easily until they are readable and tell a story. The sooner a person can rebase, the sooner they can use Git. It’s not really possibly to proficiently or pleasantly use Git without rebasing.
- WorldMaker 8y agoI very strongly disagree with that. I'd rather someone be proficient with the staging index, and maybe even git stash, than rebasing. Maybe, if they are feeling fancy, `git add --interactive`, `git add --patch`, and/or `git commit --amend`. Rebasing is a fascinating footgun. I'd rather a messy story that includes details of how someone screwed up, then fixed their mistakes, than an entire branch I need to cherry pick in a hazmat suit because a developer rebased the wrong thing.
- yebyen 8y ago> I'd rather a messy story that includes details of how someone screwed up Strongly disagree. I am mostly interested in reviewing your best work, and ensuring that it is correct, as much as I enjoy hearing the story about how you got there. When we spend a lot of time on specs and ensuring they are correct, it's mostly important that I can review your change and compare it to the spec to ensure correctness. A commit that was wrong, but was corrected before it ever went to prod, doesn't really help me at all during code reviews. I agree that 'git stash' and 'git commit --amend' are also important skills to have, but I prefer to make small, incremental commits that are obviously correct changes in isolation, even if they are not very interesting, so long as they are moving something toward the goal. Then I'll condense them into commits that look something like "the whole change I intended to make" – but that's maybe once it's fully formed and the tests are actually passing. I don't like to keep a lot of small commits around, again selfishly and simply because they can make rebasing harder. It is telling how many things I do in service of keeping it easy to rebase a changeset. It's not an unobtrusive feature and there's definitely merit to the argument that it's a nice gun to shoot yourself in the foot with. There is a happy medium between squashing all commits within a feature branch, and keeping every "boring, but obviously correct" incremental change intact forever. A change is only interesting in isolation if it might be reverted, or if I read it in isolation and for whatever reason strongly believe that I might ever want to read it in isolation again.