A new site for my ramblings
Home | Up |
I often find myself working on projects where the root repository is locked behind a firewall and can only be accessed with a privileged device like a corporate laptop. But the laptop is not powerful enough to do the development on, and I want to use a dedicated machine.
This article shows you a workflow that helps you do this.
To make the description clear I will use the following terminology.
So the main repo already exists and foo is an existing project and develop is the branch all my colleagues and myself are merging to.
We will create a bare repository on the USB so that we can use it as remote on both the laptop and the workstation. Plug the USB into the laptop and navigate to the directory where you want the repo to go. I use git-bash for working on the laptop so a sensible place is /d/repos.
cd /d/repos
git clone --bare https://main.repo/foo.git
On the laptop clone foo into my workspace and then add a remote for the bare repo on the USB.
cd ~/workspace
git clone https://main.repo/foo.git
cd foo
git remote add usb /d/repos/foo.git
So now you have a working directory on the laptop and it has remotes set up. The main repo is called origin and the USB stick is called usb.
Eject the USB stick from the laptop and plug it into the workstation. We will assume from here on if you are working on a device, the USB will be plugged into that device and correctly mounted.
On the workstation you only need to clone the project from the USB. On my workstation I use WSL instances and mount the USB on /mnt/d. The workflow here is mount the USB, clone the project, then unmount the USB. The working directory on the workstation only has one remote, origin which will point back to the USB.
dmount
cd ~/workspace
git clone /mnt/d/repos/foo.git
dunmount
You will be doing the work on a feature branch, which you later merge/drop into develop. You can create this branch either on the main repo, laptop or workstation, and then propagate it to the other locations.
This is the preferred place to create the branch. You pick up a new ticket and create a feature branch on the main repo using the GUI. Now you need to get this branch onto your workstation.
On the laptop, you need to checkout the new branch and then push it to the USB. First do a pull to make sure you get updated branch information from the main repo.
git pull
git checkout feature/bar
git push usb feature/bar
Note that the tracking remote for this branch will be origin.
Simply checkout the new branch from the USB. Again, pull first to update the list of remote branches.
git pull
git checkout feature/bar
This is less preferred. You start working on something and realise it needs its own branch. So you create one, then push it all the way back to the main repo. At each step you set the upstream tracking information to make the pulling and pushing consistent.
Create the new branch with your changes, then push to the USB, setting the upstream tracking information.
git branch feature/bar
git checkout feature/bar
git commit -m "some message"
git push -u origin feature/bar
On the laptop you need to update the branch information from the USB, checkout the new branch, and push it the main repo, and reset the tracking so you always have the main repo as the default tracking location.
git remote update usb
git checkout feature/bar
git push -u origin feature/bar
Setting the upstream is optional, but for consistency it is best to have the tracking upstream point towards the main repo, then you know where you are later when you are pushing and pulling commits.
This is not preferred, but if you get in this situation you need to push both to the main repo and the USB. You would get into this situation if the main repo was not one of the git servers, like Github or Gitlab, so the only way of creating and merging feature branches is to do it in a working directory.
Create the new branch, push with tracking to the main repo, then push without tracking to the USB.
git branch feature/bar
git checkout feature/bar
git commit -m "some message"
git push -u origin feature/bar
git push usb feature/bar
A pull request will update the local refs, then you can just checkout the required branch.
git pull
git checkout feature/bar
You can run git branch --all -vv
to get a view of which branches are known about, where they are tracked and if they up to date. Here is the view from the laptop.
$ git branch -avv
* feature/from-lap 4a2a68c [origin/feature/from-lap] changed on laptop
feature/from-ws 97d0821 [origin/feature/from-ws] Change on ws
main c12dd7c [origin/main] .
remotes/origin/feature/from-lap 4a2a68c changed on laptop
remotes/origin/feature/from-ws 97d0821 Change on ws
remotes/origin/main c12dd7c .
remotes/usb/feature/from-lap 4a2a68c changed on laptop
remotes/usb/feature/from-ws 97d0821 Change on ws
remotes/usb/main c12dd7c .
From this you can see that the current branch is “feature/from-lap”, and it is tracked to origin. The same branch is known about remotely on both “origin” and “usb”, and the commit IDs all match so they are synchronised. You can also see the other two branches here are also tracked from origin and synchronised both locally and on usb.
Here is the simpler view from the workstation.
git branch --all -vv
* feature/from-ws 97d0821 [origin/feature/from-ws] Change on ws
main c12dd7c [origin/main] .
remotes/origin/feature/from-lap c12dd7c .
remotes/origin/feature/from-ws 97d0821 Change on ws
remotes/origin/main c12dd7c .
It looks like the workstation does not know about the branch “feature/from-lap”. We can fix that with a pull.
$ git pull
remote: Counting objects: 5, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /home/sjh/git-tests/usb
c12dd7c..4a2a68c feature/from-lap -> origin/feature/from-lap
Already up-to-date.
$ git branch --all -vv
* feature/from-ws 97d0821 [origin/feature/from-ws] Change on ws
main c12dd7c [origin/main] .
remotes/origin/feature/from-lap 4a2a68c changed on laptop
remotes/origin/feature/from-ws 97d0821 Change on ws
remotes/origin/main c12dd7c .
So now the workstation knows about the new branch because it is listed in the remote refs. Checking out that branch will pull all changes locally.
$ git checkout feature/from-lap
Branch feature/from-lap set up to track remote branch feature/from-lap from origin.
Switched to a new branch 'feature/from-lap'
$ git branch --all -vv
* feature/from-lap 4a2a68c [origin/feature/from-lap] changed on laptop
feature/from-ws 97d0821 [origin/feature/from-ws] Change on ws
main c12dd7c [origin/main] .
remotes/origin/feature/from-lap 4a2a68c changed on laptop
remotes/origin/feature/from-ws 97d0821 Change on ws
remotes/origin/main c12dd7c .
So now the current branch is the laptop one, and by comparing the commit ID it matches what is on the laptop and in the main repo.
Committing is pretty simple. Depending on where you do the commit, you have to take different actions to ensure all of the repos and working directories are up to date.
You have made some changes and now you are ready to commit them. Commit then push to the rest of the repos.
Commit the changes and push to the USB.
$ git commit -m "a message"
$ git push
Plug the USB into the laptop, pull from it, then push to the main repo.
$ git pull usb feature/bar
$ git push
Not preferred, but maybe you spotted a mistake while transferring and fixed it there and then.
Push to both the main repo and the USB.
$ git push
$ git push usb feature/bar
Update from the USB
$ git pull
Perhaps someone else has made some changes on your branch and you want them.
Pull from main, push to USB.
$ git pull
$ git push usb feature/bar
Bring the working directory up to date.
$ git pull
Through merging you incorporate your work onto the main branch. If the work is complete, the feature is finished or the bug is solved, you will also be deleting the working branch.
If you are using a tool like Github or Gitlab, use the merge mechanism on the platform to complete the merge in preference to any other place.
If you need to merge within the tools then do this as close to the shared repository as possible. Push the updated main branch back to the central repository and also the USB repository.
git checkout main
git merge bar
git push
git push usb main
Repeat the pull on the workstation to ensure it is also up to date.
If the branch is now finished with you should drop it wherever it exists.
git checkout main
git branch -d bar
git push --delete origin bar
git push --delete usb bar
Ensure the working space is up to date with any branches there might be on the remote.
git remote update origin
Delete any stale branches held locally that no longer exist on the remote.
git remote prune origin