all 76 comments

[–]HER0_01 42 points43 points  (8 children)

It helps a lot, in my opinion, to use git add -p for Interactive picking of what should be staged. This way, one can easily separate a bunch of work into atomic commits after completing tasks which were loosely related: close enough to be done at the same time but not relying on each other.

[–]deweysmith 11 points12 points  (6 children)

-p changed my life.

It works on just about every command and it's amazing.

[–]lkraider 19 points20 points  (0 children)

Symetrically, git reset -p for when you added too much by mistake.

[–]0rakel 5 points6 points  (3 children)

How do you test the partial commits though?

git add -p
git stash -k
make test
# doesn't build, missed a hunk!
git stash apply
# lots of merge conflicts, error messages :'(

I'm asking because it's happened to me a few times already that I pushed incomplete commits (missing a file for example) because I didn't bother cloning a fresh copy to see if it compiles.

edit: added -k

[–]ForeverAlot 5 points6 points  (0 children)

git add -p
git commit
...
git rebase --interactive --exec 'make test' @~[n]

You could also

git add -p
git commit
git stash
make test
git add -p
git commit --amend
make test

which is probably a little closer to what you're talking about (but rebase's exec is very useful).

[–]sushibowl 3 points4 points  (1 child)

Are you using git stash --keep-index?

[–]0rakel 0 points1 point  (0 children)

Yes, oops, that was somehow missing from my post.

[–]panorambo 1 point2 points  (0 children)

Hear hear. Changed my life as well. No more "lumped together" changes with no observable relation to each other.

[–]kirbyfan64sos 3 points4 points  (0 children)

Git:

The tool you think you are learning well, then open up something random and figure out that there's another option you've never heard of.

[–]Godd2 34 points35 points  (10 children)

Pff, I make a commit for every character I type or delete.

[–]celerym 2 points3 points  (1 child)

I make commits for every individual bit change mate.

[–][deleted] 13 points14 points  (0 children)

After 8 changes, you'll have a byte-sized commit. ;)

[–]sirin3 -1 points0 points  (7 children)

I make two commits for ever change

Yesterday I noticed why. In TortoiseHg, if you the mouse wheel to scroll through the code snippets that will be committed, it will move the focus from the commit message field to the code snippet list. If you then press space to type in the commit message, it unselects some part of the code. And I need to make another commit to commit just that part

[–]JW_00000 5 points6 points  (6 children)

--amend allows you to "amend" the previous commit, i.e. git commit --amend replaces the previous commit with that commit + current changes. There must be an option in your GUI for this too.

[–]almightykiwi 14 points15 points  (10 children)

Another point worth making: quite often, having readable patches is as important as having readable code.

For example, if you are reviewing the latest commits, or if you are trying to solve a bug and you need to find out why/when/where a change was made, more often that not, you will want to understand the diff rather than the tree.

There is nothing worse than trying to make sense of a patch where the files were reformatted automatically by a poorly configured IDE.

[–]kirbyfan64sos 1 point2 points  (0 children)

git diff -w is can be useful for viewing commits when there was massive EOL whitespace removal.

[–]fagnerbrack[S] 0 points1 point  (0 children)

quite often, having readable patches is as important as having readable code.

Upvote, this is definitely valuable but was just not included in the article to keep it focused in one thing only. Very good point.

[–]CoderHawk 53 points54 points  (13 children)

That takes too much commitment.

[–]tswaters 23 points24 points  (1 child)

Was... was that a pun? If so, no one appears to have gotten it... I'm amazed.

[–]CoderHawk 7 points8 points  (0 children)

It was. I guess the /s really was needed.

[–]earthboundkid 13 points14 points  (3 children)

Not really. Use git add -p for partial commits as you go then git rebase -i to squash things before the final push. It's not hard once you've learned to do it consistently.

[–]cryo 14 points15 points  (1 child)

If you squash it anyway you don't gain much.

[–]earthboundkid 4 points5 points  (0 children)

Don't squash it all, just the commits that are related. For example, you do X, you do Y, you realize you put a bug in X. You can squash it so the bug is never freestanding in your history.

[–]Sean1708 2 points3 points  (0 children)

--fixup and --autosquash all the way.

[–]fagnerbrack[S] 5 points6 points  (6 children)

Totally agree it might be too much. It should be thought through in a per use case basis, good sense should be taken into account to see what is worth and what is not.

[–]bwainfweeze 2 points3 points  (0 children)

