[HN Gopher] Ask HN: What is your Git commit/push flow?
___________________________________________________________________
Ask HN: What is your Git commit/push flow?
I've long been in the practice of "commit early, commit often". If
one use case works I commit, if the unit tests pass I commit. The
code may be a mess, the variables may have names like 'foo' and
'bar' but I commit to have a last known good state. If I start mass
refactoring and break the unit tests, I can revert everything and
start over. I also push often because I'm forever aware disks can
fail. I'm not leaving a day's worth of work on my local drive and
hoping it's there the next morning. I've become increasingly aware
that my coworkers have nice clean commit histories. When I look at
their PRs, there are 2-4 commits and each is a clean, completely
functioning feature. No "fix misspellings and whitespace" comments.
What flow do you follow?
Author : nineplay
Score : 156 points
Date : 2022-03-17 15:27 UTC (7 hours ago)
| phkahler wrote:
| You need to include a step where you squash commits. For me that
| was the point where I had to learn vi, since "git rebase HEAD~4"
| will throw you into vi. So then I ran "vim tutor" daily for a
| week and learned enough to continue using git.
| spookyuser wrote:
| git commit -m "Initial commit"
|
| git commit -m "Add some stuff"
|
| git commit -m "progress"
|
| git commit -m "Add library"
|
| git commit -m "Drop library"
|
| git commit -m "Let's try this library"
|
| git commit -m "Slider is working"
|
| git commit -m "Fixing transparency issue"
|
| git commit -m "Fixed"
|
| git commit -m "I hate you"
| moonchrome wrote:
| I commit when I hut logical milestones. I ammend typos and stuff
| like that if I catch it early.
|
| The commit all the time is a waste of time for me - my IDE
| (intellij) has excellent local history.
| jawns wrote:
| Here's how I address this problem.
|
| When I'm developing, but before I create a PR, I'll create a
| bunch of stream-of-consciousness commits. This is stuff like "Fix
| typo" or "Minor formatting changes" mixed in with actual
| functional changes.
|
| Right before I create the PR, or push up a shared branch, I do an
| interactive rebase (git rebase -i).
|
| This allows me to organize my commits. I can squash commits,
| amend commits, move commits around, rewrite the commit messages,
| etc.
|
| Eventually I end up with the 2-4 clean commits that your
| coworkers have. Often I design my commits around "cherry-pick"
| suitability. The commit might not be able to stand on its own in
| a PR, but does it represent some reasonably contained portion of
| the work that could be cherry-picked onto another branch if
| needed?
|
| Granted, all of the advice above requires you to adhere to a
| "prefer rebase over merge" workflow, and that has some potential
| pitfalls, e.g. you need to be aware of the Golden Rule of
| Rebasing:
|
| https://www.atlassian.com/git/tutorials/merging-vs-rebasing#...
|
| But I vastly prefer this workflow to both "merge only," where you
| can never get rid of those stream-of-consciousness commits, and
| "squash everything," where every PR ends up with a single commit,
| even if it would be more useful to have multiple commits that
| could be potentially cherry-picked.
| aerovistae wrote:
| ...what is the golden rule of rebasing
|
| edit: googled, "Never rebase while on a public branch" i.e. a
| shared branch
| notapenny wrote:
| It usually works out fine when you do a `git pull --rebase`,
| but not everyone does this or has it setup so pulling might
| have some nasty effects. Generally helps to consider a
| feature branch as a private branch. Don't push to other
| people's features without asking, don't fuck up other
| people's work.
| OJFord wrote:
| Everyone absolutely should configure that. (Git config
| pull.rebase true.)
|
| Such an annoying mess it leaves otherwise. And CI is
| building 'merge branch master', on the master branch,
| great.
| nyanpasu64 wrote:
| FWIW I set pull.ff to only, since I don't want merge
| commits _or_ rebases happening without explicitly calling
| pull --rebase or --merge.
| lambic wrote:
| Are there any downsides to doing this? Why isn't it on by
| default?
| formerly_proven wrote:
| > Why isn't it on by default?
|
| Because git was written primarily for the Linux kernel
| and the defaults reflect that. The workflow of the Linux
| kernel is completely different from what most people
| outside of it do with git. "git pull" is used for
| opposite purposes in both worlds.
| OJFord wrote:
| I suppose just the usual 'rebase vs. merge' - i.e. if
| there are conflicts to resolve they will be dealt with
| commit-by-commit in the usual way when rebasing, whereas
| without the option set they will be dealt with all at
| once 'merge-style'. I happen to think that's a feature,
| but I know some don't like it.
|
| I think there's less argument in favour of merge than
| usual with pulls though - since it's much less like a
| semantic merge to begin with for git-merging to preserve
| a history of.
|
| I'm certainly not aware of any _objective_ downside
| /gotcha/'oh but it doesn't work when...', no.
|
| The docs only add that you might further want to set it
| to `interactive` or `merges` rather than `true`, for the
| effect of rebasing with those options: https://git-
| scm.com/docs/git-config#Documentation/git-config...
| heurisko wrote:
| I think it's the usually public vs private branch issue.
|
| If you're merging a public branch with another public
| branch, then if you a rebase, rather than a merge commit,
| then you mess up the history for anyone has pulled that
| branch.
|
| For private branches that isn't an issue.
| mkesper wrote:
| Combine with git config --global rebase.autostash for
| your own protection.
| cpcallen wrote:
| > And CI is building 'merge branch master', on the master
| branch, great.
|
| How does one set this up in GitHub actions?
| SnowingXIV wrote:
| Yes, if you're going to rebase, rebase your feature branch.
| Do not do it on the shared staging/dev etc.
| matticusrex wrote:
| The only problem I have with this workflow in the command line
| is that I would like to be able to split changes to the same
| file across multiple commits. I think some GUI tools enable
| this, anyone know about it?
| kjeetgill wrote:
| If you're a vim guy, I use `git difftool` setup with
| `vimdiff` for this. Let's say you have your changes in a
| branch CHANGES on top of public branch PUBLIC.
|
| 1. I `git checkout PUBLIC -b CLEANUP` to a new branch.
|
| 2. Do a `git difftool CHANGES`, which opens each changed file
| in vimdiff one at a time.
|
| 3. For each file, I use :diffput/:diffget or just edit in
| changes I want.
|
| 4. Commit these changes on the CLEANUP branch.
|
| 5. Use `git difftool CHANGES` again to see the remaining
| diff.
|
| 6. Repeat until the diff comes back empty!
|
| My unstructured changes tend to contain a handful of small
| typo fixes, white spacing, localized refactors, and 1 or 2
| larger refactors and a behavioral change. Once they're all
| broken out, It's usually easy enough to use `git rebase -i`
| and reorder the smaller changes first, put out PRs for just
| those first, etc.
| newaccount74 wrote:
| If you have a Mac, check out GitUp. It's a simple but
| fantastic tool for cleaning up git histories: merging
| commits, splitting commits, reordering...
| matijsvzuijlen wrote:
| Git has a built-in GUI for that. Just run 'git gui'. It's not
| pretty but it works.
| simlevesque wrote:
| > git gui git: 'gui' is not a git command. See 'git
| --help'. The most similar commands are gc
| grep init pull push
| formerly_proven wrote:
| It's a separate package in some distros since it's
| written in Perl and uses Tk. gitk is often in the same
| package.
| arilotter wrote:
| When you're doing your interactive rebase, find the commit
| you'd like to split - choose "edit" for that one. Then when
| you reach that point, you can do `git reset HEAD^1` to bring
| those changes back onto your staging stack, and make as many
| commits as you need.
| erdo wrote:
| Gitx is great for that on a mac, but every time I set up a
| new MacBook I have to hunt down the latest repo / build. It
| keeps getting abandoned and then forked and continued, and
| then abandoned again...
|
| Edit: looks like it's back from the dead again :)
| https://github.com/gitx/gitx
| tuckerpo wrote:
| I do this via git add -p which breaks your changeset down
| into atomic patches that you can either add, skip or delete
| before making a commit. You can turn one file change into
| many commits this way, if need be.
| atq2119 wrote:
| I can second the recommendation of tig in the sibling
| comment.
|
| Additionally, git itself comes with a simple `git gui`
| command that allows you to do partial commits on a line by
| line basis. It also has a nice "amend last commit" mode.
| yodsanklai wrote:
| The way I deal with this is 1. try to make commits small
| enough so you are less likely to split them after the fact.
| 2. when I need to split a commit, I use VSCode UI and apply
| patch by patch. This is one of the rare case were I use a GUI
| for git. For most other things the command line is fine.
| bentcorner wrote:
| sublime merge handles this really nicely. You can do this in
| VS code too but the UI is a little more fiddly (right-
| click->"Stage Selected Range").
| btschaegg wrote:
| Have a look at `tig`. It's even included in Git for Windows
| now and does this reasonably well.
|
| Only the keybindings are a bit weird if you're not accustomed
| to Vim bindings:
|
| - Open tig
|
| - Change into the staging view with `s`
|
| - Select your file using the arrow or `j` and `k` keys
|
| - Press Return to show the diff
|
| - Navigate to the line(s) in question with `j` and `k` (arrow
| keys will switch files)
|
| - Stage parts with `1` (single line), `2` (chunk parts), `u`
| (chunks) or split chunks with `\\`
|
| - "Leave" the diff with `q`
|
| - You can find the keybindings with `h` in the help screen,
| which also uses Vim keys -- like manpages usually do
| mikewhy wrote:
| I used tig for a bit because it was the nicest way I could
| find to do line-level staging in a terminal. But was really
| impressed with gitui https://github.com/extrawurst/gitui so
| I've switched to that
| mariusor wrote:
| "s" is status view, which you can also get at by running
| "tig status" directly.
|
| "c" is staging view.
|
| > - Stage parts with `1` (single line), `2` (chunk parts),
| `u` (chunks) or split chunks with `\\`
|
| You can also revert a chunk or file by using "!". Sometimes
| this is very useful.
| btschaegg wrote:
| Ah, thanks for the correction :)
| distortedsignal wrote:
| I use the interactive flag on git add for this. It lets you
| add parts of a file, commit, and then do it all again. I want
| to say it's git add -i, but I'm not 100% on that. My fingers
| just do the right thing when I want it to happen.
| Izkata wrote:
| It's "p" for "partial"
| fatnoah wrote:
| This is very close to my approach. I work in a private branch
| and make many commits along the way, but then organize it to
| tell a coherent story for the actual PR.
| spacechild1 wrote:
| I do the same. A clean and logical history helps other people
| understand your code and might consequently increase the
| chances of getting it merged.
| andrewzah wrote:
| This is the ideal workflow for me since I think merge commits
| clutter up the log, but it falls apart if people aren't
| consistent in following it.
|
| *glances and $corp git repo and sees 'updates' 'fix' 'updates'.
| Sigh.
| Consultant32452 wrote:
| I've always been fond of the "WIP" commits.
| elpakal wrote:
| I do this (kind of too), but instead of an interactive rebase I
| just do a `git reset --soft <target_branch>`, where
| target_branch is the local (and up-to-date) copy of my target
| branch. That gets me one clean commit that I can force push up
| to replace my branch @ remote.
|
| (This works for me because auditing commit history is not
| important where I work, if it were I would organize commits
| better.)
| dopidopHN wrote:
| I first did rebase, and after a while I realized I was not
| getting much of it since I mostly wanted to merge everything
| down to a single commit.
| nyanpasu64 wrote:
| I do the same thing generally. In fact I generally find
| multiple mistakes or changes to be made, reading over my _own_
| code before merging, requiring figuring out which commit to
| merge my changes into (git absorb helps in the easy cases) and
| even more rebasing, or giving up and adding an extra commit at
| the end.
|
| I see some people whose projects (Furnace Tracker, PipeWire,
| previously Famitudio) seem to make progress very quickly
| without getting noticeably slowed down by technical debt,
| despite sloppy programming and unorganized commit logs (push-
| to-head). Meanwhile I move slowly, dread reviewing hundreds of
| lines of my own code, and produce technical debt (regrets)
| anyway, not as many surface-level lintable errors but plenty of
| entrenched mistakes. I wish I could move faster, but instead
| struggle to make progress.
| adrianmsmith wrote:
| > I also push often because I'm forever aware disks can fail.
|
| You could consider using a tool other than git push for
| protecting your work against disk failures. I rely on Apple Time
| Machine for that for example.
| nineplay wrote:
| My dev box is deep inside a corporate lab. I'd be much happier
| if I could manage my own backups.
| bern4444 wrote:
| I do the same as you - commit early and often, push nearly on
| every or every few commits, but I try and write my commit
| messages nicely even (and especially) if the code behind them is
| not so clean.
|
| I care less about the code quality during development, so long as
| the commits make sense and the end PR is clean. Commits that may
| have placeholder names, disorganized code could include:
|
| "fix: failing test case" "feat: support new user flow" "cleanup:
| variable names and helper functions" "cleanup: organize files"
| etc
|
| If the commit messages are clear as to why the change was
| committed, reviewing is a lot easier even with less than ideal
| code along the way. So long as the end state is cleaned up.
| kblev wrote:
| We just squash the commits in Gitlab at a Merge, so the
| sequential commits won't matter.
| shoo wrote:
| always use `git add -p`. review each individual hunk before
| staging it into commit. dont blindly add everything.
|
| once you've got it working, do a second pass on the commit
| history and compress it into one or more coherent logical
| commits, reordering or squashing changes as necessary. learn the
| interactive rebase interface. lots of operations of the form `git
| rebase -i HEAD^^^^^^`
|
| where necessary, if you need to erase your old messy history from
| a feature branch and overwrite it with your tidied up commits,
| `git push --force-with-lease some-remote some-feature-branch`. in
| general, avoid using `--force`, and if you ever believe you need
| `--force`, prefer `--force-with-lease` . the latter avoids some
| failure modes related to race conditions where a coworker pushes
| some commits and your concurrent `--force` push that lands a few
| seconds later blows them all away.
| [deleted]
| WorldMaker wrote:
| My opinion is that the time for clean commits is the merge
| commits created by PRs. Git uses a two dimensional commit data
| structure and most git commands today take a --first-parent
| argument that gives you a smart, clean view of just the merge
| commits. It's only a bit of config work to make those your
| default aliases, and I just wish more UI tools defaulted to
| something more like it.
|
| I don't necessarily care how "messy" the commits inside a PR are
| at that point if my default view is at the merge commit/PR level.
|
| Teaching your coworkers how to use --first-parent may be
| beneficial to everyone and less stress than worrying about the
| peer pressure to conform to smaller "cleaner" commits.
|
| That said, making cleaner commits is sometimes a useful skillset
| to learn for _yourself_. Sure, it can make code reviews easier,
| but it 's advanced skills that take practice and most PR tools
| aren't particularly good at reviewing a commit at a time anyway
| so most PR reviews are entire PR at a time. I use tools like git
| add -p and git rebase --interactive as I feel necessary to clean
| up a commit narrative, but I also have a strong understanding of
| when not to force push and have years of "training" in these
| commands. I don't expect and don't want to expect junior devs to
| use them. I'm happy with the --first-parent approach to the DAG.
| I'm also always happy to teach junior devs how to use git add -p
| and git rebase --interactive, but when it is for _them_ , when it
| is they who want to improve their skills.
|
| A semi-related thing here is that the other way to remove a lot
| of "fix misspellings and whitespace" commits is to automate them
| away. Standardized formatters like prettier remove most of the
| manual effort of whitespace management. They can be setup to
| format on save in editors like VS Code. They can be added to pre-
| commit hooks. Similarly, many misspelling problems (certainly not
| all) get automated away with type systems and linters.
| francisofascii wrote:
| Create a branch. feature_todo
|
| Do a bunch of commits.
|
| Push branch to remote as needed.
|
| Refactor.
|
| Create a new branch. feature_1
|
| Reset soft back where I started.
|
| Commit a nice, clean change and good message.
|
| Rebase main.
|
| Push.
|
| PR.
| MPSimmons wrote:
| rebase -i <branch-to-merge-to> then squash the changes you want
| to hide
| keehun wrote:
| I do exactly as you say: commit early and commit often. However,
| something I find quite successful when publishing a Pull Request
| (aka CR/MR), especially large ones, is that I'll use git rebase
| to group chunk diffs together in a logical flow to create an
| easy-to-review set of commits.
|
| If I have 5 commits that are all whitespace changes, I'll use git
| rebase to group them into one commit before I push.
|
| If it's a large, complex PR, then I'll reorder my commits and
| pick-and-choose chunks from the many commits so that they make
| sense in a progression. For example, I might just add one new
| component in the first commit. Add a second component in the
| second commit. Third commit might be integrating those two
| components into the system.
|
| If my PR consists of both "cleanup" like running black on python,
| then I'll make that its own commit instead of littering actual
| functional changes within cosmetic ones.
|
| I try to make it as easy as possible for my reviewers to review
| my code and actually catch mistakes. I also tell the reviewers to
| look at the commits separately and not to look at the entire diff
| which can sometimes be hundreds of thousands of lines of code.
| Even a large PR with 500+ lines of changes can be easy to review
| if you structure the commits right. (It's really like many PRs
| within one PR.)
|
| You may ask, why not have separate PRs then for each commit?
| Sometimes, that makes sense when it's so large that it's worth
| having an integration branch that lasts weeks or months.
| Sometimes, it's not possible to just merge that one commit due to
| problems it'll cause with compilation or linting or other issues.
| Also, with separate PRs, it can be more costly (in both CICD
| resources and the dev's time) to do automated testing on each
| commit separately.
|
| With some practice, the git rebasing and reordering or
| restructuring commits is not as difficult as it sounds,
| especially with the aid of a good git GUI (I like Fork.app) that
| lets me choose exactly the chunk to commit from a particular
| diff.
|
| Once I got really comfortable with this workflow, what I'll
| actually starting doing is... when I'm done with something and
| ready to put up a PR, I'll flatten (fixup) all my commits into
| one, and then I'll revert it and commit that. Then I revert the
| revert but instead of committing that revert-the-revert, I'll
| stage it. This gives me all of my changes in a staged state. Then
| I'll pick-and-choose chunks from that entire diff to craft a
| "narrative" like I was describing before. Once I have everything
| in the right order, I'll drop the first two commits to get of the
| initial and revert commits.
| yodsanklai wrote:
| I commit often (as long as it compiles, pass the linter, and fast
| unit tests if there exist), then I rewrite the history. If I work
| alone on the feature (which is most case) I also push quite often
| on a private branch (mostly for backup, and for running the CI).
| If needed, I also rewrite the history of my private branch and
| `push -f` (even though this isn't ideal...).
|
| My PRs are clean, each commit pass the CI and is its own thing.
| ragebol wrote:
| As long as I'm working on my branch, that I work on alone, I tend
| to rebase and interactively rebase those relatively often. The
| mantra is you shouldn't rebase public history, but since it's my
| working branch, I feel I can do whatever I want with it.
|
| Nice thing about small, atomic commits that still pass tests, is
| it works well with `git bisect` to find issues.
|
| I also split commits defining a function etc from using it in
| other code. So if I `git reset --hard` because I screwed up some
| caller, I still have the function.
| tuckerman wrote:
| I commit/push to a remote branch often mostly as a backup/easy
| undo. My commits are squashed for each PR; if I have two commits
| that I want to stay separate, I send them as separate/chained PRs
| (I like the idea that each commit in master represents a reviewed
| point in history).
| bo1024 wrote:
| It sounds like a main problem is that you don't have your local
| drive backed up. Can you address that first?
| mattwad wrote:
| I squash all commits in a PR as a clean commit. I don't see any
| benefit to knowing when or what someone did other the past few
| weeks to get to the point we're updating the main branch, and i
| don't want them to waste time either. If your PR is so large you
| need to review it as individual commits, maybe your PRs are too
| big.
| jedimastert wrote:
| The git history on my personal/dev-machine are an absolute mess
| that I try to optimize for `git bisect`, so preferably each
| commit should compile (and I usually commit whenever a new part
| of the requirements is introduced/a new test passes)
|
| The way our code review system works is essentially each upload
| is a commit, so the review's history is like a compressed version
| of the local git history. I usually upload when I think the
| branch is "complete"/will pass all of the CI, and ~once per round
| of comments.
|
| The main git history is squash-and-rebase, so one commit per
| code-review, with the CR description serving as the commit
| message (with automatic links to bugs and code reviews and the
| like).
|
| I personally like the squash-and-merge strategy for the main
| branch, it makes the most sense (especially when the code
| review's history is still around after)
| notapenny wrote:
| I commit as clean as possible, each one should be a functioning
| feature or a part of it. I try to do small ones, so generally
| they'll just be part of a feature I have on my todo list for the
| entire feature. That actually helps me to mentally move on as
| well. If I need to rename some stuff I might squash commits, but
| no wip commits in the actual history.
|
| End of day I usually commit a "temp" commit with a few comments
| to myself and push that to the remote branch, revert that the
| next day and force push over it for the next commit.
| tobyhinloopen wrote:
| I commit and push often, with no sensible commit messages. The
| git messages aren't used, except for issue ids and random
| garbage.
|
| All details regarding code and reasoning is on the issues and
| pull requests.
| smashah wrote:
| I commit anytime the staged code can have a logical commit
| message. So I go for the smallest possible change per commit.
| Push when an issue can be closed/new release can be built or I
| leave my computer for any reason.
| lmarcos wrote:
| I used to do exactly what you described a few years ago (when I
| was learning git for the first time). Not anymore. A few reasons:
|
| - commit early/commit often. I usually push one commit when I
| think the feature is done. While others do a review of my code, I
| commit to improve the code/fix the issues found by others. The
| advantage here is that future readers looking at the history of
| file X line N can know what other files were introduced alongside
| file X (as a reader of big codebases, this is a nice side
| effect). I don't like hiding defects either from the git history
| (one could in theory squash all the commits of a given PR in
| order to keep the "history clean"... In my experience having a
| trace of bugs fixed at PR time, or other subtle details is also
| worth it and serves as documentation of what not to do).
|
| In the cases I need to work through many days in a single
| feature, and only if the feature is so complicated/critical than
| I cannot reproduce it from scratch by myself again, then yes I
| push the progress upstream. This is usually not the case though:
| I stash progress. I tend to open small PR and usually I remember
| what I've done (so I could write the entire code again easily).
| Plus, hard drives fail, sure but they are also quite reliable. In
| 20 years of work I never experienced losing "non critical" work
| because of disk failure (for critical work, I for sure have a
| different workflow).
| InvOfSmallC wrote:
| Master only.
| setgree wrote:
| My main git case is idiosyncratic -- I use blogdown [0] to host
| my personal blog, which means I am first pushing the content to
| GitHub and then it gets built/deployed on Netlify.
|
| I typically commit once at first as a pretty complete draft, and
| then every subsequent edit/revision is a commit and rebuild. This
| comes to 20-30 commits per post, and some are indeed like 'fixed
| a spelling error'.
|
| For this case, the benefits of being a frequent commiter clearly
| outweigh the costs.
|
| [0] https://bookdown.org/yihui/blogdown/
| smcameron wrote:
| I use stgit[1] which makes it easy to polish patches (commits),
| re-order patches, format and email patches, etc. It also makes it
| very easy to keep a lot of balls in the air at once, working on
| lots of commits all at the same time while keeping them
| reasonably separated from one another. I've had maybe 50 to 100
| patches going at once from time to time (but usually more like 5
| to 10). Then there are guys like Andrew Morton who's known to
| juggle 1000s of patches at a time using ancient home grown
| scripts that are the primordial ancestor of quilt[2] and stgit.
|
| [1] https://stacked-git.github.io/ [2]
| https://en.wikipedia.org/wiki/Quilt_(software)
|
| Edit: forgot to mention, once I'm happy with a given
| patch/commit, or series of patches/commits, I then cherry-pick or
| merge them from my patches branch over to the "real" branch, and
| then push them.
| SAI_Peregrinus wrote:
| Commit often, then interactive rebase, then push to GitHub. Then
| code review happens, and any comments get addressed with some
| extra commits.
|
| The annoying thing is that often someone will change CI for some
| unrelated subsystem (we're in a monorepo) and the way to fix that
| is "merge master into your branch". Of course I could rebase on
| top of master before pushing, and I do, but that doesn't work
| well if the CI change happens while my PR is in review. Then I
| have to merge master into the PR branch, since people do check
| branches out to review them sometimes.
|
| Thankfully we squash PRs before merge, so it only ends up with a
| single commit in Master, but it does mean there's sometimes an
| intermediate mess.
| gabereiser wrote:
| I got conditioned to commit early and commit often for much of
| the same reasons, hardware failures while dealing with code that
| touched hardware. GPU's mainly. So I would commit and push to
| have CI do checks while I pushed more code changes so that I
| could reduce the cycle.
|
| A few years ago, Acme Security Corp decided to use my commit
| frequency as an excuse to say "I didn't know how to code..." and
| let me go. So really it's all over the spectrum and the correct
| answer is, whatever your team is doing.
|
| If they are holding back commits for uber PR's, well, so should
| you. Are they in a commit frenzy and everyone PR's all day long?
| So should you.
| jmchuster wrote:
| Create a feature branch for everything i work on. Then squash all
| commits on that branch for merge. If that doesn't look clean
| because there are too many features munged together, then split
| that feature branch into multiple ones (ideally would have
| already realized this ahead of time), then squash and merge each
| of those. So, then the main branch commit history is only "clean,
| completely functioning features" and then a link back to the PR
| that then has the full history of commits that got squashed, if
| you wanted more insight into the development process. The github
| UI simplifies a lot of this process and makes it a lot nicer to
| view.
| contingencies wrote:
| No branching + messy commits. Exceptions would be forking public
| projects to contribute, and public project issue resolutions
| ("fix #XXX").
| jedberg wrote:
| I keep my personal dev folder in Dropbox so I don't have to worry
| about lost work since it always syncs to the cloud. My work dev
| folder uses syncthing to a remote server for the same purpose.
|
| I make my own branch and then do checkins when I get to good
| stopping points. Then I do git squash merges to staging or the
| group branch when I have nice small updates. Keeps the public
| history clean and also lets me revert back to the previous
| stopping point, while not being worried about lost work.
| BerislavLopac wrote:
| Amend and force push are your friends.
| miscaccount wrote:
| have you looked into squash commit merge.
|
| Basically you do the same workflow as you are doing now, just
| squash it to a single commit so that wherever is your last commit
| stays.
|
| if needed you can go to your branch for history
|
| https://stackoverflow.com/questions/5308816/how-can-i-merge-...
| surfer7837 wrote:
| GitHub/Gitlab allow you to rebase your commits when merging. We
| do that, but has the disadvantage of mucking up things for people
| who are using that commit. I personally think it's worth it
| user3939382 wrote:
| I have everything aliased and use few commands:
|
| gb feature/Foo // make a branch called foo from the current
| (usually develop) and switch to it
|
| // make edits
|
| gac I did a thing // add all files and commit with this message
|
| mduc // Merge current remote develop into this branch
|
| git push
|
| mkpr // Create a draft PR from this branch on github and open my
| browser to it
| wildpeaks wrote:
| When multiple people work in the repo, I like Squash Merge in
| Github best because you can still do small commits in your
| feature branch, and when you merge, it generates a message from
| all commits messages (so there is still a trace of the process,
| but you can get rid of noise like "fixed a typo" with the benefit
| of hindsight) and history looks clean because it's merged as a
| single commit, no rebase footgun to worry about.
|
| https://docs.github.com/en/pull-requests/collaborating-with-...
| ghotli wrote:
| I barely skimmed what's below so maybe someone else has covered
| this, maybe not.
|
| If I need to hack on a task and I know I'm the only person that's
| going to work on the branch I amend changes to my commit
| basically constantly. The only reason I might not is if I want
| multiple commits on the branch to make review simpler for others.
|
| ```
|
| git fetch && git checkout main
|
| git branch feature/JIRA-###/words-describing-it
|
| git checkout feature/JIRA-###/words-describing-it
|
| <do some work>
|
| git add .
|
| git commit -m "JIRA-###: words / description"
|
| git push -u origin feature/JIRA-###/words- describing-it
|
| <review CI build, make more changes>
|
| git add .
|
| git amend
|
| git push -f
|
| ```
|
| `git amend` is an alias in my ~/.gitconfig
|
| ```
|
| #cat ~/.gitconfig
|
| <snip>
|
| [alias] amend = commit --amend --no-edit
|
| ```
|
| So most of my commits I just amend the first commit I made, force
| push, review CI build results, rinse repeat until it's ready for
| review.
|
| Simplest thing that works when it's just my own work on a branch.
| I'll also do a rebase pre PR review if need be.
|
| ```
|
| git fetch && git rebase -i origin/main
|
| git status
|
| <do what it says if anything>
|
| git add <fixed files>
|
| git rebase --continue
|
| git push -f
|
| ```
| camnora wrote:
| I tend to keep my PRs small enough to where several can be
| submitted within a day. This being said, I tend to keep my
| changes un-staged.
|
| When I'm ready to commit:
|
| 1. `git diff` to get an overall picture of what changes were
| made. Which parts of this diff can be packaged into an isolated
| commit?
|
| 2. `git add -p` This is where I selectively stage bits.
|
| 3. `git diff --cached` to verify that the staged items are all in
| place
|
| 4. `git commit` with a detailed message.
|
| 5. Repeat steps 1-4 until all changes have been committed.
|
| 6. `git fetch origin main && git rebase origin/main`
|
| 7. Finally, `git push`
|
| When PR feedback is left by peers, some teammates prefer you to
| not rewrite commits and force push. This makes re-review easier
| for them (especially if you use the Github features around PR
| review).
|
| I opt for rewriting commits if it's okay with team members. This
| way you don't have "fix typo" commits getting merged into the
| main branch.
|
| Edit: formatting
| bubbab wrote:
| Messy WIP commits that are reorganized to cleaner commits later,
| like most others have said.
|
| However, instead of rebasing, I often git reset to the beginning
| and recreate the commits from scratch, using partial file commits
| (or staged hunks). IDEs/editors like VS Code make it really easy
| to stage an individual part of a file for the commit. The CLI way
| (git add -p) has always been pretty confusing to me.
| btschaegg wrote:
| Not entirely unlike yours, but I also very often use `git commit
| --fixup` and let the computer clean up large portions of my
| messes with `git rebase -i --autosquash` later.
|
| That is, nowadays I usually do the same, but through Git Fork [1]
| (via its custom command system), and it works even better than
| the terminal interface for me -- which doesn't happen often. But
| for fixups the "find the target commit in the history and use a
| context menu entry to flag your commit flow" really works rather
| nicely.
|
| Also, Fork's interactive rebasing dialog does `--autosquash` by
| default.
|
| [1]: https://git-fork.com
| crnkofe wrote:
| The n1 rule I follow (and push everyone to follow) is: "Don't
| write shitty commit messages." It helps in general with
| everything related to Git.
|
| Otherwise I decide ahead of time and focus on one area at a time
| that I know is a small chunk of functionality (like adding
| boilerplate for a small script, unit testing a piece of
| functionality, implementing an endpoint) and as long as I'm
| working on it I just use git add -A ; git commit --amend --no-
| edit . Once I move on to new self-contained batch of
| functionality I make a new commit and repeat the amending. It
| requires a bit of discipline to keep commits small enough but I
| like it since it's an easy process to follow.
|
| Before I make a review request I usually do an interactive rebase
| and reword commit messages, sometimes reorder them and squash
| small stuff if it makes sense. After a review is in process I
| generally no longer rebase (to keep review transparent) and
| commit each fix separately.
| jakupovic wrote:
| Make as many commits as needed to get whatever it is I'm working
| on "working". Then by default all the commits get merged during
| Merge Request and we get one commit to master.
| deckard1 wrote:
| The flow you use will typically depend on the company you are
| working for. Using regular git (no Github/Gitlab) will often have
| a different workflow than Github.
|
| My team (and myself) prefer this workflow:
|
| - One commit per PR. This allows for easy reverts and cherry-
| pick.
|
| - One developer per branch. You can do a few devs per branch, but
| rebases need to be coordinated and carefully handled, because:
|
| - No merge commits. Only rebase onto latest main. Which means
| force-pushing PR branches and, thus, rewriting history (other
| devs working on same branch need to be aware that history has
| changed).
|
| If you're constantly rebasing onto main, then all of your working
| commits sit on top of the latest code in main. Which means you do
| not have to deal with tricky merge conflicts, where your commits
| may weave in and out of the main branch at various points in time
| because you were doing "git merge" at random points. In addition,
| if you squash your commits before doing a rebase this will _also_
| make merge conflicts rather trivial, because you 're only dealing
| with one set of merge conflicts on one commit.
|
| That's the big picture, team workflow. For my _personal_
| workflow, I rely on "git add -p" and stashes. The only time I do
| a commit and push up code is: a) when I have a large change and
| want to make sure I don't lose it _or_ b) others have already
| reviewed my PR and I want to keep the new changes separate to
| make their life easier when reviewing a 2nd time. I use "git
| reset --soft HEAD~<number-of-commits>" to squash instead of "git
| rebase -i" because I find it easier and quicker.
|
| I must emphasize this point: learn "git add -p". It's _extremely_
| useful in the case where you have some changes like debugging
| code or random unrelated changes that you do not want to commit.
| It 's a filtering mechanism.
| wodenokoto wrote:
| > - One developer per branch.
|
| I had never even considered that some teams might have multiple
| developers active on the same branch.
| teeray wrote:
| I often commit as well to checkpoint, and push those onto a
| branch organized under my username as a backup
| (<username>/<branch> to make use of ref folders). When I'm done,
| I use interactive rebase to clean the branch up, writing
| meaningful commit messages for each unit of change (answering the
| question "why does this commit exist?" usually). I force push
| that cleaned up branch and then open a PR.
|
| My view is that final commits are a form of communication, and
| deserve some intention. I've thanked myself when I've looked
| years back at work I've done and been able to figure out not only
| the change, but also my own state of mind.
| EVa5I7bHFq9mnYK wrote:
| Maybe they commit "misspelings and whitespaces" to their private
| branches and then commit clean batch to the shared repository?
| whoomp12342 wrote:
| commit early, commit often is really great for beginners. I dont
| do that. I commit when it makes sense to. Since my commits will
| get rebase squashed on merge into master, I dont put a ton of
| effort into doing it perfect.
|
| Reasons I commit 1) it feels right, this was a good logical step
| 2) ima bout to do something that might break everything like a
| refactor 3) everything works so it makes sense to before I do
| something else
| bsimpson wrote:
| I have three branches: macbook, imac, and develop.
|
| develop is the mainline branch that other people could pull from.
|
| macbook and imac are each backups of their respective machines. I
| use git merge --ff-only to rebase commits from one to the other
| when I change machines. If I need to change machines midway
| through a commit, I'll push a WIP commit to imac, fastforward
| macbook to match, and then git reset HEAD^ to keep the WIP files
| (but undo the commit) on macbook. I finish on macbook, make the
| commit, and push it to origin's macbook and develop.
|
| Like the others here, I make liberal use of git rebase -i to
| reorder commits, etc. If imac and macbook ever diverge (e.g. I
| forgot to push a commit before changing machines), I also use
| interactive rebase to resolve it.
| twofornone wrote:
| >I also push often because I'm forever aware disks can fail.
|
| In the 20+ years that I've been using computers, and [?]15 or so
| that I've been writing software, I've never experienced a drive
| failure.
| brimble wrote:
| About 30 years using computers, a little over 20 being paid to
| do it. I've had two fail outright (one internal, one external)
| and a couple others develop errors that I noticed (one because
| I finally started using ZFS on my bulk-storage machine and it's
| very good at telling when a drive is misbehaving, the other,
| SMART caught, years ago) so they had to be replaced. All were
| spinning rust. Maybe 50 drives total, over my computer-using
| life, counting those in game consoles and ones in work machines
| that were assigned to me. Including SSDs. Give or take 10.
|
| With the experience of the last 3 or so years of using ZFS, I'd
| bet _most_ of my "still working" drives over the years were
| erroring and losing data by the time I replaced them, and I
| just didn't know it.
| contingencies wrote:
| Some non physical failure scenarios I have experienced include
| catastrophic filesystem failures (NTFS: _never again_ ), loss
| of machine and no handy backup machine capable of reading the
| disk or filesystem in question (ext _X_ , ZFS, etc.),
| accidental damage to disk, partition or filesystem tree due to
| bad code (operator error; PEBSAC).
| TillE wrote:
| I've had a Macbook SSD fail (suddenly and completely) within
| the warranty period. Surprisingly I've only had one hard drive
| fail before I retired it, maybe when it was about 6 years old.
|
| But those are just the catastrophic failures, I'm pretty sure
| I've also had hardware-related data corruption here and there
| as well.
| amarshall wrote:
| Sure, but your anecdote does not refute in any way that they
| can fail. It's all about risk vs. overhead of avoiding that
| risk. The overhead of pushing often is very low, so even with
| the low probability of a drive failure, there's not much reason
| to not do so (or any other form of backup, really).
| secondcoming wrote:
| I have. You're not coding hard enough!
| El_RIDO wrote:
| This is a good example of how scale can bias your view! :-D
|
| Personally I share the same experience: In the 30 years I've
| been using personal computers at home and work, only 2 disks
| failed on me, one was an error on my part during an OS upgrade
| and the second was an external disk that physically fell off my
| bed while I had it plugged into my notebook. So both of these
| weren't really those random failures.
|
| On the other hand, while working in an IT infra team of a 60
| developer company with 4 racks full of servers for 3 years,
| we'd get to see about one failed SSD per 2 months and 2-3
| failed disks or SSDs per year in servers.
|
| During the 1 year I worked for the IT infra team at a smaller
| hospital of a medium sized city with a large VDI environment
| and two HP EVAs in a two datacenter configuration each, we'd
| get 3-4 disk failures per week. Those had over 140 disk per
| storage each and were approaching the end of their support
| life, being around 5 years old, so the failure ratio started to
| get higher.
| throwawayboise wrote:
| All I use in git is clone, pull, commit, push. I do not use
| feature branches. The only branches I use are for releases that
| need to be maintained separately from master.
|
| I absolutely do not care if there are "fix typo" or WIP commits
| in the history. The amount of effort it takes to get a "clean"
| commit history has negative payback in my experience.
|
| It should be said I am a lone developer for the most part,
| sometimes working with one or two other people. So Git in fact is
| overkill for that scenario. Subversion would do just as well and
| in fact I prefer it or mercurial.
|
| In a large project such as Git is meant for, my usage probably
| doesn't apply.
| gxespino wrote:
| I like to git commit --amend --no-edit
|
| often
|
| once a piece of functionality is working, edit the commit so it
| makes sense
|
| start new commit and work on next piece of functionality, repeat
|
| clean commit history not just for me but for my coworkers who
| will benefit from seeing a cohesive commit diff
| alkonaut wrote:
| I imagine many like me use it so often they have this as the
| alias "git oops".
| 8note wrote:
| I generally know what I want commits for before I start writing.
|
| While writing I make my first commit once I've got one file
| changed, then ammend it as I go.
|
| If I write a whole ton of code/don't plan well in advance, I can
| end up with a few changes on the go at the same time. I'll tend
| to reset all the commits at the end and interactively add lines
| to commits
| megapusher wrote:
| worik wrote:
| I commit when I finish a task.
|
| I push at least once a day
| nikivi wrote:
| I use Sublime Merge (https://www.sublimemerge.com) for all git
| commands. For automating commits on things like curated lists /
| wikis / .. I use gitupdate
| (https://github.com/nikitavoloboev/gitupdate)
| [deleted]
| CogitoCogito wrote:
| I usually squash my branches to single commits in the end and
| write a nice message then. There are times when I don't do this.
| For example, yesterday I was moving existing code to a separate
| project and I first committed the original version and then made
| necessary changes in my next commit. This made it clear where
| things differed from the original.
|
| Overall I think commits that land in main should be worthy of
| landing in main. Random crap you tried isn't important. Larger
| self-contained changes are.
| immutology wrote:
| Squash-merge PRs. You can configure this in GitLab, GitHub, and
| Azure DevOps. Your private commits can be whatever you want and
| they get rolled up to a single PR commit when your working branch
| is merged to trunk.
| beders wrote:
| Yes. Much easier to roll back things, cherry pick things and
| blame people ;) Don't you dare merge a PR with 30 commits.
| conradludgate wrote:
| +1 to this. I like the mantra that every commit is deployable
| _se wrote:
| I think part of it depends on the tooling that you're using and
| what your review system supports. Assuming that these are all
| supported, I would generally:
|
| 1. Push very often, essentially every time I'm going to context
| switch or take a break
|
| 2. Iterate often, get things working, then clean them up, pushing
| at each step along the way
|
| 3. Interactive rebase to squash into meaningful stacked commits
| for review
|
| 4. Mark the change as ready for review by my team
|
| I have found stacked commits to be the best way to both perform
| and author reviews by a wide margin. It's so much easier to
| review 4 200 line semantic changes than a single 800 line change.
| You'll get better feedback from others, and thinking about
| development in this way can also lead to better results on its
| own.
| kraftman wrote:
| Pretty similar to you, I commit as often as possible, but I also
| push whenever I commit so that its backed up. Then once its ready
| for review, I do an interactive rebase to try and group the
| commits into useful chunks for the people reviewing, and to
| improve the commit messages.
|
| Git is crazy complicated under the hood which is awesome when you
| mess up and need to recover something, but in general my goal is
| to use as few git commands as possible and keep everything as
| clean as possible.
| timongollum wrote:
| If you are afraid to lose what you've done, you can stash your
| minor changes to keep track of the small things that you already
| got working, and then, when you got enough working to make a
| commit, you do it with the best code you got. And for the many
| pushes, you could backup your projects files everyday. I think is
| a much more appropriate way to use the tools that git gives us.
|
| That way, you won't be afraid to lose your recent work by messing
| something up, because you have the stash, and won't be afraid to
| lose your whole project/progress because you have a recente
| backup of it.
|
| For instance, I have a backup script that runs everytime I
| shutdown my work computer so I won't have to worry if suddenly my
| hard drive gives up on everything.
| rendall wrote:
| I say, you have it right and your coworkers are less so.
| Encourage your coworkers to be secure in their work. Show your
| struggles, false starts, mistakes, typo fixes. Embrace the messy
| history!
|
| My last few teams' workflows and projects were such that commit
| history wasn't really a big deal. I'm skeptical that it matters
| if the dev-to-production process is smooth.
|
| These tips are habits we have:
|
| Keep commit message first line to under 50 characters, use
| imperative mood, capitalized. If you need more than that to
| describe what's going on then the commit might be too big.
|
| PRs must pass all continuous integration tests + 1 or 2 devs
| approval. Pretty much always do what a dev suggests in review,
| even if you disagree.
|
| Optionally, squash merge PRs to master, to make reverting easier.
| I prefer that.
|
| If a feature is very complicated, break it down into smaller
| tasks, merging each to master when completed.
|
| Maybe use a feature branch for super complicated inextricably
| tasks, but doing that too often is a code smell.
|
| In that situation, code history isn't really that important.
|
| That said, if you're still keen, look up these commands:
| git commit --fixup {commit id} git reset --soft {something}
| git rebase -i --autosquash {commit id}
|
| Lots of force pushing, will be needed, but never, ever force push
| to a shared branch unless every one agrees and is aware.
|
| Those can straighten out your history right out.
| whycombagator wrote:
| > Pretty much always do what a dev suggests in review, even if
| you disagree.
|
| I disagree.
| muzani wrote:
| My "atomic" level is that it can build. I try to minimise time
| between commits/pushes because often I work on two different
| computers. So I don't try to keep it clean, and often cleaning is
| its own commit.
|
| Android is a little weird in that a build may take 6 min on the
| production app though. So a lot of code is written and tested on
| an external repo where it might take 20 sec instead and then
| copied in when complete. Looking clean/complete isn't the intent
| but that's how it ends up.
| amarshall wrote:
| When forming commits, this is the rule of thumb I have: can the
| entire diff of a commit be understood and explained, both in
| content and intent, by its commit message, ideally by someone
| months or years from now? If not, the commit is not properly
| "atomic" or the message deficient in some way.
| [deleted]
| Drdrdrq wrote:
| I try to make clean commits that do one thing only. If I have
| trouble writing a meaningful commit message, it means I have
| failed and should do a better job next time.
|
| That said, I often make a messy "wip" commit that I push to my
| branch, just so that the work doesn't get lost. But I always undo
| such a commit and clean it up.
|
| Also, I always use git add -p, so that I can break changes into
| multiple meaningful commits and review them one more time before
| pushing.
| danielyaa5 wrote:
| I think clean commit history is overrated as long as your squash
| and merge prs into main. I've tried clean commits using rebase
| and I just don't think overhead for me personally is worth it.
| What's more important is small PRs. And if you can't do that
| usually find spending some time reviewing the code with the
| reviewee is also helpful
| yboris wrote:
| Before I ever commit anything, I always run _diff2html_ command
| to view my changes in HTML side-by-side (I even have an alias
| `diff` that makes it fast and easy).
|
| https://diff2html.xyz/
| cosmosgenius wrote:
| ohmyzsh adds two git alias which I use very often `gwip` and
| `gunwip`. I push `gwip` commit for work which I am not clear on
| if to do a clean commit. Once I have settled on a unit of work (
| like code + tests + docs ) I use `git add -p` to selectively
| create clean commits. For "fix misspellings and whitespace" kind
| of stuff use `git commit --amend --no-edit`.
| bjourne wrote:
| Here is my last five commit messages: "width*height is area",
| "fixing stuff i broke", "rm properties we dont need", "rm more
| useless attributes", "nicer figures". I do my best to keep the
| code base as clean as possible, but I couldn't care less about
| keeping the commit history pretty. Any time spent on prettifying
| git history is better spent on documenting the _existing* code
| imo._
| sodapopcan wrote:
| It depends on the project. An open source library should
| probably have a sane history, a closed-source application, in a
| lot of cases it doesn't matter so much and often useful to see
| the whole workflow.
| kyleee wrote:
| i think this can be true, in some cases the git history may
| never be looked at so agree effort may be better soent
| elsewhere
| pionar wrote:
| I do the same, but before pushing, I squash the commits to remove
| the small intermediate commits. That may be what your coworkers
| are doing as well.
| [deleted]
| jve wrote:
| Yeah.
|
| Consider I have a feature branch that no-one depends on. When
| my history is messed up I do easy rebase : git
| reset --soft master (or whatever commit up to which I want to
| UNDO, but no further than commit I branched off from)
|
| Now at this point changes from multiple commits are in my
| STAGING. git commit -m "Feature X implemented"
| git push --force (you can do If no-one depends on your branch,
| otherwise - don't do this)
| qorrect wrote:
| Ohhh, you trickster! Going to start doing this.
| jessikat wrote:
| I use branches gratuitously, and push to my forks regularly as
| you do, but I also do interactive rebases and edits when
| preparing to push to upstream to clean up my mess.
| dspillett wrote:
| _> The code may be a mess, the variables may have names like
| 'foo' and 'bar' but I commit to have a last known good state. If
| I start mass refactoring and break the unit tests, I can revert
| everything and start over._
|
| For that use case, if you are sure you don't want the intervening
| history in the main source repository, is to keep your "scratch"
| commits to a local store. This could be a branch, or a separate
| repo.
|
| For my work areas I have a timed rsync taking snapshots, and can
| kick it off manually if I want to make a snapshot for a specific
| time (just finished debugging a major function, for instance). If
| there have been no changes since it last run the snapshot is not
| kept (just a note added to a file to say one was considered at
| that time). Identical files are all hard-links to the same data
| so it is pretty space efficient unless you have some large assets
| that change regularly. This has the advantage that I don't even
| have to remember to commit to anything: the snapshot is
| _automatically_ taken regularly. Rolling back is manual, but
| rarely needs to be done and can be done easily for small parts of
| the update if the rest needs to stay.
|
| Every now and then, as this is just backing up temporary work
| status, clear down snapshots older than a given point in time.
| Using a source control repo and auto-committing to that would
| work as well as creating filesystem based snapshots like I do I
| should think, but all my other backups were rsync+snapshot based
| when I set this up so I just repurposed existing scripts for the
| job.
|
| _> I 'm forever aware disks can fail. I'm not leaving a day's
| worth of work on my local drive and hoping it's there the next
| morning._
|
| Keep the snapshots on a different drive, or even a different
| machine (they are mostly in my case, though "just because it
| happened to get laid out that way" rather than by thoughtful
| design). Mine are even covered by daily off-site backups so if
| the place burns down overnight I still don't lose them (or at
| least absolutely no more than a day's worth). Just be careful
| with rsync, if you use this method, due to the many hard-links as
| the --hard-links option can be quite CPU and memory intensive,
| and if your backups are usually append-only you'll need to
| occasionally wipe old snapshots that are long since irrelevant.
| jdc0589 wrote:
| I see no value in shorter "clean" commit histories in a feature
| branch. In fact, if you need that, it might imply that the PR is
| too large to look at holistically, which is a red-flag.
|
| Half my PR's probably have a commit that just says "mashed
| potatoes", or 5 commits in a row that say "maybe it works now?".
| It doesn't matter, its going to get rebased/squashed to a single
| commit in the merge process anyway (which IMO everyone should be
| doing, true merges from feature branches to mainline are bad).
| floodle wrote:
| I don't use commits as "atoms" of the work. Instead, I work at a
| PR level. I make PRs small and often, and try to make each one a
| small, self-contained piece of work, usually not more than a day
| or two.
|
| Practically this means that I commit and push whenever I feel
| like it, but then always squash the PR. At that point I create a
| clean and informative commit message.
|
| However, I leave a lot of context and information in GitHub
| rather than putting it in large commit messages. I rely heavily
| on GitHub's automatic linking of issues and pull requests for
| this.
| kstrauser wrote:
| This made me realize I haven't heard about git-flow[0] in ages.
| There was an era when it seemed like everyone wanted to use that
| for everything, even when it didn't make any sense.
|
| [0] https://nvie.com/posts/a-successful-git-branching-model/
| chaitanya wrote:
| You can have the best of both worlds -- "commit early, commit
| often", and "nice clean commit histories" -- with git, and it is
| easier than most people think.
|
| - So you start work on a new branch, and reach a checkpoint.
| Create a new commit with "git commit".
|
| - Continue working, and when you reach the next checkpoint,
| create another commit. But this time, use "git commit --amend".
| Contrary to what the flag says, this doesn't modify the previous
| commit, instead it modifies your commit history and replaces the
| last commit with a new one[1]. So instead of having two new
| commits in your branch's history, you only have one.
|
| - Repeat the process until you have something worth pushing to
| the remote.
|
| - Once you've pushed to remote, remember to not make any further
| modifications to your git history[2] i.e. going forward, create a
| new commit and only then run "git commit --amend".
|
| Now, there's an obvious question here: if "git commit --amend"
| keeps replacing the last commit with a new one, what happens when
| you mess things up and want to revert to NOT the last checkpoint,
| but some checkpoint before that?
|
| The trick here that git has up its sleeve is called "git reflog".
| You see, while "git commit --amend" replaces the last commit in
| your branch's history with a new one, the older commit is not
| actually gone, its still there. And you can see all of them with
| "git reflog". Basically "git reflog" returns every commit at
| which the local HEAD (i.e. the commit checked out in your working
| directory) has been. So none of the commits that you replaced
| with --amend are actually lost, and you can find them all in the
| reflog.
|
| Restoring to an older checkpoint becomes as easy as running "git
| reset --hard <previous-commit-id>", or if you want to play safe,
| "git checkout -b <new-branch-name> <previous-commit-id>".
|
| Hope this helps!
|
| Notes:
|
| 1. By design, a commit, or in fact most objects in git cannot be
| modified. They are immutable.
|
| 2. Basically you can play with git history as long as it is
| private to you and not shared with others. But the moment you
| push it to a remote you share with others it's no longer private
| and you must not modify that history anymore. Read Linus's note
| on keeping a clean git history: https://www.mail-archive.com/dri-
| devel@lists.sourceforge.net...
| sbinnee wrote:
| meowface wrote:
| >I also push often because I'm forever aware disks can fail. I'm
| not leaving a day's worth of work on my local drive and hoping
| it's there the next morning.
|
| I separate file backup and version control. I keep every git
| repository I'm working on in Dropbox, and don't ever worry about
| how often I'm committing and pushing. I don't think git should be
| considered a substitute for a proper continuous backup system.
| jedberg wrote:
| Same. I used to make a commit every time I got up so as not to
| lose work, but that just littered the history. Then I switched
| to keeping it in Dropbox or using Syncthing for work stuff, so
| now I only have to commit when I get to a stopping point or to
| share with others.
| meowface wrote:
| Yep. Dropbox is also a great safety net for when I mess
| something up in between commits. I've had a few times where
| I've deleted or changed some code that I couldn't restore
| just via undos. Normally I'd pretty much be screwed, but
| Dropbox retains a diff every time a file is saved, so it's
| basically impossible for me to lose anything.
| globular-toast wrote:
| Agreed but pushing at least at the end of the day should be
| required just in case somebody needs to pick up your work for
| some reason.
| rraval wrote:
| > I separate file backup and version control. I keep every git
| repository I'm working on in Dropbox, and don't ever worry
| about how often I'm committing and pushing.
|
| Motivated by a slightly different use case (seamless syncing
| across multiple machines), I built a custom tool that solves
| this concern within `git`: https://github.com/rraval/git-nomad
|
| You can toss `git nomad sync` into a systemd timer (or cronjob
| if you prefer) and forget about it.
| dimtion wrote:
| The most important git feature I discovered was `git add -p`,
| this allows both to select which patchs to stage, but also to do
| a review of what you are going to stage. Combined with `git
| commit -v`, this allows you to have plenty of occasions to review
| your changes before creating your pull request.
|
| Shameless plug, but here are other efficiency tips I wrote about,
| for working in a high demanding environment:
| https://dimtion.fr/blog/average-engineer-tips/
| aghilmort wrote:
| depends on function for me:
|
| - new features tend to be one clean PR since there's so much
| experimentation on what will work and lots of commits tends to
| slow things down -- a nominal disk backup is helpful, or even
| just a commit when taking a break on a branch of your own, no PRs
| until clean
|
| - refactoring tends to be lots of test / experimental / ugly
| branches with incremental PRs, since tends to be easier to say,
| ok, change this one thing
|
| - been experimenting with some third in-between mode, say add X
| with a bit more of a planning / sprint mindset vs. oh wow, let's
| see if this works
|
| - feels like this approach is more of works for startups,
| probably harder to do in enterprise / large teams?
| izietto wrote:
| My flow is:
|
| 1.a. a lot of dirty commits/wip commits
|
| 1.b. a few of clean commits, when I spot changes that I know they
| are already a commit by itself
|
| Before opening the PR:
|
| 2. `git log -p`: I inspect the commits I've done and I decide
| what should go together, what should be edited and what can stay
| as it is
|
| 3. `git rebase -i`: I apply the changes I've decided during 2
|
| 4. repeat 2 and 3 until I'm happy with the results
|
| 5. the last `git rebase -i`: reword almost every commit, as
| almost all the commits at this point have placeholder
| descriptions
|
| I'm very happy with this strategy. It requires some time to get
| used to it but at the end my PRs are very clean and well-thought.
| globular-toast wrote:
| One thing that can make rebasing much easier is making use of
| --fixup and --squash. Often you know at the time that a commit
| is either fixing a previous commit or that you would want to
| squash it with a previous commit. This can save a lot of time
| later as you can simply issue a --autosquash to rebase. If you
| do it right it means others can rebase your branch too.
| RobertRoberts wrote:
| I do the same as you, get the work done, keep is stable. Being
| clean and pretty is the _last_ thing I do.
|
| (based on years of experience with errors, failures, data loss,
| etc...)
|
| edit: But I also now like to be messy in a dev branch, so it
| matters less in the grand scheme.
| theshrike79 wrote:
| Create branch, I commit stuff always when my stuff isn't actively
| broken and I can somehow describe what the change did.
|
| I push often just to be sure. (This is the modern equivalent of
| constantly hitting Ctrl-S to save).
|
| Squash and clean up before merging to main branch after PR is
| reviewed and accepted. This makes rolling back the change a lot
| easier and keeps the main branch log clean from "let's see if
| this crap works" -style messages.
| TameAntelope wrote:
| At the end you can just do an interactive rebase and squish the
| commits away that don't clearly explain what functionality you've
| added.
|
| I believe you can also configure your PR software to attempt to
| squish for you? I'm not sure about that, but I think I've seen an
| option in the settings somewhere.
| Macha wrote:
| I commit chronologically, then depending on the scope of the
| changes refactor into logical subsets, or just squash into a
| single commit.
| aurelianito wrote:
| Commit early. But do not commit garbage. Each commit should be a
| small but meaningful advance. All tests should pass. If working
| with compiled code, off course it should compile. No todos. No
| clunky var or method names. A branch per merge request.
|
| If you do it like this it is great for everyone. Do not squash
| commits or rebase. Those are antipatterns. We are lying to
| ourselves when we do it. We cannot learn from history we rewrite.
| rootusrootus wrote:
| I follow your flow, and I don't bother squashing my commits. So
| the repo history has lots of dumb little commits. We use a branch
| model for features, though, so I can just filter for those merge
| commits if I want to see granularity at the feature level.
| muxator wrote:
| Easier for you. Harder for who reads you history.
| rootusrootus wrote:
| Probably. Like I said, though, it's easy to just look at the
| merge commits and ignore the rest. I don't personally read
| per-commit history almost ever. If I have to follow someone's
| train of thought _that_ closely to understand what happened,
| then 1) the docs suck, 2) or there should have been comments
| and they are missing, or 3) the story was too complicated.
|
| I will stipulate in advance that this is very much going to
| vary by project, language, and experience. It is entirely
| legitimate to have a different point of view ;-).
| mkirsche wrote:
| In addition it makes rebasing harder, which might make you
| use merge commits and then reading your commits gets even
| worse because changes might hide inside those merge commits.
| perlgeek wrote:
| I commit often, push to branches until I'm satisfied, and for
| smaller branches often do squash-merges so all of the mess
| doesn't show up in the history.
|
| Also, I too used "foo" and "bar" as variable names, but stopped
| doing that. If I find myself using nonsense names it means that
| my mental model of the problem (or the solution) is too vague.
| Then I stop and think about it instead of going ahead at full
| speed.
| globular-toast wrote:
| Rebase is the key.
|
| There are two types of commit: checkpoints and versions.
|
| Checkpoints are just you randomly deciding to "save" your
| progress. They don't necessarily correspond to completely working
| versions. The commit messages can be completely inappropriate for
| sharing but only make sense to you.
|
| Versions are fully working copies of the program that could be
| checked out, run, released etc. These are what you present to
| your team and what gets merged in the end.
|
| Sometimes you can write a new version straight away but other
| times you'll generate checkpoints first. Then you use rebase to
| get to versions. Use rebase as a way to make it look you are a
| superhuman writing perfect commits first time.
|
| Getting good at rebasing takes some practice and pretty good
| understanding of git's data model. Learn this. And learn how to
| use --fixup, --squash and --autosquash to make your life easier.
| [deleted]
| dboreham wrote:
| Lots of commits. Squash merge the PR (github feature) to clean up
| the commit history.
| nvarsj wrote:
| I've been introducing https://ejoffe.github.io/spr/ at work and
| am pretty happy with it. It makes the process of managing stacked
| PRs really smooth. With that tool, I usually just create a local
| branch and run git spr up when commits are ready.
| michaelsalim wrote:
| I commit as soon as a single functionality makes sense as its
| own. Simple example: If function X uses function A, B and C. I'll
| commit after finishing A, B, or C. And once X is then, I create a
| separate commit. I also ensure the code still runs most of the
| time. How I group them depends on how complicated it is. The more
| complex, the more commits.
|
| This helps me write code that are more standalone (easier to
| replace & test). Also helps to clear the cognitive burden when
| developing larger features. Anything that's committed are pretty
| much "done". So if I leave any work mid-way, I can simply look at
| the untracked files to know where I was at.
|
| Then at the end of the work/PR, I go through every changes to
| make sure everything makes sense.
|
| In practice, this means that the first code I write is often the
| last I commit (see my simple example above).
| wry_discontent wrote:
| For smaller PRs/bugfixes, I'll often just have 1 commit, and
| that's all it took me to write.
|
| For bigger things, I do stream-of-consciousness, rebasing
| somewhat often when I get to a place where I like things.
|
| Unfortunately we're all about merging, so that mucks up my
| commits a bit.
|
| I use Magit to handle all that for me, which is by far the nicest
| git interface I've ever used.
| burnished wrote:
| I try to commit whenever I have enough to write a coherent
| message. I branch out to provide me with an objective and I merge
| back into main when I accomplish it.
|
| I think I'm going to start using rebase to get those clean commit
| histories though.
| [deleted]
| jmkr wrote:
| 1. Create feature branch
|
| 2. Make changes
|
| 3. Commit changes at whatever point and write a good commit
| message about the feature.
|
| 4. Commit more.
|
| 5. Create feature/branch_rebase
|
| 6. Squash all the commits.
|
| 7. Push to fork
|
| 8. Make pull request
|
| 9. Make fixes and push those commits per fix.
|
| 10. Squash when merging back to that first commit.
|
| I like having a separate rebase branch because then I have all my
| work in one branch and the history of what I did. Then I squash
| it and get rid of the that history, then maybe rebase main back
| into it if there we changes since I started the feature.
| blobbers wrote:
| git rebase -i HEAD~5
|
| Where 5 is some number of commits (or origin tags)
|
| Is your best best friend! Write great messages, squash things, or
| fix ups. Force push over your branch after you clean up... and
| send out a great PR!
| [deleted]
___________________________________________________________________
(page generated 2022-03-17 23:01 UTC)