DEV Community

Cover image for How do you use git between devices?
Doug Bridgens
Doug Bridgens

Posted on

How do you use git between devices?

If I'm working on a feature, on a branch, I struggle to do that while working 'remotely'.

When I work remotely I don't mean from the kitchen table, in a wfh style. My use-case is doing a couple of hours on a desktop at home, then maybe continuing on the train with a laptop as I travel to see some friends. Or going away for a few days and doing a couple of hours coding every morning.

I also use git history to keep track of progress, or track down rogue commits. So trying to maintain meaningful (one line) commit messages is important.

Through the years I've never found a good way to maintain a meaningful git history, while updating code on different devices. It's often too impractical to commit fully worked features, because I'm not actually finished yet but have to go off somewhere.

I've effectively created a desire line, by committing and pushing whatever I have as a checkpoint so I can continue the work on another device.

For example. I'm adding a new function as part of a feature, at home on a desktop. I don't quite have time to get it finished before I have to leave for a meeting. But I can use the sixty minute train ride to finish the work, using my laptop.

I'd just commit what's done with a message of checkpoint. Then twenty minutes later pull changes on the branch from my laptop, and finish it off.

The ideal would be a git log of commits with the checkpoint (or transfer) commits removed, while meaningful commits remain.

But I'm interested to know if anyone else has a better method?

What I'm thinking is somehow automating the following, maybe via an alias function or git hook.

Current state:

$ git log --oneline      
9ac99be (HEAD -> feature) meaningful 2
1736b60 checkpoint
5de2fe5 meaningful 1
Enter fullscreen mode Exit fullscreen mode

Move HEAD back to the last meaningful commit, but leaving the code intact:

$ git reset --soft HEAD~2

$ git log --oneline      
5de2fe5 (HEAD -> feature) meaningful 1
9679310 (develop) initial commit

$ git status             
On branch feature
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    modified:   main.go
Enter fullscreen mode Exit fullscreen mode

Now commit the next change:

$ git commit -m 'meaningful 2'
[feature 6fd925e] meaningful 2

$ git log --oneline           
6fd925e (HEAD -> feature) meaningful 2
5de2fe5 meaningful 1
9679310 (develop) initial commit

$ git diff 6fd925e~       
diff --git a/main.go b/main.go
index f33752a..8e3863f 100644
--- a/main.go
+++ b/main.go
@@ -4,4 +4,6 @@ import "fmt"

 func main() {
        fmt.Println("meaningful 1")
+       fmt.Println("checkpoint")
+       fmt.Println("meaningful 2")
 }
Enter fullscreen mode Exit fullscreen mode

Top comments (13)

Collapse
 
benr77 profile image
Ben

You could also practice continuous integration with yourself (i.e. even though there is no team).

Working in very small steps, the code is ALWAYS in a releasable state, and you only commit to main. If stuff needs to be hidden, use feature flags (a simple implementation can just be a config setting in the code - no need for a fully fledged feature flag product).

Collapse
 
daunderworks profile image
Doug Bridgens

Yeah, I do try to do this. But life sometimes gets in the way, more so as a solo dev on projects without a boss 😃

I've found that no matter how small the intention, sometimes I still reach for a checkpoint commit.

Collapse
 
benr77 profile image
Ben

Sure, but what I'm saying is the checkpoint commit doesn't have to be a bad thing to be avoided.

As long as the code compiles/runs, just commit it as though it was a normal part of your workflow. Don't call it a "checkpoint", just describe what and why you've done it like any other commit.

If you are working in small steps anyway, this shouldn't be much different from any of your other commits.

Basically if the code is good enough to keep, it's good enough to make it a "proper" commit, and if it's not good enough to keep you should just delete it and start over in your next coding session. If this feels like you are wasting work, it's because you are working in too large a step.

Also, if your commit history is really bothering you, remember about Git's interactive rebase feature - this allows you to do a lot of tidying afterwards if you feel the need.

Thread Thread
 
daunderworks profile image
Doug Bridgens

The checkpoint isn't bad code, it's just unfinished. And I want to finish it on another device.

You raise a good view though, which maybe modifies the question. If I'm already doing reasonably continuous integration in practice, is it possible to go one level more in granularity?