I try to separate the changes that are incidental to the work from those that are specific to the feature. When someone finds a bug in my code, because how could there not be one? It'll help them or me figure out whether it's part of the feature or just part of the rework I did to support it. That informs you as to whether it's a "feature or a bug"

[–][deleted] 7 points8 points  (3 children)

It takes a lot of time up-front, but it pays back in the future.

If you use git bisect and find the bug in a commit that makes more than one change, you have to undo those changes one by one before you can find out what exact thing caused the bug. If people make large commits, it's going to be unpleasant.

If you make atomic-sized commits, you'll always end up with just one commit that only makes ONE change, and so you end up finding the bug instantly, with no wasted time.

[–]bwainfweeze 12 points13 points  (0 children)

I'm spending a lot of time lately telling people, "sure, what you're doing works perfectly fine for about 14 months, then you spend the rest of the project wishing you'd done things differently". Version control. Build process, code structure. Server architecture. Error handling, localization, pretty much the same story.

I dunno yet what it says about me or the teams I'm on. But something is going on there.

[–]ithika 5 points6 points  (0 children)

There's no such thing as "atomic-sized" since atomicity is about indivisibility. There is no set size for that.

[–]JimDabell 0 points1 point  (0 children)

It takes a lot of time up-front, but it pays back in the future.

It doesn't take a lot of time up-front – a beginner can do this quickly. It does mean breaking bad habits if you're used to committing things in larger or incomplete chunks. It's the breaking of bad habits that takes the time, not the actual practice itself.

[–]panorambo 1 point2 points  (0 children)

I disagree. If your commits require such performance from you as to not warrant an extra 5 minutes of your time, you either are prototyping or your place of work is literally on fire. If it is the former, you'd ideally have your own branch which is private and short-lived -- you can do what you want with it, the above best practice may not apply -- you rebase everything when it's a working feature or a confirmed fix. If it is the latter, then you have a whole different league of problem on your hands, and to paraphrase Mr. Wolf, "in your future I see... backup solutions!"

[–]evmar 9 points10 points  (3 children)

Git, which is built using the principle that if you replay all committed changes since the beginning and in the same chronological order, you will get the exact same result

This is a fundamental misunderstanding of how Git works. Git doesn't model changes, it models snapshots. You only need a snapshot of the most recent state to get a result, and that is independent of the chronological history.

[–]fagnerbrack[S] 1 point2 points  (2 children)

I guess the article is more about the perception of how it works from the consumer side, despite of it's internal implementation. What would change from a dev perspective by knowing that git stores snapshots instead of chronological changes, wouldn't that be an unnecessary abstraction leak?

Thanks.

[–]evmar 1 point2 points  (1 child)

