In the following sequence hub sync
won't remove local branches, that were merged/removed on Github:
$ hub clone
$ hub fork
$ git checkout -b new-branch
$ # (make & commit changes)
$ git push gmile new-branch
$ hub pull-request
$ # (enter PR description)
$ # (merge the branch on github)
$ # (remove the branch on github)
$ hub sync
After hub sync
local branch new-branch
is not removed. Only master is updated. Full output:
$ hub sync
remote: Counting objects: 26, done.
remote: Compressing objects: 100% (25/25), done.
remote: Total 26 (delta 1), reused 0 (delta 0), pack-reused 0
Updated branch master (was 4f2c4c9).
$
hub --version
returns this:
$ hub --version
git version 2.10.0
hub version 2.3.0-pre8
$
Thanks for reporting! This is right now expected behavior, but I definitely see how you were surprised by this because it seems logical that "new-branch" would get deleted.
hub sync
right now only manages to track branches that have "upstream" configuration in git terms. This is achieved with git push -u gmile new-branch
, or with git checkout new-branch
as a shorthand for git checkout -b new-branch --track gmile/new-branch
.
A branch that doesn't have upstream configuration is never deleted during sync
because I couldn't figure out how to cleanup all merged branches without risking disrupting someone's flow by deleting branches that technically _appear_ merged but that a person might not have wanted deleted just yet. Therefore, deletion is only restricted to branches that have upstream configuration, but whose remote branch (gmile/new-branch
) is now missing (i.e. deleted).
@mislav thanks for explaining the behaviour!
Your examples suggest hub sync
will remove local branches if they were set to track remote upstream _during branch creation or push_.
Should hub sync
properly remove existing branches, _created without_ --set-track-to
, but modified to track an upstream branch afterwards? I just tried this and failed, somewhat. I took existing branch, and modified it to track a remote upstream branch of the same name. Here's a full sequence of steps I did:
$ # (branch update-deps is not tracking an upstream branch)
$ git branch update-deps --set-upstream-to gmile/update-deps
$ # (merge & remove branch update-deps on github)
$ hub sync
$ # (only see master branch updated)
After final step, update-deps
is still not removed.
This is what I see in git branch -vv
after modifying the branch to track upstream:
$ git branch -vv
master e807e13 [origin/master] Merge pull request #24 from gmile/update-deps
update-deps 2996ee3 [gmile/update-deps] Include timex_ecto package
$
Was gmile/update-deps
merged and deleted on GitHub? These are the two prerequisites for sync
to delete the local branch.
@mislav I'm having the same problem, but only for branches tracking remotes other than origin
:
$ git init test-hub-sync
$ cd test-hub-sync
$ hub create
$ git commit --allow-empty -m 'Initial commit'
$ git push -u origin master
$ git checkout -b pr-branch
$ git commit --allow-empty -m 'PR branch commit'
$ git push -u origin pr-branch
$ hub pull-request
# merge PR and delete remote pr-branch
$ hub sync
remote: Counting objects: 1, done.
remote: Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
Updated branch master (was fe196f7).
Deleted branch pr-branch (was 7a19ebc).
$ git checkout -b pr-branch-2
$ git commit --allow-empty -m 'PR branch commit 2'
$ git remote add other [email protected]:jawshooah/test-hub-sync.git
$ git push -u other pr-branch-2
$ hub pull-request
# merge PR and delete remote pr-branch-2
$ hub sync
remote: Counting objects: 1, done.
remote: Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
Updated branch master (was 1b8ca48).
@jawshooah sync
currently only fetches from main remote, and ignores other remotes. Should sync
try to fetch from all configured remotes and affect branches that are tracking either of those remotes?
Should sync try to fetch from all configured remotes and affect branches that are tracking either of those remotes?
I think so, yes. I almost always open PRs from my own fork rather than from a branch on the source repo, so it would be very nice if sync
could update branches that track those as well.
Related: how does sync
determine which remote is the "main" remote? Is it just the remote tracked by local master
? What if there is no master
?
It's the first remote named either "upstream", "github", or "origin", in that order. Failing to find any of those, it's the first remote that is reported in the list git remote -v
.
@mislav Was gmile/update-deps merged and deleted on GitHub
Yes, it was. It's weird that hub sync
didn't delete it locally.
@mislav: Should sync try to fetch from all configured remotes and affect branches that are tracking either of those remotes?
That would be good, but I think there's a simpler middle ground here.
I think it would be good if hub sync
follows the "happy path" of hub
: if you don't specify any args, all commands work with the same assumptions e.g. the "same way". As such, I would expect hub pull-request
and hub sync
to work in conjunction. What I'd love to see is this:
hub pull-request
(without arguments) by default creates a fork under my own account (instead of under organization account, e.g. origin
) – we have this,hub sync
(without arguments) by default cleans up branches under (but not limited to) my own account's fork, made using hub pull-request – I'd love to have this.It's weird that
hub sync
didn't delete it locally.
After running hub sync
, does gmile/update-deps
still exist in git branch -r
list? If so, that might be the cause of the problem, because git fetch --prune
(that sync does as a first operation) is supposed to first remove all remote tracking branches that have been deleted in the GitHub repository.
hub sync
(without arguments) by default cleans up branches under (but not limited to) my own account's fork, made using hub pull-request – I'd love to have this.
That's a good suggestion! Right now it doesn't clean up those branches that you submitted through your fork but that got merged in the meantime. It definitely should.
Ah, I just realized that you might have multiple git remotes and that "gmile" is the remote for your fork, while hub sync
will usually just run operations against the "origin" or "upstream" remote. That explains why the gmile/*
branches didn't get cleaned up. I definitely need to think how to implement this feature. Or, you could take a stab at submitting a PR! 😉 But in any case, thanks for the productive discussion.
If you're concerned about accidentally deleting branches that the user may not have wanted to delete, you could add a --prune
option to hub sync
. By default, it wouldn't delete the local branch unless you explicitly ask it to do so.
You could also keep the current behavior of only fetching from the main remote as a default, and fetch from all remotes when given a flag like --all
.