If I am working on my smallest chunk of change , something that's a single commit sized, is it possible to do that across two devices?

I've been bound by the git way of working for nearly twenty years. The concept that the commit is smallest part of the system, and indivisible. And you must sit still until it's completed.

But how we work has changed. I stopped being office based ten years ago, and stopped 9-5 hours over five years ago. In my mind is something like a cross between git and Google Docs.

Hmm.. just had a thought about creating a public VM with a file sync process. Maybe when I am leaving my desktop I can sync branch changes, and do the same on my laptop. I might try and see if that would work in practice.

thanks for your feedback, it's making me think 👍

Thread Thread
 
benr77 profile image
Ben

You could just spin up a NextCloud droplet (check it out on Digital Ocean Marketplace).

But I still think you are over-complicating things, and just need to use smaller commits. If you read Kent Beck's description of the TDD process you realise how tiny a commit can or should be.

Thread Thread
 
daunderworks profile image
Doug Bridgens

Ah, I didn't know about NextCloud. Interesting.

Yes, I understand development methodologies. And I also break them when I need to. I'm doing systems development, some data generation, infrastructure code, app development, documentation, etc, all in parallel. I'm building an app solo, which often (always 😂) means non-linear work.

I really do get what you're saying. But the position I find myself in is juggling five repo's concurrently, to develop features and deploy those features and document those features. It would be great to have a team on each stream of work, focused exclusively on that code and feature delivery.

Collapse
 
ridays2001 profile image
Riday

If you're working on something and have to switch devices, you can create a new branch and add a WIP commit. Then, when you are done, you can use git merge --squash <branch-name> to squash the WIP commits as one single commit into the main branch.

Zsh has this helpful alias for git - gwip that automatically adds a WIP commit. You can then use gunwip to undo the WIP commit. And then you can also do a force push to erase the WIP commit from GitHub history.

I encountered a situation similar to yours when I used a dual boot setup. Sometimes I shared projects between both OS on the same laptop. I used to create a new branch, push a checkpoint commit, switch OS, pull, undo the checkpoint or merge with squash if done. Sometimes, I just pushed the checkpoint commits to the main branch, then I used undo commit and force push to erase history.

Collapse
 
daunderworks profile image
Doug Bridgens

Ah, that's interesting. Nice, and uncontroversial 😃

Yes, dual boot would bring up the same challenge.

I'm going to give this a go, as it's fairly simple. 👍

thanks

Collapse
 
daunderworks profile image
Doug Bridgens • Edited

Now into the rabbit hole... 😂

I've just discovered that GitHub lets you modify the merge commit message. You can set it to the PR title (Settings>General>Pull Requests), which is a big help.

This makes the git log more readable:

