5 ms·
I never understood the need to squash commits (or rebase). If you do merge requests and use merge commits (like GitHub or gitlab do). A "nice" history is a smal
by aurelianito 6y ago
I never understood the need to squash commits (or rebase). If you do merge requests and use merge commits (like GitHub or gitlab do). A "nice" history is a small script away. It should even be a part of the GitHub/gitlab gui. Do not loose information about the development history!
- fs111 6y agoMerge commits are noise, a clean history is has no merge commits
- NateEag 6y agogit log --no-merges
- leejo 6y agoSee also git log --no-merges --first-parent I don't get the "no merge commits" argument - git log has dozens of options allowing you to bend it to your use case. To address the grand parent that "a clean history is has no merge commits" I would argue that a clean history is also a lie if you're working in a branching workflow (hint: you should be working in that most of the time). If you want to avoid (note: not eliminate) merge commits then make sure to rebase against master before merging, and then ensure merges are fast-forward merges.
- aurelianito 6y agoIf you squash all the merge requests, you get ONLY merge commits.
- Droobfest 6y agoThey can both be pretty useful. So keep all commits and decide upon viewing the log which ones you really want to see.
- OJFord 6y agoA 'merge commit' is the commit that ties together two strands. * merge commit |\ | * branch work | | | * branch work |/ * If you squash to merge, typically you're also going to rebase it (equivalently, if it's more familiar, cherry-pick the squash onto the branch your 'merging' it into). * squash cherry-picked / rebased | * both branch works squashed | * | branch work | | | | * | branch work |/_/ * (In this case the target branch could have been fast-forwarded, but this also works if there's some other work on the mean time:) * squash cherry-picked / rebased | * something unrelated | * both branch works squashed | * | branch work | | | | * | branch work |/_/ *
- aurelianito 6y agoI know. It means that the only commits left are the ones that originally where merge requests, and you loose the rest of the history.
- l72 6y agoI think this depends on your policy. The policy at my work place is that every commit into master is always a merge commit. When looking at the git logs, we then always do: git log --first-parent This only shows the top level commits (either a direct commit or a merge commit) and doesn't show any of the subcommits in the branches. This gives us a very clean history, something like: commit ce29331f7da82ce528ca6e437b8893248a842169 Merge: a14522cbf 936ef9f90 Author: Joe Sample <joe.sample@example.com Date: Tue Jul 7 14:34:20 2020 -0500 ISS-2047 - Add ids to user invitation or creation commit a14522cbf32487dc590c8b6f3332d3fc9371a640 Merge: d08342170 cb94a86b1 Author: Jane Dow <jane.doe@example.com Date: Tue Jul 7 14:28:28 2020 -0500 ISS-2032 - If an enterprise is disabled, their api keys should be disabled commit d083421702e3ff50bc4c62e85b687e172e4bfe76 Merge: 0d167d25e ba3900a4a Author: Joe Sample <joe.sample@example.com> Date: Tue Jul 7 14:25:41 2020 -0500 ISS-2045 - Return a reason of why the invitation was auto-cancelled Then if I want to see everything that happened in the branch that was merged in, I can just run: git log d083421702e3ff50bc4c62e85b687e172e4bfe76^..d083421702e3ff50bc4c62e85b687e172e4bfe76 and see all the commits that were in that feature branch. No need to squash things or hide them. I really wish git, by default, showed commits under a merge as a tree, rather than as a flat list. This is what bazaar (bzr now breezy) did, and it made a lot more sense when looking at the history.
- cvrajeesh 6y agorebase will give you linear history, merge doesn't provide you that
- Chris2048 6y agoI squash most feature PRs, but this is into a dev/qa branch initially. This is later merged into the actual release branch where we obviously want to maintain each of the individual commits. Reason for the feature squash: most of the context of the original commit(s) are meaningful only to the original dev who is free to keep that history locally (or share with others). There are time's it's convenient to structure the commits in a certain way, but this is often most useful at PR review time, and less so after merge. Granted, you may want to be able to re0review code at a later date, and hence keep that structure, but hopefully this is a rare case, and PRs and not often so huge.
- dnsmichi 6y agoHi, Developer Evangelist at GitLab here. I would say, it depends on the workflow, unfortunately there is not right or wrong here. I'll try to share some situations of my development experience in the past years, also as Git/GitLab trainer: ## Squash I often start in a feature branch with a new proof of concept, or other code which is persisted in several commits. Sometimes I'll iterate on a few things, like testing a change in a GitLab CI yaml, and checking whether it works. Or a different compiler flag to enable faster package builds. Or a refactored function which needs to run all the e2e tests to prove the performance gain. These changes may, or may not work. When they do not work, I'll reset the commits - either soft to keep the changes, or hard to throw away the attempt. This follows a changed history and force push into the remote branch. In case of a shared branch, message colleagues with "git fetch && git reset --hard origin/branchname". Within pair programming sessions, we often left with commits like "Add REST API HTTP server, WIP 2" in branches and depending on the availability, either one of us continued. At a certain point in development time, we decided to squash and amend the commits. Sometimes not all of them, as rebase/squash also allows you to do the following: c1 s \ c2 s / c3 p c4 s \ c5 s / Which squashes c1+c2, leaves c3, and squashes c4+c5 again. You can navigate into this on the CLI with "git rebase -i HEAD ~5". ## Rebase/Merge Short-lived branches which are quickly merged back to the main branch shouldn't cause problems with a broken deployment. In case you get a task assigned where the main branch is far beyond (say, 100 commits or more), it may be the case that - Branch and merge request works fine, CI/CD pipelines are green - Changes in the main branch which affect your feature. These changes can be - Function interfaces renamed, or not existing. Easy to fix upon rebase, build/run does not work anymore. - Runtime changes, for example, queries take longer roundtrip due to a refactor. Your feature only takes the old behaviour into account, and increases the runtime complexity. Or it consumes 10x memory resulting in OOM crashes later. The last change may not be immediately visible, as it involves staging environments and application performance monitoring results. ### Merge without Rebase If said changes occur, and the rebase did not happen, the green CI/CD MR is merged back to the main branch. Depending on the releases, you either roll into production, or after days/weeks/months, a new release is cut. At that point, the regression may be seen in the main branch, and cause delayed analysis and debugging. Often times on-call alerts and all the debug fun which may lead to burnout (been there myself). ### Merge Request with Rebase During the final review, and prior the merge, the changes are rebased against the latest base in the main branch, to see if they compile or any other influences. A rebase puts the existing commits onto a new commit base, which influences the calculated checksums. Therefore all commits are newly generated, the author date is preserved with changing the commit date. ### Merge Commits There are different opinions on them. One of them is to always rebase the MR and then do a merge with a commit. Rationale: Even without GitLab/GitHub/etc. you can reliably see the git graph on the CLI or with other visualization tools. https://gitlab.com/dnsmichi/dotfiles/-/blob/main/.gitconfig#L6 https://gitlab.com/dnsmichi/dotfiles/-/blob/main/.gitconfig#... I've recently seen the possibility to reference a PR/MR to a commit as the merge-from-branch reference, without the dedicated merge commit. This can be handy to avoid it, with using GitLab/GitHub/etc. to store this detail in their database. It also is a vendor lock-in in a way, that the native "git clone" does not provide this information for you in Git's database. That being said, I used to dislike merge commits. With enriched details, and CLI work, I now prefer them again. Git commits as datasource are valuable, and they can be shown/parsed in any environment. ### Rebase, Merge, ... large environments? This can of course get more complex, with fast moving main branches and lots of merges which depend on each other, and should not reach the main branch. Instead, you'd want them to be queued and tested. We experience that at GitLab quite often, and have created so-called "Merge Trains" which ensure that all MRs in such a queue/train are taken into account: https://docs.gitlab.com/ee/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/ https://docs.gitlab.com/ee/ci/merge_request_pipelines/pipeli... ## A personal note: The best merge/rebase strategy is nothing without tests I've been working on a monitoring tool in the past which includes distributed environments, and often needed to fix bugs with memory leaks or other performance issues in multi-threaded scenarios. Things you do not see immediately when the MR/PR is green. There was one commit which caused a OOM crash after 3 days of runtime, but only in cloud environments with >100 satellite nodes. The turnaround was to bisect all the commits, and run each of them in production for 3 days until the crash occurred. IIRC we had 1,200 of them to do in a binary search. Now the question is: - Fewer squashed commits - More development history In this case, fewer commits would have unveiled the error sooner. The resulting commit would be larger and harder to debug & fix though. In the end, it did not really matter. The thing which would have helped: There was no reliable test environment coupled to CI, CD which ensured to run specific commits & MR/PR in dedicated scenarios and alert of breaking changes soon enough - before the release happens. ## Conclusion One thing which greatly helped: Looking how others do it, Open Source projects and customer success stories and webinars, online training sessions. Even though you may not adopt the workflows, trying them out is a good way to learn. For instance, "trunk based development with feature flags" is something different to well-known branching models for me, I needed to try them out first to change my opinion. They are indeed useful for certain scenarios. While committing changes, and keeping them throughout un-squashed MRs, I always remember that I will be highly likely debugging the changes later on. Or someone who finds the MR reviewed by myself, documenting every thought or idea in a commit or MR comment can help. Some more tips and exercises are discussed in an OSS training I created in the past: https://github.com/NETWAYS/gitlab-training/releases/tag/v2.5.2 https://github.com/NETWAYS/gitlab-training/releases/tag/v2.5...