1. 17

  2. 13

    I use the Fish shell’s abbr (abbreviation) feature for my typing-saving Git aliases. Because Fish replaces the abbreviation with the full command before the command is logged and run, I can more easily spot when I ran certain Git commands when I browse my shell session or search through my command history.

    For example, after defining this abbreviation:

    abbr --add gitst "git status"

    I can type gitst in my prompt:

    $ gitst

    But after pressing Enter, my session looks like this:

    $ git status
    nothing to commit, working tree clean

    Then, if I leave my shell and go back to it later, I can see that I just ran git status. I don’t have to remember what gitst stands for.

    Along the same lines, I can see the long form of flags in my history while spending as much time typing as if I had written their short forms. My gitspu abbreviation expands to git stash push --include-untracked, which is easier to read than git stash push -u.

    1. 10

      I just use magit.

      1. 7

        Surprised noone has mentioned aliasing git push --force-with-lease yet (shame this wasn’t the original default implementation of --force). (Explanation)

           pforce = "push --force-with-lease"

        or pf if you really hate typing.

        (But +1 for using magit and rarely needing to run git commit line commands!)

        1. 1

          I’ve never been sold on the idea of --force-with-lease being the “one true way” or a “correct” default. It seems to just trade-off between fetch vs push -f being ‘safe’. There are scenarios where that trade-off might be a good one to make, but it’s still a judgement call. At least to me, from a logical perspective it seems a more intuitive and consistent default that push would be the ‘unsafe’ operation rather than fetch.

          And just in general I feel like encouraging forced pushes to shared branches is not how I would choose to balance things. It might sometimes be necessary, but I’m perfectly ok if it’s a bit awkward and requires some careful thought.

          1. 4

            Agree that pushing to shared branches is still to be avoided.

            However force-pushing to private branches is something people regularly do if their workflow involves any rebasing, so having the default be a behavior that fails if the branch has somehow become “not private”, rather than just overwriting whatever was there with no obvious sign it wasn’t what was expected, gives some comfort and avoids insidious problems.

            Same if you accidentally go to push to a shared branch (or someone else’s feature branch) without knowing it. Failing is preferable to quietly removing commits.

            In a perfect world where noone makes any mistakes, –force and force-with-lease would be 100% equivalent as the latter would never have a reason to fail.

            Edit: Just realised what you mean about fetch: that with force-with-lease the danger becomes that you don’t notice the remote branch updated when you fetched, and then the force-with-lease succeeds anyhow. Is that right? This is a good point, although I still think some footgun protection beats no footgun protection.

        2. 3

          My favorite yet cursed alias:

          git config alias.save "commit --no-edit --allow-empty-message"

          I say commit early, commit often, and then squash / rebase when you’re going to push something publicly.

          I’ve broken tools that parse git log this way, though.

          1. 3

            I have “git ff” for “git merge --ff-only”. And “git lol” for “git log --format=oneline”.

            1. 2

              I have a ton, broken broadly into shortcuts and flow.

              My most used shortcuts are

              amend = commit --amend --no-edit
              s = status
              co = checkout
              cof = checkout -f
              cm = commit -m
              a = add
              staged = diff --staged
              poh = push origin HEAD
              sync = "!f(){ git stash && git pull && git stash pop; }; f"

              On the flow side, basically we have a dev branch which each developer creates feature branches off (with a naming convention of <initials>/<feature name>). I have these helpers:

              dev = "!f(){ git co us/dev/$1; }; f"
              devs = branch --list /dev/*
              rmdev = "!f(){ git branch -D us/dev/$1; }; f"
              rmdevs = "!f(){ git branch -D `git branch --list 'us/dev/*'`; }; f"
              mkdev = "!f(){ git fetch origin dev:dev && git branch us/dev/$1 dev && git co us/dev/$1; }; f"
              mgdev = "!f(){ git fetch origin dev:dev && git merge dev; }; f"

              Sometimes I’m on a machine without my usual .gitconfig and I wonder if I’ve done the right thing muscle-memorizing all my own nonsense :)

              1. 1

                Instead of sync you can just use git config --global rebase.autostash true and the result will be similar.

                1. 1

                  I only use sync in specific circumstances (between local clones on the same branch), so I don’t want it to be the default. But that’s cool to know.

              2. 2

                I use similar ones. A few more suggestions I use regularly:

                conflict = !"$EDITOR" -c '/^[<=|>]\\{7\\}' `git ls-files --unmerged | cut -c 51- | uniq`
                praise = blame
                branches = for-each-ref --sort=-committerdate refs/heads/ --format='%(authordate:short) %(color:red)%(objectname:short) %(color:yellow)%(refname:short)%(color:reset) (%(color:green)%(committerdate:relative)%(color:reset))'
                remotebranches = for-each-ref --sort=-committerdate refs/remotes/ --format='%(authordate:short) %(color:red)%(objectname:short) %(color:yellow)%(refname:short)%(color:reset) (%(color:green)%(committerdate:relative)%(color:reset))'
                1. 2

                  I like these threads, I always learn a new trick. :)

                  Here’s mine:

                    br = branch -vv --sort=-committerdate
                    co = checkout
                    dc = diff --cached
                    ff = pull --ff-only
                    fixup = commit --amend --no-edit
                    lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
                    st = status --short --branch
                    wd = diff --word-diff
                  1. 2

                    Nice, I also have “g s” and “g l”.

                    I can also recommend the meta process: Once in a while look at the statistics of your shell history to see which commands you enter most often. Create shortcuts for those.

                    # most used commands
                    cat $HISTORYFILE | cut -d ' ' -f 2- | sort | uniq -c | sort -n | tail -n 32
                    # most used first words in commands
                    cat $HISTORYFILE | cut -d ' ' -f 2 | sort | uniq -c | sort -n | tail -n 32

                    The output for me currently is:

                    171 cd
                    197 g diff
                    205 g l
                    208 g st
                    542 ls

                    I do have a shortcut “l” for “ls” but somehow I don’t use it.

                     373 m
                     608 v
                     631 apt
                     747 cd
                     829 ls
                    1464 g

                    Interesting, I’m running apt more often than vim these days?

                    1. 2

                      I use three, but of those three, only one is worth mentioning:

                      psuh = push
                      1. 4

                        Interesting option:

                        autoCorrect = 10            # Run guessed command after 1s if there's only one guess.
                        $ git psuh
                        WARNING: You called a Git command named 'psuh', which does not exist.
                        Continuing in 1.0 seconds, assuming that you meant 'push'.
                        Everything up-to-date
                        1. 1

                          why not:

                          p = push

                          Then you 1) cannot misspell it and 2) save 3 key strokes!

                        2. 1

                          I try to use even shorter aliases through my shell, here are mine: https://github.com/timvisee/dotfiles/blob/master/bash/bash_aliases#L66-L81

                          1. 1


                            	ai = add -i
                            	b = branch
                            	ca = commit --amend
                            	ci = commit
                            	co = checkout
                            	cob = checkout -b
                            	lg = log --color --graph --oneline --abbrev-commit
                            	pr = pull-request
                            	rci = commit --amend --reuse-message HEAD
                            	squash = rebase -i @{u}
                            	st = status -sb
                            	todo = grep -Ee '\\bTODO:?\\b'
                            	fixme = grep -Ee '\\bFIX(ME)?:?\\b'
                            	com = checkout master
                            	ag = grep
                            	rg = grep
                            	ver = tag --sort=version:refname
                            	skip = update-index --skip-worktree
                            	unskip = update-index --no-skip-worktree
                            	publish = push -u hauleth
                            	cleanup = "!git branch --format='%(refname:lstrip=2)' --no-contains HEAD --no-contains master --merged master | xargs -xn1 git branch -d"
                            1. 1

                              I have a bunch of aliases, but nowadays I just use magit. The most useful ones I have that weren’t in the article are probably:

                                lol = log --graph --decorate --pretty=oneline --abbrev-commit
                                s = status --short
                                dc = diff --cached --diff-algorithm=minimal -w
                                dw = diff --word-diff
                                cm = commit -m
                                a = add
                                dd = "! git status --short | awk '$1 == \"D\" { print $2}' | xargs git rm --cached"
                              1. 1

                                Doesn’t it seem weird that there’s support for aliases in .gitconfig? I guess this is sort of the logical succession from things like the porcelain commands but it really seems like messy scope creep compared to people just making aliases themselves in their shells or whatnot.

                                The internals of git feel really clean, but the UI is really hard to deal with…

                                1. 1

                                  git already is two layered CLI UI-wise. see: porcelain

                                2. 1

                                  fish to turn every git alias into a shell alias:

                                  git config --list | perl -lne '/^alias[.]([^=]+)/ and $1 ne "alias" and print "alias $1=\"git\\ $1\""' | source


                                  eval "$(git config --list | perl -lne '/^alias[.]([^=]+)/ and $1 ne "alias" and print "alias $1=git\\ $1"')"

                                  My history just looks like this:

                                  vim app/controllers/syntax_highlighting_controller_methods.rb
                                  tx origin
                                  cb kiv-enable-darkship-globally

                                  It looks arcane but having git be so near at hand makes it very easy to move fast.

                                  1. 1

                                    Ok, so this isn’t that practically useful. 😢 But, let me reiterate what I said earlier: it makes you feel efficient, and maybe there’s some kind of placebo effect that actually makes you more productive.

                                    I’d say it’s more important than that. More characters is more cognitive overhead, it’s more places where you can typo and do the wrong command, and if you need to fix something, it’s more characters to erase.

                                    1. 1

                                      I use these:

                                          co = checkout
                                          st = status
                                          lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
                                          bn = symbolic-ref --short HEAD
                                          extend = commit --amend --no-edit
                                          reword = commit --amend
                                          rb = branch --sort=-committerdate