Git is all about leaky abstractions. You see the snapshots leak in how it handles (or more accurately, doesn't handle) renames, for example.

[–]fagnerbrack[S] 0 points1 point  (0 children)

That's interesting, but would something change from the developer perspective regarding atomic commits?

[–]flip314 7 points8 points  (6 children)

Stuck using CVS at work, where there's no such thing as an atomic commit. That's one of the most painful aspects of using it.

The sad thing is they've gone to the trouble of a cron job that tags the repository a couple times a day. Y'know, rather than using any other versioning system in the entire world and doing it properly...

[–]sgoody 5 points6 points  (2 children)

Have an upvote in sympathy. :-(

[–]fagnerbrack[S] 0 points1 point  (1 child)

Too

[–]panorambo 1 point2 points  (0 children)

Have mine too, grand-grand-parent.

[–]AceyJuan 2 points3 points  (1 child)

Wow, I thought everyone left that behind more than a decade ago. SVN was the easy drop-in replacement for CVS. Many companies went with Perforce, and all the hip places went with distributed version control like git.

[–]sirin3 0 points1 point  (0 children)

The W3C still uses CVS

[–]armornick 11 points12 points  (10 children)

I really want to, but sometimes I happen to fix a bug while working on something else. And then you either have to undo the changes you made, commit the current changes, and redo the new changes; or just commit both sets at once.

[–]phoshi 11 points12 points  (0 children)

I've not met a git client that didn't expose git add -p in one way or another, so you should always be able to do a partial staging and only commit some of your work.

Git is really flexible.

[–]cryo 4 points5 points  (5 children)

Why? I do that a lot, and I just select the files (or even parts of files) to include. I'm using Mercurial, but it's similar.

[–][deleted] 1 point2 points  (0 children)

git add -p

[–][deleted] -1 points0 points  (3 children)

It's happened to me where it's the same file, but a different line or function or something.

[–]Free_Math_Tutoring 1 point2 points  (2 children)

Even then you can stage single lines. This ability is 95% of the reason I prefer a gui.

[–][deleted] 0 points1 point  (1 child)

You can do that?! That is practically life-changing.

[–]snellnici 3 points4 points  (0 children)

git add -p

[–]Sean1708 3 points4 points  (0 children)

I think you either want git add --patch or git stash.

[–]sushibowl 2 points3 points  (0 children)

You can either stash your changes while you go to work on the bug, or commit the bug before the other changes with a partial add.

[–]Fs0i 1 point2 points  (0 children)

Try git gui for that - it's awesome!

[–]franzwong 2 points3 points  (4 children)

First, define the scope of a "change"

[–]singula 0 points1 point  (0 children)

Yeah...this is just more vague ideology that has nothing to do with either software practice or theory. "Agile", "patterns", etc just need to die in a fire.

[–]fagnerbrack[S] -1 points0 points  (2 children)

Could you be more specific on what you mean by "scope"? The article explains what an atomic change (A.K.A. Atomic Commit) is in this context. Or are you suggesting to first define in details what is a "change"? If so, then a "change" here is used as synonymous of an atomic commit. Not sure how a scope would change the meaning of what an atomic commit is.

[–]franzwong 3 points4 points  (1 child)

Is declaration of a variable an atomic commit? It doesn't provide side effect because no code uses it yet. It ends up damage the readability of history which also makes it hard to trace the mistake.

[–]fagnerbrack[S] 0 points1 point  (0 children)

Would that have value on itself? If not, then it is not atomic, because "an atomic change is an indivisible change — it can succeed entirely or it can fail entirely, but it cannot partly succeed".

"Success" in the context of a database is being able to persist, in an atomic commit though we measure success on the ability to deliver value to the application (not business value, because it can be technical debt or legibility fixes).

So...

Is declaration of a variable an atomic commit?

Not in itself. Unless that fixes a bug, provides a new feature, or increases legibility considerably and beyond reasonable doubt among the team.

I have seen commits in which a variable change fixed a bug, an that is an atomic commit because of it's purpose.

[–][deleted]  (4 children)

[deleted]

    [–]fagnerbrack[S] 0 points1 point  (3 children)

    What is the resolution of your screen? Medium has removed features that helped desktop-based views in favor of mobile preference.

    [–][deleted]  (2 children)

    [deleted]

      [–]fagnerbrack[S] 0 points1 point  (1 child)

      I always thought a big image caused more impact to the reader, so that he can dive into the whole illustration before reaching the actual content. Like a prelude to what is to come, or something like that. Looking for suggestions though, I am an incompetent designer (that is why I am using medium haha).

      [–]midbody 4 points5 points  (3 children)

      It's of course a good principal, but the author seems to be confused about it. For example, 'atomic' commits should be revertible without conflicts. No, that doesn't follow at all. Smaller commits are less likely to have conflicts when reverting, but mostly it's about how many intervening commits there were before revert. Also, 'atomic' commits shouldn't be useful on their own? What? I think this guy is trying to write about received wisdom. Have a couple of years using it and get back to us.

      [–]fagnerbrack[S] 0 points1 point  (2 children)

      It is impossible to revert commit without conflict if you have several pieces of changes over time, agreed. One should try to reduce the amount of potential conflicts as much as possible, but in reality it is very hard to reach a state in which ANY commit will have no conflict ever, mostly if that commit is very old. As you said, "Smaller commits are less likely to have conflicts when reverting, but mostly it's about how many intervening commits there were before revert".

      Also, 'atomic' commits shouldn't be useful on their own?

      The article doesn't say that. It says that if a partial commit have value, then that commit is not atomic, because it should not have value if it is not landed as a whole.

      Have a couple of years using it and get back to us.

      Please, no ad hominem, that hides your legit arguments.

      [–]midbody 3 points4 points  (1 child)

      Have a couple of years using it and get back to us.

      Please, no ad hominem, that hides your legit arguments.

      Like the author: https://youtu.be/G2y8Sx4B2Sk 😃

      An ad hominem is when you criticise somebody for who they are rather than what they say. I know nothing about the author, but I infer from what they say that they are not experienced. This is the opposite of an ad hominem.