Same task — "show me what this branch changed" — but the two tools take opposite dot conventions. Get it backwards and your review fills with commits the author never touched.
The diff: use three dots
git diff origin/main...HEAD
Three-dot diff is git diff $(git merge-base origin/main HEAD) HEAD — it diffs against the branch point, not the tip of main. That's exactly what you want: the author's delta and nothing else.
The nice property: it's immune to origin/main moving forward. New commits landing on main after the branch point aren't ancestors of HEAD, so they don't shift the merge-base. The diff stays clean.
The trap is a stale base, not a newer one. If your local main is older than the branch point, the merge-base slides back to an older ancestor and the diff swallows unrelated upstream commits — making the author look like they changed far more than they did. So fetch first:
git fetch origin
git diff origin/main...HEAD
Want to see the branch point itself? git merge-base origin/main HEAD.
The log: use two dots
git log origin/main..HEAD
Two-dot log = commits reachable from HEAD but not from origin/main = the branch's own commits, exactly.
Don't reach for three dots here out of habit — git log A...B is the symmetric difference, so it also lists the commits main picked up that HEAD doesn't have. That's the noise you were trying to avoid.
So: diff three-dot, log two-dot. Different tools, opposite defaults, same job.
Moving a vagrant-libvirt VM between Linux hosts looks like a two-step
(vagrant package then vagrant up on the other side), and that's exactly
what I tried. Both steps died in the same place: fog-libvirt's stream
upload/download of a large qcow2 from/to libvirt's storage pool reset
mid-flight (Cannot recv data: Connection reset by peer, hung at 0%).
The streaming bug is in fog-libvirt's vol upload/download. The fix is to
bypass vagrant-libvirt's vol-upload/vol-download entirely: flatten
the overlay qcow2 against its backing file, drop the result in a libvirt
storage pool by hand, then virsh define + virsh start. Treat
vagrant-libvirt as the boot-time scaffolding only; the running VM is plain
libvirt after that.
1. Make the box self-contained
vagrant package exists to bake the VM's disk + metadata into a .box
file. With a libvirt provider the disk is usually a qcow2 with a backing
file (qemu-img info ... | grep "backing file"), and vol-download only
streams the overlay — you'd ship an incomplete box. Skip it and flatten
manually:
…more
You SSH through a bastion box. So you copied your private key onto it. Now that key lives on one more machine — one more place it can be stolen from, one more copy to rotate when something goes wrong.
SSH agent forwarding removes the need entirely.
What it actually does
This is the part most explanations hand-wave past. Your private key never needed to be on the bastion — that's not how SSH auth works.
- The target machine needs your public key (in
~/.ssh/authorized_keys). It always did.
- The client (you) holds the private key and signs a challenge the target sends.
Without forwarding, when you SSH from the bastion to a third machine, the bastion becomes the client — so it needs the private key to sign. That's the only reason you ever copied it there.
With forwarding, the bastion doesn't sign anything itself. It forwards the challenge back to your agent on your laptop, your agent signs it, and the signature travels back. The bastion never touches the private key.
No forwarding: laptop (key) → bastion (key) → target (pubkey)
With forwarding: laptop (key+agent) → bastion (no key) → target (pubkey)
Setup
- Load your key into the agent on your laptop (the agent is usually already running):
ssh-add ~/.ssh/id_rsa
- Enable forwarding for the bastion in
~/.ssh/config:
Host bastion
HostName bastion.example.com
User myuser
ForwardAgent yes
- Verify it works:
ssh bastion
ssh-add -l # lists your keys → forwarding is live
ssh internal-vm # connects, bastion never had your key
The catch
Only forward through machines you trust. Anyone with root on the bastion can request signatures from your agent while your session is open — effectively borrowing your identity. Never use -A on a shared or untrusted host.
Do you still need it with a passphrase-less key?
If your key has no passphrase and you've already copied it everywhere, forwarding isn't strictly required — direct auth from the bastion works fine. But keep ForwardAgent yes in the config anyway. It costs nothing, and the day you switch to a passphrase-protected key, you'll only ssh-add once on your laptop instead of typing the passphrase on every connection.
On Windows, when you open Terminal in a Vagrant VM, it sometimes runs in Administrator mode regardless of which shell you choose — even when you explicitly selected normal user mode.
The fix is to restore User Account Control (UAC) prompts:
- Open Control Panel → System and Security
- Under "Security and Maintenance", click "Change User Account Control settings"
- Move the slider back to the default: "Notify me only when apps try to make changes to my computer"
- Click OK, then confirm with Yes
When UAC is fully disabled (slider at "Never notify"), Windows bypasses the elevation prompt and grants administrative privileges silently — which causes every Terminal session to launch as Administrator. Restoring UAC to its default level re-enables the elevation check and lets normal user sessions work normally again.
I was inside a Windows Server 2025 VM (running on a Linux host via libvirt/Vagrant) trying to scp a file from the host. The host answered ping fine, but every ssh/scp to it just hung and failed. The obvious suspect — the Windows firewall on the VM — was a red herring. The real culprit was ufw on the Linux host, which MX Linux configures to default-deny incoming and only allow the LAN.
The giveaway: ICMP works, TCP doesn't. ufw permits ping by default but drops unlisted TCP ports, so connectivity "looks" fine while SSH silently dies. If you can ping but not connect to a port, suspect a host firewall, not a routing problem.
Check what the host actually allows:
sudo ufw status verbose
In my case port 22 was only open to the physical LAN (192.168.68.0/24), while the VM lived on the libvirt NAT subnet 192.168.121.0/24 — a different network the rules never mentioned. So the VM's packets hit the default deny (incoming) and vanished.
Fix: explicitly allow the VM subnet to reach the port you need.
sudo ufw allow from 192.168.121.0/24 to any port 22 proto tcp comment 'libvirt guests -> host ssh'
After that the VM connects straight away, and the rule survives reboots.
One trap worth naming: if the host is also on a Tailscale/VPN network, its public name may resolve to the Tailscale IP (e.g. 100.x.x.x) — but from a NATed guest that's still the same host, reached through the same deny-by-default firewall. Don't let the fancy hostname distract you; the fix is the same ufw rule on the libvirt subnet.
If you'd rather not open the firewall at all, push the file the other way — from the host into the guest. With Vagrant that's just vagrant upload <src> '<C:\dest>', no inbound rule needed.