Not so long ago after I learned the ropes of Git, what got me curious was magic trick developers would do :slight_smile: to manage changes and commit history.

On top of basics [1] , what other Git commands/options [2] do you think you can level up with?

  • Basics such as Git checkout, branch, status, log, add, commit, push, pull, remote, fetch ↩︎

  • For example, tricks you don’t have to log into web interface ↩︎

    Joking aside, I recently learned that I can delete a branch on a remote (e.g. github) from my local repo on my computer (so I don’t have to log in from a web browser):

    git push -d remote_name remote_branch
                  

    Here are some which I find very useful.

    # Interactively choose which files / part of files to add to the
    # index. Pretty useful if you like to double check what code you 
    # are committing.
    $ git add -p
    $ git add -p src/
    # Also works when stashing changes.
    $ git stash -p
    # Instead of using `-m` do not provide a message. Git will open
    # the default text editor where you can type the commit message. 
    # The text editor will also show which files are going to be committed
    # to which branch, so no need to run git status.
    $ git commit
    # When wanting to commit all changes in a directory, just use commit
    # instead of doing a add + commit.
    $ git commit src/
    # Apply changes of an existing commit to the current branch.
    $ git cherry-pick "$COMMIT"
    # Revert the changes of a commit.
    $ git revert "$COMMIT"
    # Interactively manipulate the history of the last 10 commits. Drop,
    # merge, edit or reorder commits.
    $ git rebase -i HEAD~10
    # Show the git history including the changes made by commits.
    $ git log -p
                  

    I have a GUI tool that I wrote and use to interact with source code systems.
    It supports git, subversion (svn) and partitially murcurial (hg).

    It uses that stash command to make git pull reliable as one if its value adds.

    You can see its home page here https://scm-workbench.barrys-emacs.org/
    and I maintain it in copr here: barryascott/tools Copr

    As I develop on Fedora, Windows and macOS my tools also run on all of them.
    I maintain binary install kits for macOS and Windows.

    Another thing that is useful to configure is commit signatures. If you are already using ssh keys for authentication to the git remote its pretty simple to reuse them for signing commits. Just add the following lines to your git config (~/.gitconfig or ~/.config/git/config):

    [user]
            email = ...
            name = ...
            signingKey = ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBOsxcpis76VmY0xfhwN7ZEC/Ud16Nes+eoWHZtHpEDg # <- place your public key here (`$ cat .ssh/id_ed25519.pub`)
    [gpg]
            format = ssh
    [commit]
            gpgSign = true
    

    Its also possible to use gpg keys for signing, if you prefer gpg or are using bitbucket (which doesn’t support ssh key signatures) see the git documentation. After adding the git configuration go to github / gitea / gitlab and add your ssh key as signing key. Now your commits will have the verified badge next to them.

    Without signatures its impossible for people to say for sure that you are the person that created the commit. Its very simple to create a commit with the credentials of another person:

    $ git commit --author="John Doe <john@doe.com>"
                  

    There is a Git (and other VCS) integration plugin in KDE Dolphin, which is disabled by default. Enable it, and then Dolphin will show the state of files and folders in the local Git repository. The right-click menu also allows some basic Git operations.

    I have a few git log variants that come in handy, taken from different places:

    [alias]
        lg = !"git lg1"
        lg1 = !"git lg1-specific --all"
        lgs1 = !"git lg1-specific --all --simplify-by-decoration"
        lg2 = !"git lg2-specific --all"
        lgs2 = !"git lg2-specific --all --simplify-by-decoration"
        lg3 = !"git lg3-specific --all"
        lgs3 = !"git lg3-specific --all --simplify-by-decoration"
        lg1-specific = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(auto)%d%C(reset)'
        lg2-specific = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(auto)%d%C(reset)%n''          %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'
        lg3-specific = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset) %C(bold cyan)(committed: %cD)%C(reset) %C(auto)%d%C(reset)%n''          %C(white)%s%C(reset)%n''          %C(dim white)- %an <%ae> %C(reset) %C(dim white)(committer: %cn <%ce>)%C(reset)'
    

    The git-worktree command is very very useful when one is working on different branches simultaneously. For example, if I’m writing a new quick doc and also reviewing one, I can have two worktrees and not have to keep switching between the two branches in one checkout of the folder:

    https://git-scm.com/docs/git-worktree

    For vim users, fugitive is really good:

    github.com

    There’s pre-commit that is very useful to run hooks before committing.

    https://pre-commit.com/

    For Python code, for example, we use pre-commit to format our code before it can be committed:

    github.com

    NeuroML/pyNeuroML/blob/development/.pre-commit-config.yaml

    # See https://pre-commit.com for more information
    # See https://pre-commit.com/hooks.html for more hooks
    repos:
    -   repo: https://github.com/pre-commit/pre-commit-hooks
        rev: v4.4.0
        hooks:
        -   id: trailing-whitespace
        -   id: end-of-file-fixer
        -   id: check-added-large-files
    - repo: https://github.com/astral-sh/ruff-pre-commit
      rev: v0.4.1
      hooks:
        - id: ruff
          args: [ "--select", "I", "--fix" ]
        - id: ruff-format
                  

    Since we’re on Fedora’s discourse: Have something like

    [includeIf "gitdir:~/fedora/"]
            path = ~/.config/git/config.fedora
    

    in your global git config (e.g. in ~/.config/git/config), and put all the things which you want for your Fedora work in ~/.config/git/config.fedora (assuming you work in repo clones below ~/fedora/), for example:

    [alias]
            fedtag = ! git tag $(fedpkg verrel)
    [user]
            email = mjg@fedoraproject.org
    [push]
            default = simple
    

    If you feel fancy, you can make your life easier with dist-git: fetch via https (faster) and push via ssh; add your fork remotes with a URL like dist-git:mjg/rpms/forkedproject:

    # ssh for pushes only
    [url "https://src.fedoraproject.org/"]
            insteadOf = dist-git:
    [url "ssh://mjg@pkgs.fedoraproject.org/"]
            pushinsteadOf = dist-git:
    # rewrite "fedpkg clone" generated config
    [url "https://src.fedoraproject.org/"]
            insteadOf = ssh://mjg@pkgs.fedoraproject.org/
    [url "ssh://mjg@pkgs.fedoraproject.org/"]
            pushinsteadOf = ssh://mjg@pkgs.fedoraproject.org/
    # convenience for my forks
    [url "https://src.fedoraproject.org/forks/mjg/"]
            insteadOf = dist-git:mjg/
    [url "ssh://mjg@pkgs.fedoraproject.org/forks/mjg/"]
            pushinsteadOf = dist-git:mjg/
    

    Since I did not include rpms in the substitution you can use it for requests, flatpaks etc. also.

    This is excellent @job79, I had most of those in my ~/.gitconfig, but was missing the [commit] stanza.

    Also, the value for signingKey can be the (full path to the) filename containing your SSH private key.

    Here’s another ~/.gitconfig trick I learned a few years ago. This uses the Fedora package diff-so-fancy to perform granular highlighting of git diff. Change colors to suit your taste:

    [color "diff-highlight"]
    	oldNormal = red bold
    	oldHighlight = red bold 52
    	newNormal = green bold
    	newHighlight = green bold 22
    [color "diff"]
    	meta = yellow
    	frag = magenta bold
    	commit = yellow bold
    	old = red bold
    	new = green bold
    	whitespace = red reverse
    [diff-so-fancy]
    	changeHunkIndicators = false
    	stripLeadingSymbols = false
  •