Multitasking like a pro with the WIP commit
Tags: git, coding, developer
Published: 2024-01-31 08:02:29

## Intro
Multitasking sucks and should be an exception 99% of the time for coding work. But alas, life does what it wants, so sometimes when coding, you have to urgently put your current work away to work on something else.

You may already know of the popular git stash command but did you know there’s an arguably better way?

In this article, I talk about the The WIP (work in progress) commit and the git commands that enable it, why it’s more flexible than other choices, and also some aliases with cool names.

---

## The WIP Commit Sales Pitch

You’re working on some branch and have some unstaged changes. Imagine the following scenarios:

- You want to share your progress with a colleague to collaborate on a tough issue you’re stuck on.

- A sudden high priority production bug arises and you need to work on it ASAP while you delegate your current branch to someone else.
- The feature you’re working on is unfinished but you’re done for the day so you want to push your work to your branch to keep it safe in the cloud.
- You want to simply transfer your current work to a different machine to continue working there.

The common thing between all of these is that you need to save your work somewhere **right now**. You don’t care about commit messages, pre-commit hooks, CI pipelines, or anything else.

Well, guess what? The WIP commit removes all of that from your way and allows you to truly just **send it and forget it**.


![WIP commit skips unnecessary steps](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n14xv7jwo370h23oiflr.png)

Here’s the command for it:

```bash
git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify --no-gpg-sign --message "--wip-- [skip ci]"
```

Yeah, it’s pretty terrifying. The cool part is, [some smart people on the internet](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/git) thought of it for us so we don’t have to worry about it. The command comes from the ohmyzsh git plugin aliases.

If you’re curious, here’s a breakdown of what each part of the command does:


![Breakdown of the gwip alias](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mdxoqsfqm5fdp29wjhpl.png)

## Demo & Usage

There are three aliases you should know:

- `gwip`
- `gunwip`
- `gunwipall`

You can use the `gwip` alias to stage everything and create a WIP commit in one go. Here’s a demo:


![Using the gwip command](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0nqlk43ydrsy3teq5wcq.gif)


Note that you still have to `git push` it manually if you want to track it remotely. If you have pre-push hooks, you can skip those with `git push --no-verify`. _Use this power wisely._

Likewise, you can use `gunwip` to unwip (soft reset) the last WIP commit you’ve made. Here’s a demo:


![Using the gunwip command](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lg9gbvzxlq5v9t5ppp6s.gif)


Finally, you can use `gunwipall` which unwips (soft resets) all WIP commits you have in your current branch if you happened to have more than one.


## Why?

- Relevant work is stored in the relevant branch
- WIP commits are gone when you delete the branch, so you don’t have a list of rotting old stashes.
- No copy-pasting of files like with apply
- Your work is saved on the cloud

### Why not git stash?

Although `git stash` is another really handy command, stashing doesn’t work for this use case for a few reasons:

- It’s only local to your machine
- It’s not associated with any branches as it’s stored in your stash list
- Applying a stash which is not at the top of your list complicates your command.
- Your stash list can get messy with forgotten stashes (be honest with yourself, how many do you have right now?)


### Why not patch?

Patches solve pretty much the same issue, but they aren’t as useful as `gwip` for the following reasons:

- They’re not associated with a branch.
- They involve copy-pasting
- You have to track them manually. You’re not able to push a patch, otherwise it would be called a commit.
- Did I mention they involve copy-pasting?

## Setting it up

### Using Ohmyzsh

If you’re using Ohmyzsh, you can edit your `.zshrc` file’s plugins to include `git` like so:


![Notice the red arrow helping you to find the word git under plugins, in case that was difficult](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dls4mkhzjgwknlkkpdy5.png)


Afterwards, you’ll want to run `source ~/.zshrc` or quit your terminal and open it up again for changes to take effect. By the way, the `git` plugin for OMZ includes a ton of really helpful aliases that you’d do yourself a favor by checking out [its docs](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/git).

If you’re not using OMZ, simply read the next section about setting it up manually with aliases.


### Manually


Add the following to your `.zshrc` or `.bashrc` file:

```bash
alias gwip='git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify --no-gpg-sign --message "--wip-- [skip ci]"'

alias gunwip='git rev-list --max-count=1 --format="%s" HEAD | grep -q "\--wip--" && git reset HEAD~1'

# Similar to `gunwip` but recursive "Unwips" all recent `--wip--` commits not just the last one
function gunwipall() {
  local _commit=$(git log --grep='--wip--' --invert-grep --max-count=1 --format=format:%H)

  # Check if a commit without "--wip--" was found and it's not the same as HEAD
  if [[ "$_commit" != "$(git rev-parse HEAD)" ]]; then
    git reset $_commit || return 1
  fi
}
```

Now reload your config file using `source ~/.zshrc` (or `.bashrc` or whatever you’re using) and you should now have the aliases ready for use.


## Conclusion

WIP commits make everyone’s lives easier by allowing you to simply send it and forget it. I hope you find it useful. Let me know your opinion!