Skip to content

Essential Git fu for technical writers

Posted on:January 16, 2023 at 07:29 AM

In my previous post, Calling all developers: We need better documentation tools I touched upon how Git becomes problematic for writers. Here I am sharing with you some Git fu I have seen people use, and how I adapted it in my everyday workflow. Using these tricks allows me to save time and reduce the chances of manual error.

These are also helpful if you or someone in your team is a Git newbie or having trouble remembering all the Git related commands from your workflow. I presented this as a talk at linux.conf.au 2020.

See the slides form my talk.

Table of contents

What is Git fu?

Unfortunately, no one can be told what The Matrix is. You’ll have to see it for yourself.

Mainly, it’s Git aliases and bash functions that I use multiple times a day. It allows you to map easy English terms for the Git commands you use every day. For example, to create a new branch, you can run the following command:

git newbranch <branch-name>

Mainly, it’s Git aliases and bash functions that I use multiple times a day. It allows you to map easy English terms for the Git commands you use every day.

For example, to create a new branch, you can run the following command:

git newbranch <branch-name>

instead of

git checkout -b <branch-name>

To me, that is more logical and saves me from remembering the actual command. That was a simple operation, for complex tasks, you can also run anonymous bash function with git aliases. An example of that would be downloading a remote branch (pull request or merge request) for review. So here goes my list of handy git aliases. Although you can use single alphabets for aliases, I believe having a full word makes more sense.

A use case

A use case Consider the content editing guide for openshift-docs. Before you edit content, the first step is to “Ensure your local repository is in sync with the remote” by running the following commands:

$ git checkout master
$ git fetch upstream
$ git rebase upstream/master
$ git push origin master

You must do this every time you create a new branch for editing content.

Now, this is a manual process, people are sloppy and sometimes forget to do these steps, which might result in merge conflicts at a later stage. To minimize the chances of error and support your workflow, you can have a new branch alias that does all this, every time you create a new branch, for example:

[alias]
newbranch = "!f() { \
	    git checkout master; \
	    git fetch upstream; \
	    git rebase upstream/master; \
	    git push origin master; \
	    git checkout -b \"$1\"; \
	    }; f"

Now when writers use this alias to create a new branch, they actually are following the specified workflow processes.

$ git newbranch test-branch
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
remote: Enumerating objects: 4979, done.
remote: Counting objects: 100% (4979/4979), done.
remote: Total 125270 (delta 4979), reused 4979 (delta 4979), pack-reused 120291
Receiving objects: 100% (125270/125270), 96.45 MiB | 5.51 MiB/s, done.
Resolving deltas: 100% (85396/85396), completed with 875 local objects.
From github.com:openshift/openshift-docs
 * [new branch]          dedicated-3.1          -> upstream/dedicated-3.1
 * [new branch]          dedicated-3.2          -> upstream/dedicated-3.2
 * [new branch]          enterprise-3.0         -> upstream/enterprise-3.0
 * [new branch]          enterprise-3.1         -> upstream/enterprise-3.1
 * [new branch]          enterprise-3.10        -> upstream/enterprise-3.10
 * [new branch]          enterprise-3.11        -> upstream/enterprise-3.11
 * [new branch]          enterprise-3.2         -> upstream/enterprise-3.2
   6551b4bd8..af48688cf  master                 -> upstream/master
 * [new branch]          master-3               -> upstream/master-3
 * [new branch]          online                 -> upstream/online
 * [new branch]          revert-15425-BZ1644512 -> upstream/revert-15425-BZ1644512
First, rewinding head to replay your work on top of it...
Fast-forwarded master to upstream/master.
Everything up-to-date
Switched to a new branch 'test-branch'

Git aliases

… one little tip that can make your Git experience simpler, easier, and more familiar: aliases (SOURCE: GIT DOCUMENTATION)

Git aliases allows you to create your own Git commands. You can use it to specify an alias and specify a Git sb-command or bash function when you call that alias.

Git sub-commands

You can use the git configcommand as follows to create an alias:

git config --global alias.newbranch 'checkout -b'

In this command, we are creating an alias called ‘newbranch’ to create a new branch. You can use the alias as follows:

git newbranch <branch-name>

Rather than using the git configcommand to create aliases, you can also directly modify the .gitconfigfile. All aliases are saved under the alias directive in your git configuration file as follows:

[user]
	email = …
...
[alias]
	unstage = reset HEAD --
...

Bash functions

You can also run external commands by appending your aliases commands with !.

$ git config --global alias.visual '!gitk'

And you can also run bash scripts by using the following format:

[alias]
your_alias = "!f() { <your-complex-commands> }; f"

Some Git aliases that I use

Below are some of the git aliases I use every day, you can also view the full list. To use them, just copy-paste the aliases into your global .gitconfigfile, or your local repository config file .git/config

Sync with remote repository

[alias]
syncorigin = "!f() { \
git fetch origin master && git rebase origin/master; \
}; f"
syncupstream = "!f() { \
git fetch upstream master && git rebase upstream/master; \
}; f"

Create a new branch

[alias]
newbranch = checkout -b

Delete, rename and find branches

[alias]
deletebranch = "!f() { git branch -D \"$1\"; }; f"
renamebranch = "!f() { git branch -m \"$1\"; }; f"
findbranch = !git branch | grep -i

I find ‘findbranch’ alias pretty helpful, you can use it to list all branches that match your query.

$ git findbranch <few-characters-of-branch-name>
$ git findbranch bug-22
gn/bug-2235
sh/bug-2261
sh/bug-2234

Switch to previous branch

[alias]
previousbranch = checkout @{-1}

Add changes to previous commit

[alias]
addtolastcommit = "!git add -A && git commit --amend --no-edit"

Undo commits

[alias]
undotillcommit = "!f() { git reset --soft \"$1\" && git status; };f"
undolastcommit = !git reset --soft HEAD^

Work-in-progress commit

[alias]
wip = "!f() { \
git add -A; \
if [ \"$(git log -1 --pretty=%B)\" = \"WIP:Do not merge\" ]; then git commit --amend --no-edit; else git commit -m \"WIP:Do not merge\"; fi; \
}; f"
unwip = "!f() { \
if [ \"$(git log -1 --pretty=%B)\" = \"WIP:Do not merge\" ]; then git reset HEAD^; else echo \"No work in progress commit\"; fi; \
}; f"

Push changes

[alias]
pushbranch = "!f() { \
git push origin $(git rev-parse --abbrev-ref HEAD); \
}; f“
forcepushbranch = !git pushbranch -f

Get a remote branch

[alias]
getremotebranch = "!f() { \
read -p \"Enter remote branch name: \" branchname;
echo \"==== Syncing with origin ====\";
git fetch origin;
echo \"==== Getting the remote branch ====\";
git checkout -t origin/$branchname;
}; f"

View a list of modified files in the last commit

showmodifiedfiles = "!f() { \
echo \"==== Modified files in last commit ====\"; \
git diff-tree --no-commit-id --name-status -r $(git rev-parse HEAD); \
}; f"

Know more