$ git log --all --oneline --graph               
*   9669f21 (HEAD -> main, origin/main, origin/HEAD) Adds animal feature (#3)
|\  
| * 716f790 (origin/feature3, feature3) adds animal business logic
| * f044934 adds animal datastore
|/  
*   3ac9909 Adds person feature (#2)
|\  
| * cbf63f0 (origin/feature2, feature2) adds person business logic
| * c6429c1 checkpoint
| * 9d364d1 adds person datastore
|/  
*   ea50fad initial main function (#1)
|\  
| * 4bd88ab (origin/feature1, feature1) initial main function
|/  
* 9364e87 Initial commit
Enter fullscreen mode Exit fullscreen mode

Here I've done a soft reset on feature3.

And a summary is simple (with the merge commits set to PR title):

$ git log --first-parent --oneline
* 9669f21 (HEAD -> main, origin/main, origin/HEAD) Adds animal feature (#3)
* 3ac9909 Adds person feature (#2)
* ea50fad initial main function (#1)
* 9364e87 Initial commit
Enter fullscreen mode Exit fullscreen mode

Just need to figure out an alias function and where to apply it. But, getting the checkpoint commit hash, and then doing a soft reset to the preceding commit.

$ git cherry -v main
+ f044934704fff123ae2b3e9a41e8c79965a41a37 adds animal datastore
+ 670f395cfe6010e8fb9213485b930ae7ad57256d checkpoint

$ git reset --soft f044934704fff123ae2b3e9a41e8c79965a41a37

$ git commit -a -m 'adds animal business logic'
Enter fullscreen mode Exit fullscreen mode
Collapse
 
phlash profile image
Phil Ashby

Two things I've done in the past in this situation (neither of which actually use git, please feel free to shout cursed!):

  • File sync between devices, so I have the exact same state everywhere.. after all git fetch/push are effectively this to a shared repo, but I also have stash, modified things....

  • Remote dev system, that I RDP/ssh/vnc/etc. into, usually for me this is an Azure VM. Depends on network staying up which might be challenging on trains.

Collapse
 
daunderworks profile image
Doug Bridgens • Edited

Ha, vnc. Do you remember when Citrix (desktop) arrived on the scene? I think this may be tricky (for me), for the connection issues you mention. On the other hand, things like Google Docs (or any other mainstream note/doc sharing) work fine as part of a fairly random work day. It's interesting that nothing like this sync (as opposed to vnc-like) exists.

Yes, I'm thinking a simple file sync may be useful. Given that I am leaving my desk (iMac) and knowingly going on the road to work on my laptop. So $ sync_my_wip would be easy.

I've been toying with @ridays2001 suggestion. It looks pretty neat, and easy.

Explicitly branching off my feature branch to create a checkpoint/wip branch, where I don't care about commit messages:

*   5f5abbd (HEAD -> main) Adds robot feature.
|\  
| *   e7d3b17 (feature4) Adds robot business logic
| |\  
| | * def0ab3 (wip) my second checkpoint
| | * 1b42f7e my first checkpoint
| |/  
| * 68b0ecb adds robot datastore
|/  
*   9669f21 (origin/main, origin/HEAD) Adds animal feature (#3)
|\  
| * 716f790 (origin/feature3, feature3) adds animal business logic
| * f044934 adds animal datastore
|/  
*   3ac9909 Adds person feature (#2)
|\  
| * cbf63f0 (origin/feature2, feature2) adds person business logic
| * c6429c1 checkpoint
| * 9d364d1 adds person datastore
|/  
*   ea50fad initial main function (#1)
|\  
| * 4bd88ab (origin/feature1, feature1) initial main function
|/  
* 9364e87 Initial commit
Enter fullscreen mode Exit fullscreen mode

And then the same graph when I'd squash the merge of my wip branch back into my feature branch, where I get a commit message to say what happened:

*   5f5abbd (HEAD -> main) Adds robot feature.
|\  
| * e7d3b17 (feature4) Adds robot business logic
| * 68b0ecb adds robot datastore
|/  
*   9669f21 (origin/main, origin/HEAD) Adds animal feature (#3)
|\  
| * 716f790 (origin/feature3, feature3) adds animal business logic
| * f044934 adds animal datastore
|/  
*   3ac9909 Adds person feature (#2)
|\  
| * cbf63f0 (origin/feature2, feature2) adds person business logic
| * c6429c1 checkpoint
| * 9d364d1 adds person datastore
|/  
*   ea50fad initial main function (#1)
|\  
| * 4bd88ab (origin/feature1, feature1) initial main function
|/  
* 9364e87 Initial commit
Enter fullscreen mode Exit fullscreen mode

I really think this is a cool workflow/solution. And easy with some shell alias functions.

The filesync is what I'll try if this doesn't work out. 👍

Collapse
 
mrlinxed profile image
Mr. Linxed

You could use feature branches and squash merge them when they are done. Then in your main/master branch, you'll only have one meaningful commit.

Collapse
 
daunderworks profile image
Doug Bridgens

I'm old enough to believe squashing commits is bad, because you lose that history. Therefore it's pointless to write commit messages at all. Although I understand that this is not the modern view 😃

The way we old-timers see a summary view, with git log and --first-parent:

$ git log --first-parent --oneline
* 9669f21 (HEAD -> main, origin/main, origin/HEAD) Adds animal feature (#3)
* 3ac9909 Adds person feature (#2)
* ea50fad initial main function (#1)
* 9364e87 Initial commit
Enter fullscreen mode Exit fullscreen mode

This means we do the squashing just on the view, rather than throw away the meaningful commit information.