1. 24
  1.  

  2. 7

    Our workflows sound identical. A few things I’ve started doing recently:

    1. 7

      git commit --amend is pretty handy to edit the last commit

      1. 1

        I’ve got a similar alias to fix mistakes in the last commit using the same commit message:

        fixup = commit --amend -C HEAD
        
        1. 2

          In Mercurial, this is just hg amend or hg am (all Mercurial commands can be abbreviated to their shortest unique prefix). If you do want to edit the commit message, it’s hg amend --edit.

      2. 2

        I recently fell in love with the committing style used by one of my favorite technologists, Pieter Hintjens. The first line starts with Problem: and is used to summarize the business or user facing problem fixed by the commit. The third line (you need that blank second line, of course) is 72 characters wide, and starts with Solution:, and expands on the solution. You need that context, because the first line has nothing to do with what you did, just the problem you see. And, of course, once you are writing something unconstrained by a character limit, you are likely to keep writing.

        One downside seen by my colleagues is the way this encourages large commits for refactoring or large changes to fix problems. I’d argue that the business case needs to be there to fix such problems, at which point you will have a large commit in any system.

        A talk by Pieter Hintjens discussing the idea, just one of many, can be found at https://youtube.com/watch?v=uzxcILudFWM , about ten minutes in he gets to this committing format.

        1. 1

          Great article! As a user of sway, I’ve been aware of drew’s work for a while now. I like his classic approach to reducing complexity and those were some good tips.

          I have a shortcut script which I use (I got it a long time ago) called soft_rebase. The scenario it solves is for when I’m working in a branch and I intend to roll it up into a single commit at the end when I make a pull-request. What it does is reset the working tree changes against the master branch, compile all the commit messages that I had put in the branch until that point into a file, and re-commit it as a single commit and open the editor to modify the commit messages. The functions I use are fish functions, but you can easily adapt it to sh:

          # Defined in /home/ashkan/.config/fish/functions/soft_rebase.fish @ line 2
          function soft_rebase
            set FILE (mktemp '.COMMITMSG.XXXXX')
            set MERGE_BASE (git merge-base origin/master (git_branch_name))
            get_commit_messages $MERGE_BASE..HEAD > $FILE
            git reset --soft $MERGE_BASE
            git commit -v -e -F $FILE
            rm $FILE
          end
          
          # Defined in /home/ashkan/.config/fish/functions/get_commit_messages.fish @ line 2
          function get_commit_messages --argument RANGE
          	git log --reverse --pretty=format:%B $RANGE
          end
          
          1. 0

            Each commit should be a self-contained change

            Couldn’t agree more! For anyone curious to learn about this in more detail, this practice is often called ‘microcommitting’ and there are many articles on the topic.

            1. 5

              Microcommitting is basically the polar opposite of what I’m advocating for in this article.

              1. 1

                I think I have a different (and possibly erroneous) understanding of what microcommitting is then, because my definition is pretty much exactly what you said in that paragraph. I also don’t understand how even the most extreme definition of “microcommitting” can be the polar opposite.

                To me microcommitting is making self-contained commits that are as small as possible but no smaller, with heavy emphasis on that last part.

                1. 1

                  Microcommitting in the view of the broader internet seems to be going so far as to set up a cronjob that does git add -A && git commit -mbullshit every 5 minutes, which is pretty much the opposite of committing with discipline.

                  Note that my approach doesn’t always mean small commits - sometimes commits written with this approach are relatively large due to the difficulty of splitting it into smaller pieces.

                  1. 3

                    Microcommitting in the view of the broader internet seems to be going so far as to set up a cronjob that does git add -A && git commit -mbullshit every 5 minutes, which is pretty much the opposite of committing with discipline.

                    This is a practice that doesn’t even deserve a label to describe it, but if I had to choose, would use “folly”. I honestly had no idea the term was sometimes used to describe this type of workflow (maybe it’s more popular in webdev circles? If so might explain why I haven’t come across this usage).

                    As an aside, it’s fascinating to me how people can interpret terms differently. If microcommit really means what you said above, I wonder what the best word for this approach is. Disciplined committing seems like it could also be interpreted a myriad of ways.

                    Note that my approach doesn’t always mean small commits - sometimes commits written with this approach are relatively large due to the difficulty of splitting it into smaller pieces.

                    Yes, this is my understanding as well. Your commits shouldn’t be small just for the sake of it, and should make sense on their own first and foremost. Reading down the thread here, I tend to side with @JordiGH in preferring changes to be split out for reviewability (as long as the split out changes are still sensible in their own right). I’ll admit that determining “sensible” is as much art as science.

                    1. 1

                      I find it difficult to find commits that are too large yet impossible to split up. I can usually find a way to split them up. Exceptions are stuff like running a linter on the entire codebase, although I have seen people prefer to split that up into one commit per file linted, which I’m not sure I agree with.

                      The boundary I try to find is, how much of this change is it possible to reject while still accepting the rest? One of the big (historical?) advantages of atomic commits was to allow partial rejection of a change while still allowing the rest to progress, without breaking anything.

                      I find it’s easier to get stuff through code review if it’s possible to concede points on some rejected portions while getting the important stuff approved.

                      1. 1

                        Consider “Add support for XYZ”. You could split this up into:

                        • Prepare module A for XYZ support
                        • Refactor module B for X support
                        • Add YZ types to data structure C
                        • Update module D to consider XYZ

                        But honestly I’d rather just see “Add support for XYZ”.

                        1. 2

                          And yeah, I’d prefer to see those four commits, because I find that easier to review.

                          Is this correctly preparing the module? Yep. Easy, approve. Go on.

                          Do I like the refactored module? Wait, no, that should be done differently. Let’s do this later.

                          Add types? Sure, that seems fine. Let it through.

                          Update the other module? Sure, this one is fine, the change is easier than a refactor.

                          If a commit makes sense on its own and it’s better than not having the commit, however small that improvement may be, it’s helpful to have it on its own.

                          1. 1

                            Some degree of discretion is of course necessary here for bigger changes, but I suppose we’ll have to agree to disagree on where to draw the line.

                            1. 1

                              FWIW, I agree with JordiGH - I’d prefer to see these as separate commits too.

                2. 2

                  The handful of articles I just read about ‘microcommitting’ seem to indicate that it’s just ‘saving whatever you have at very frequent intervals’ and less about ‘committing self-contained changes’. I highly doubt that anyone could crank out self-contained changes at intervals of 1-5min (or even less) for prolonged periods that ‘microcommitting’ preaches.

                  1. 1

                    It’s possible I’ve been misusing the term microcommitting then. My definition is making self contained changes that are as small as possible but no smaller. Each commit needs to be self-contained, pass tests, etc, but should tell a larger story alongside the other commits in the series.

                3. -1

                  This is an interesting article, and possibly quite useful to the people living in the alternative universe where not everything happens via a GitHub PR.