How I use git on multiple devices
Tags: git, github, programming, bash
Published: 2024-05-20 14:43:03

In the last few years I've been using [Working Copy](https://workingcopy.app) on iPhone/iPad to refine README, code comments, and func/var naming, as part of feature development.

Doing this on devices without the ability to change code has been a big quality driver for me. The draw back is a few unconventional commits at the end of a feature branch.

The commit history can easily get messy, with `checkpoint` or the evil twins `typo` and `update`. Passing temporary changes on my feature branch, up into GitHub, so I can view changes on multiple devices gets a little ugly.

I posted a [question](https://dev.to/daunderworks/how-to-use-git-between-devices-3ggo) about how others have solved this, about what process others use. @ridays2001 gave a good solution 👍

### TL;DR

Create a throw away WIP branch from the feature branch, and pull the changes back to your feature branch with a `merge --squash`.

```bash
$ git checkout -b kitchen_orders
  # do main code changes

# setup your wip branch and make accessible
$ git checkout -b wip_kitchen_orders
$ git push --set-upstream origin wip_kitchen_orders
  # do minor updates and changes on this branch

# pull wip changes back onto feature branch
$ git checkout kitchen_orders
$ git merge --squash wip_kitchen_orders

# commit the wip changes as one
$ git commit -a -m 'improves godoc comments'

# clean up wip branch
$ git push origin --delete wip_kitchen_orders
$ git branch -D wip_kitchen_orders
```

These can all be aliased within the shell.

### How it works

Here's a summary write-up showing what you need to know, for multi-device changes with a clean git history.
 
I'm building out my fictional restaurant app, and want to add store and retrieve kitchen orders.

A feature branch for this change:

```bash
$ checkout -b kitchen_orders
Switched to a new branch 'kitchen_orders'
```

I do a bunch of changes as normal, and end up with:

```bash
$ git log --oneline
a45fa9e (HEAD -> kitchen_orders, origin/kitchen_orders) adds kitchen order datastore
2f77e62 adds swp to gitignore
4491447 adds fsvault external package
80df0ca adds config pkg to kitchen
```

Before I create a PR to merge back to `develop`, I want to read through the changes and make sure I will understand it in three months time. In a team environment this helps make PR reviews easier too.

So I create a WIP branch from my feature branch, and push that to Github.

```bash
$ git checkout -b wip_kitchen_orders          
Switched to a new branch 'wip_kitchen_orders'

$ git push --set-upstream origin wip_kitchen_orders
branch 'wip_kitchen_orders' set up to track 'origin/wip_kitchen_orders'.
```

This WIP branch is for messy commits, and is used to push and pull changes between devices (iPhone, iPad). It lets me do my own code review in a cafe with a pastry, in a civilised way 😁

For me, this code review process is almost more important than the actual code. It's really a review of how understandable I'm leaving things for my future self.

Depending on the feature/change I may make many updates to improve the readability over a few days, with whatever device I have to hand.

Typically this is what I end up with. A bunch of meaningless commit messages, but essential refinements underneath. 

```bash
$ git log --oneline
a04d7a6 (HEAD -> wip_kitchen_orders) typo
dadc12a stupid typo
8c0dd3c updates function godoc comments
a45fa9e (origin/wip_kitchen_orders, origin/kitchen_orders, kitchen_orders) adds kitchen order datastore
2f77e62 adds swp to gitignore
4491447 adds fsvault external package
80df0ca adds config pkg to kitchen
```

Now for the magic. I can pull these WIP changes back into my feature branch without a merge commit. 

I switch back to my feature branch, and check it's clean.

```bash
$ git checkout kitchen_orders
Switched to branch 'kitchen_orders'
Your branch is up to date with 'origin/kitchen_orders'.

$ git status
On branch kitchen_orders
Your branch is up to date with 'origin/kitchen_orders'.

nothing to commit, working tree clean
```

Then I can merge my WIP branch with `squash` to pull over the changes without any commit.

```bash
$ git merge --squash wip_kitchen_orders
Updating a45fa9e..a04d7a6
Fast-forward
Squash commit -- not updating HEAD
 kitchen/internal/datastore/order.go | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

$ git status
On branch kitchen_orders
Your branch is up to date with 'origin/kitchen_orders'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   kitchen/internal/datastore/order.go
```

This leaves me able to apply these WIP changes as a single commit on my feature branch, as if the WIP branch never existed.

So I end up with a long term git log graph like this:

```bash

$ alias gl='git log --graph --pretty="%C(green) %d %C(red)Date: %ad %C(yellow) %s" --date=human'

$ gl
*     (HEAD -> develop, origin/develop, origin/HEAD) Date: 27 seconds ago  Merge pull request #5 from thisdougb/kitchen_orders
|\  
| *   (origin/kitchen_orders, kitchen_orders) Date: 82 seconds ago  improves datastore godoc comments
| *   Date: 33 minutes ago  adds kitchen order datastore
| *   Date: 52 minutes ago  adds swp to gitignore
| *   Date: 54 minutes ago  adds fsvault external package
| *   Date: 80 minutes ago  adds config pkg to kitchen
|/  
*     Date: Wed May 1 13:57  Merge pull request #4 from thisdougb/thisdougb-patch-1
|\  
| *   Date: Wed May 1 13:57  Update README.md
|/  
*     Date: Wed May 1 13:55  Merge pull request #3 from thisdougb/part1b
```

And remember to clean up:

```bash
$ git push origin --delete wip_kitchen_orders
To github.com:thisdougb/go-eat.git
 - [deleted]         wip_kitchen_orders
$ git branch -D wip_kitchen_orders
Deleted branch wip_kitchen_orders (was a04d7a6).
$ 
```

The nice thing about this method is that it's really simple. I can create a WIP branch when I need to, within Working Copy or from another device.