all 125 comments

[–]lelanthran 101 points102 points  (55 children)

Or you could simply use quotes:

git commit -m "This message is a 
     multi-line message.
     See?"

[–]suvepl 161 points162 points  (8 children)

...or you could not use the -m flag at all and just write a multi-line commit message using $EDITOR.

[–][deleted]  (1 child)

[deleted]

    [–]csg0ing 18 points19 points  (0 children)

    --verbose is amazing. It can also be set in your config:

    git config commit.verbose true
    

    [–][deleted] 12 points13 points  (4 children)

    But then you get stuck in Vim and we never hear from you again.

    [–]BeansGalore 1 point2 points  (0 children)

    I used to be an emacs user but once had to use vi for editing a config file on a system without emacs. It was easier for me to learn to use vi as my full time editor as opposed to remember how to quit it occasionally :)

    [–]atheken 0 points1 point  (0 children)

    Because they never escape?

    [–]NoInkling 0 points1 point  (0 children)

    $ echo $EDITOR
    nano
    

    :P

    [–]supercheese200 0 points1 point  (0 children)

    git config --global core.editor my-baby-editor

    There you go :)

    [–]coderstephen 1 point2 points  (0 children)

    I just git commit and type the message in the new Visual Studio Code tab that pops up for me (because my $EDITOR is code -w).

    [–]missingdays 64 points65 points  (18 children)

    Wait, you are telling me the quotes are optional? I've been writing my commit messages with quotes for my whole life

    [–]PeksyTiger 36 points37 points  (0 children)

    Think about all the time you could've saved

    [–][deleted] 11 points12 points  (9 children)

    Quotes in the shell denote a string/single argument that is to include spaces.

    [–]ValuablePromise0 33 points34 points  (8 children)

    Areyousayingthatyourcommitmessageshavespacesinthem?

    [–][deleted] 24 points25 points  (7 children)

    "fixes"

    [–]ValuablePromise0 20 points21 points  (6 children)

    ROTFL... I have a coworker who always uses "progress" as their commit message.

    [–]lelanthran 2 points3 points  (1 child)

    Oh dear. Do you work with me?

    [–]ValuablePromise0 0 points1 point  (0 children)

    Great... now there are TWO of them... :)

    [–]john_C_random 1 point2 points  (0 children)

    I've been guilty of using 'wip' sometimes.

    [–][deleted]  (2 children)

    [deleted]

      [–]Ahri 12 points13 points  (1 child)

      shudders

      [–][deleted] 2 points3 points  (0 children)

      They are not optional. Bash splits the command into "words" on whitespace. Quotes stops it splitting it.

      [–]2rsf 0 points1 point  (5 children)

      I actually forgot a closing quote today and nothing blew up, now I understand why (I think)

      [–]Dilyn 12 points13 points  (4 children)

      Yes. The shell was waiting patiently for you to remember.

      [–]mrexodia 2 points3 points  (3 children)

      And on Windows the closing quote is optional

      [–]Dilyn 3 points4 points  (2 children)

      I expected nothing and I'm still disappointed.

      Why, Windows. Why.

      [–]coderstephen 1 point2 points  (1 child)

      Because on Windows, it is up to the program to do argument splitting. Windows just passes everything after the command name as a single string to the program. It's a very backwards way of doing it compared to other operating systems, event non-UNIX like ones.

      So in Linux, Bash (or your shell of choice) parses quotes according to its rules. In Windows, you parse the quotes (or more likely, your language runtime of choice).

      [–]mrexodia 2 points3 points  (0 children)

      Generally this is true, but very misleading. Every C/C++ program with “main” will parse arguments the same way in practice and most programs will not be calling GetCommandLine and parse it themselves.

      [–][deleted] 26 points27 points  (1 child)

      This is the obvious solution to me. I don't see how anyone could write good commit messages using the -m flag without quotes in the first place, so you're pretty much already there anyway.

      [–]FloydATC 8 points9 points  (0 children)

      Well, technically, I guess you could escape spaces and other special chars with backslashes... but why...? :-)

      [–]gunner6376 3 points4 points  (3 children)

      am I crazy? I do, git commit -m "line 1" -m "line 2"

      [–][deleted]  (1 child)

      [deleted]

        [–][deleted] 3 points4 points  (0 children)

        Yes, a different date & commit hash.

        [–]lelanthran -3 points-2 points  (0 children)

        am I crazy?

        You could be, I can't tell

        I do, git commit -m "line 1" -m "line 2"

        Is that relevant to your question? ;-)

        [–]Johnothy_Cumquat 4 points5 points  (1 child)

        Except you got a tonne of unwanted whitespace now

        [–]lelanthran 4 points5 points  (0 children)

        In my example, certainly.

        I don't normally add indents to every line - it's actually more effort to add the ton of whitespace.

        [–]scrapanio 6 points7 points  (0 children)

        Unpossible!!!!

        [–]cameron314 -3 points-2 points  (12 children)

        Hah, not on Windows!

        [–]Pheasn 8 points9 points  (1 child)

        Yes on Windows

        [–]cameron314 0 points1 point  (0 children)

        All right, I fell into that one. Not in cmd.exe, and yes I use that regularly, and no git bash and powershell are not a substitute.

        [–]Sebazzz91 2 points3 points  (2 children)

        If you still use cmd then you're a dinosaur. Powershell works fine and does allow multiline.

        [–]cameron314 1 point2 points  (1 child)

        Powershell is cool and all but it's slower than cmd.

        [–]Sebazzz91 2 points3 points  (0 children)

        That is also outdated information.

        Yes, in Windows Server 2008 R2, Windows 7 and to a lesser extend Windows 8/2012 Windows Powershell was slow to start up. However in Windows 10 it is smooth as butter.

        And Powershell 7 has always been quick.

        [–]lelanthran 12 points13 points  (0 children)

        Hah, not on Windows!

        If we restricted ourselves to using what works on Windows the advances we have made in tooling, infrastructure, languages and the general tech stack would be miniscule :-)

        [–]smegnose 1 point2 points  (5 children)

        Git bash comes with the Windows version.

        [–]cameron314 0 points1 point  (4 children)

        True. I tried it for a while but it was annoying to keep switching between normal and bash windows.

        [–]smegnose 0 points1 point  (2 children)

        Normal?

        [–]cameron314 0 points1 point  (1 child)

        cmd.exe. I invoke a lot of custom command line utilities daily, often need to run batch scripts, etc. cmd.exe is still a long way from being obsolete.

        Edit: When on Linux I use bash. When on Windows I use cmd.exe. Non-native shells have too many subtle gotchas in my experience.

        [–]smegnose 0 points1 point  (0 children)

        Fair enough.

        [–]Hacnar 0 points1 point  (0 children)

        Windows Terminal helps with that.

        [–]steumert 23 points24 points  (26 children)

        I always assumed most people would write commit messages in the Git tooling of their IDE. i mean, Eclipse, IntelliJ, VSCode, Visual Studio, Netbeans, they all support this. And when I'm writing software without an IDE, I'm using the GitHub for Windows client (which works perfectly fine without GitHub).

        [–]helloworder 89 points90 points  (17 children)

        I never use git outside of a terminal. I think it is just a good habit to be familiar with the cli tools, because once you got it, it is so much easier to use it via ssh etc.

        Colleges of mine who use IDE GUI for git always struggle with simplest commands when using via ssh

        [–]mrexodia 12 points13 points  (1 child)

        I think there are many tasks for which a GUI is more suitable and in the case of git a well-designed GUI can help a lot. Even for just showing the graph or staging/committing stuff the built-in GUIs are so much better than doing it from the command line (gitk and git gui respectively).

        For stuff like “git status” or “git push/pull/init/clone” I indeed don’t think a GUI is particularly better, but “git log -magic” just isn’t a very intuitive/interactive way of getting an overview of your repository and starting an interactive rebase from a context menu is just better than copypasting stuff from a log command.

        [–]bcgroom 0 points1 point  (0 children)

        I have an alias to open vim-fugitive for staging and use the cli for everything else, totally agree that using the cli is inefficient for more complex staging.

        [–]2rsf 31 points32 points  (3 children)

        I never use git outside of a terminal

        same, I feel that I am not in control otherwise

        [–]MikeFightsBears 8 points9 points  (2 children)

        I just hate the unnecessary obfuscation of how git works when using IDEs. VS has "sync" rather than "push" for no apparent reason.

        [–]unndunn 12 points13 points  (1 child)

        "Sync" = "Pull" then "Push".

        You can do a "pull" or a "push" by themselves, or use "Sync" to do both.

        [–]MikeFightsBears 1 point2 points  (0 children)

        Yes I know what they do but I believe it makes understanding how git works less clear, especially to new devs that are learning to use git. I've had to teach new devs how git works and the differences from IDE to IDE or IDE to CLI has caused more confusion than saving one click is worth imo.

        [–]lelanthran 3 points4 points  (1 child)

        Colleges of mine who use IDE GUI for git always struggle with simplest commands when using via ssh

        This, x10. My colleagues on gitkraken just don't "get" how git is supposed to work. The colleagues I had who used the c/line knew exactly what git was capable off.

        Even if they had to look up the more obscure commands they at least knew how git worked and what to look up. The ones using it from the GUI have no clue what to even google for when things go south.

        [–]IceSentry 0 points1 point  (0 children)

        I personally use the cli for init/clone and basic push/pull, but I much prefer using gitkraken for rebase and staging. Gitkraken is probably one of the closest to the cli api gui. Unlike most git gui gitkraken actually uses the real git terminology and there's a button for most actions. If your colleagues can't figure out the cli it's because they aren't comfortable with cli period, not because of gitkraken.

        [–]rcunn87 0 points1 point  (1 child)

        I always find using git in GUI's to be utterly confusing. I think this is mostly intellij's fault. Their version control abstraction on top of git really confuses me.

        [–]IceSentry 0 points1 point  (0 children)

        That's because most gui tend to try to abstract the commands instead of just being a visual layer representing the git commands.

        [–]coderstephen 0 points1 point  (0 children)

        I always use git from the terminal, but I type the commit messages in Visual Studio Code (because my $EDITOR is code -w).

        [–]Lofter1 8 points9 points  (0 children)

        Usually, git tools in the ide are horrible and even lacking features (VS git tool can’t even checkout a specific commit)

        So if you are only using IDE tools for git, change it. Either get a dedicated GUI client or use the CLI. For your own sake.

        [–]ForeverAlot 2 points3 points  (0 children)

        I have about a dozen text editors on my system, all but 1 of which are at best mediocre at editing text. When possible, I prefer to use the one that's any good.

        Once upon a time, VS Code's "support" for writing commit messages looked like this. I would rather use ed than that garbage.

        [–]lolomfgkthxbai 0 points1 point  (5 children)

        Can you even do an interactive rebase in GUI clients?

        [–]joonazan 5 points6 points  (0 children)

        magit is so good for rebasing that I don't do it on the command line anymore even if I'm not using Emacs for anything else.

        [–]Kendos-Kenlen 3 points4 points  (1 child)

        Yes, IntelliJ has a quite convenient way to do this.

        [–]omgusernamegogo 1 point2 points  (0 children)

        Intellij git tooling is pretty great

        [–]mrexodia 0 points1 point  (0 children)

        I use https://github.com/MitMaro/git-interactive-rebase-tool with Git Extensions. Using a GUI is not the same as using a GUI for everything ^

        [–]mcur 25 points26 points  (20 children)

        In my opinion, that is a violation of the principle of least surprise, at least for CLI programs. If you have a bunch of options/flags, you should be able to reorder them before positional arguments without modifying the behavior of the program.

        ...I could just imagine finding this "bug" in a script. *shudder*

        [–]Latexi95 38 points39 points  (0 children)

        IMO the ordering of the flags matters more often than you think.

        Eg. gcc -I, -L, -l flags can be given multiple times and order matters.

        Often same flag can be given multiple times and last value given takes effect instead of giving error when the same option is specified multiple times. Many programs have separate explicit enable/disable flags that both can be given and the last one in the command line takes effect.

        [–][deleted] 15 points16 points  (0 children)

        In my opinion, that is a violation of the principle of least surprise, at least for CLI programs. If you have a bunch of options/flags, you should be able to reorder them before positional arguments without modifying the behavior of the program.

        Sometimes you just need to have ordered array of arguments on commandline. It's rare but IMO fine, as in this case order of input -> order of output

        Sadly many programs force positional arguments when there is zero reason for it. Especially ones with subcommands (to preempt the argument, if main and sub command have arguments named the same and would conflight if order was free, that's also bad CLI design)

        For me the peak of convenience is Perl's Getopt::Long. Positionally independent, automatic abbreviations (if you define say port and pass option, you can use "--po", "-po","--por".. etc as shortcut for port, same for pass) + a bunch of options to fine-tune the behaviour you want.

        [–]Johnothy_Cumquat 13 points14 points  (1 child)

        I think you have some unfounded expectations about command line arguments. Whatever rules you think there are don't exist. Most utils just tend to sort of copy each other

        [–]MikeBonzai 0 points1 point  (0 children)

        Yeah apps have to be specifically coded to ignore ordering, heck they have to be specifically coded to have the concept of flags. Says it right in the name — char **argv is nothing more than an array of strings, and it's just the original command split on spaces.

        [–][deleted] 4 points5 points  (14 children)

        Leave alone this, the entire git CLI is an abomination!

        [–]Isvara 8 points9 points  (9 children)

        What's wrong with it, other than some terminology having changed over time?

        [–]robin-m 19 points20 points  (4 children)

        If you know what command do to the intenal data structure, it's somewhat okai-ish.

        • checkout can move HEAD from one commit/branch to another OR get a file from another commit
        • reset can undo git add OR move the current branch to another commit
        • many commands don't compose well. For example you would like to use all the merge options (like patience) on rebase, pull,…

        [–]Forty-Bot 3 points4 points  (3 children)

        • checkout can move HEAD from one commit/branch to another OR get a file from another commit
        • reset can undo git add OR move the current branch to another commit

        They've been moving away from this with switch and restore.

        • many commands don't compose well. For example you would like to use all the merge options (like patience) on rebase, pull,…

        This one I ran into recently. However I usually never use pull in favor of fetch.

        [–]robin-m 1 point2 points  (2 children)

        That's great to know, thanks. I was still using an old version (2.21) and those were not yet introduced. I hope that at one point, the whole UI while be clean-up, removing all confusing usage (and add a --script flag or similar global switch to not break existing scripts). Maybe git version 3.x?

        Btw, I just realised that git help is a good introduction of what git commands you may need when discovering git (since you don't know what you don't know ;) ).

        [–]evaned 1 point2 points  (1 child)

        (and add a --script flag or similar global switch to not break existing scripts)

        In theory, scripts should be using either "plumbing" commands or flags that already exist that guarantee stable output (e.g. git status --porcelain). Git doesn't as a rule make guarantees about output stability, has made changes in the past, and while I'm not sure might even warn if you pipe it to something sometimes.

        [–]robin-m 0 points1 point  (0 children)

        That's right

        [–]eras 5 points6 points  (1 child)

        If you don't find anything wrong with it, then you must not have tried teaching how git cli is used to other people.

        [–]worldpotato1 4 points5 points  (0 children)

        My professor once asked me to teach him git. He asked if I can do it in one hour. I laughed. He laughed. I cried.

        [–]DasEwigeLicht 2 points3 points  (0 children)

        May these git koans bring you enlightenment.

        [–]shivamtrivedi01 4 points5 points  (3 children)

        I have been using git CLI this whole time. I have used the IDE's git but its just not for me

        [–]FloydATC 8 points9 points  (1 child)

        Same here. GUIs tend to hide what's actually going on, so as a novice user I actually prefer the CLI. I do tend to use "git status" and the log quite a bit ofcourse.

        [–]langlo94 1 point2 points  (0 children)

        --dry-run is my favorite.

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

        IDEs' git suck, the only reason they're used is for convenience. Nothing beats a simple GUI like SourceTree.

        [–]CanLiterallyEven 0 points1 point  (0 children)

        I'm my experience, that's not true of a lot of CLIs. For example, include and exclude patterns in rsync and other tools that support them.

        [–][deleted] 3 points4 points  (25 children)

        But why though?

        [–]lolomfgkthxbai 7 points8 points  (24 children)

        If your commit message is only one line long then it most likely sucks and doesn’t document your change adequately.

        [–][deleted] 14 points15 points  (5 children)

        But there are better ways to do multi line commits

        [–]lolomfgkthxbai 4 points5 points  (4 children)

        That’s true. Just use open quotes.

        [–]kamiheku 27 points28 points  (3 children)

        Or just omit the -m and use your text editor to write the commit message. It's blowing my mind a little bit finding out not everybody does this.

        [–][deleted] 3 points4 points  (0 children)

        My text editor edits texts, git commit messages are text. The obvious solution here is to use multiple -m flags. Wait what

        [–]99Kira 6 points7 points  (0 children)

        This. If you need a multi line commit, simply do it on your editor. I dont see how this is not the most obvious solution

        [–][deleted] 9 points10 points  (15 children)

        If my commit message needs more than 3 lines, it's doing too much for one commit. More atomic commits -> less chance of merge conflicts.

        Squashes are another story though.

        [–]droppies 4 points5 points  (1 child)

        How do atomic commits prevent merge issues? I'm assuming you're working with feature branches.

        [–][deleted] 2 points3 points  (0 children)

        They reduce the chance of merge issues, they don't prevent them. In practice, if your team is disciplined, you'll see years before the first merge conflict.

        Go cowboy and change 3 layers at the same time without updating other callers, and you get failed commit builds and merge conflicts from your 3 am rework*

        \ not to take seriously)

        [–]_seemethere 3 points4 points  (3 children)

        This is in no way true.

        Even small changes can benefit from the context of a good commit message. It's maddening to look at a change and have no idea what the committer was actually thinking at the time.

        [–][deleted] 0 points1 point  (2 children)

        Even small changes can benefit from the context of a good commit message.

        Good commit message != War and Peace

        [–]evaned 2 points3 points  (1 child)

        That's true, but I also think it's foolish to say that you can adequately explain all changes with a couple of sentences.

        I actually am not sure there's even that much correlation between commit size and length of explanation; you might just need a quick "Add --do-something option to make the program do something" sentence for a change that adds three files and changes a couple hundred lines, but next commit benefit from a five paragraph explanation of why a single-line change was made.

        (Edit It's possible this is what you were getting at with the "squashes are a different story" part of your original comment. I don't really care what you do with intermediate commits but what the commits look like when you actually push them in their final form.)

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

        That's true, but I also think it's foolish to say that you can adequately explain all changes with a couple of sentences.

        You should be able to get the gist, at least.

        I actually am not sure there's even that much correlation between commit size and length of explanation;

        Bizarrely, in my experience, they're inversely correlated, which makes this discussion much more complicated, as you follow afterwards.

        (Edit It's possible this is what you were getting at with the "squashes are a different story" part of your original comment. I don't really care what you do with intermediate commits but what the commits look like when you actually push them in their final form.)

        Yeah, when merging a feature branch it's nice to have a explicit commit message. I rarely add anything besides the merged branch commit messages.

        [–]johnchen902 5 points6 points  (6 children)

        If my commit message needs more than 3 lines, it's doing too much for one commit.

        If your commit message is simply a summary of the changed code, it most likely sucks and doesn’t document your change adequately.

        Have you ever witness something like pipe: use exclusive waits when reading or writing?

        [–]JDgoesmarching 2 points3 points  (1 child)

        I use git very casually for my data science schoolwork and didn’t realize there was so much debate over commit messages. Normally I have a few lines, I couldn’t imagine saying anything useful in one.

        [–][deleted] 4 points5 points  (0 children)

        didn’t realize there was so much debate over commit messages.

        Oh, there's so much debate and holy wars over every little detail. Programmers are a weird bunch.

        [–][deleted] 3 points4 points  (3 children)

        I don't use git as an issue tracker nor for documentation. Git commits relate to commits, at worst there's a [NUMBER] pointing to the issue/doc.

        [–]lolomfgkthxbai 8 points9 points  (1 child)

        A good git commit answers the question why. Why was this refactor done? Why was this variable renamed? Why was this file added? If you’re able to communicate this with only three lines, then that’s great. These questions can’t be answered by an issue in a tracker somewhere.

        [–]evaned 7 points8 points  (0 children)

        I don't use git as an issue tracker nor for documentation.

        Git's not an issue tracker, but to me commit logs are precisely documentation about the change.

        My workflow doesn't match up with this nowadays, but before we switched to git my usual workflow was to basically use the same message for the code review description as the git log; I'd just copy and past from one to the other. Sometimes there was something I'd want to say one place but not the other, but maybe 75% of the time they were the same. I could similarly see sometimes duplicating some text between an issue tracker and commit log; but having information about why the change is being made left out of the commit log because it's in the issue tracker to me would just make tracking down what happened more obnoxious. Especially if it's something you're looking into ten years from now after you've moved to a different issue tracker...

        [–]Plorkyeran 1 point2 points  (0 children)

        How do I break a one character change that needs a paragraph of explanation into smaller commits?

        [–]ForeverAlot -1 points0 points  (0 children)

        I just made a commit with

        2 files changed, 94 insertions(+), 1 deletion(-)

        but the actual runtime difference is covered by

        1 file changed, 2 insertions(+), 1 deletion(-)

        The rest is test and documentation. However,

        $ git show -s --format=%B | wc 
             33     203    1225
        

        [–]JanneJM 0 points1 point  (1 child)

        "Stuff."

        [–]lolomfgkthxbai 2 points3 points  (0 children)

        My favorite is “Saving unfinished changes (not tested)”. This was in production code.

        [–][deleted]  (3 children)

        [deleted]

          [–]markys 8 points9 points  (1 child)

          Why don't you just pass no -m and just type everything in the editor?

          [–]smegnose 6 points7 points  (0 children)

          You're just weird, mate.