28

In our GitHub repository, a coworker removed a branch named release. But when I run git checkout release locally, I always get the removed branch release. Same, even when I checked out another branch, deleted the release branch with git branch -D release and ran again git checkout release.

Is there something to fix on the GitHub repository, or shall I fix something locally?

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
Tim
  • 101,790
  • 1
    What does git branch --remote output, after running git fetch? You might need to prune with git fetch -p to forget deleted remote branches. – Stephen Kitt May 18 '17 at 14:33
  • 2
    If that branch was ever pushed to GitHub, and you pulled after that, then you have a copy of the branch too. Every git repository is complete in and of itself, unless you used a shallow clone or something. – muru May 18 '17 at 14:51
  • @StephenKitt: Thanks. git branch --remote output origin/release. Do you mean to run git fetch -p without additional arguments, and will it prune all the deleted remote branches? – Tim May 18 '17 at 14:54
  • 1
    Yes, git fetch -p with no additional arguments will prune all the deleted remote branches. – Stephen Kitt May 18 '17 at 15:07
  • @StephenKitt: Do git fetch -p and git push origin :release in rudimeier's reply both forget deleted remote branches, except the former prune all and the latter prune the specified branch? – Tim May 18 '17 at 15:11
  • @Tim git push origin :release would do what your coworker probably already did. git fetch -p is similar to git remote prune origin in my answer. – rudimeier May 18 '17 at 15:20
  • @rudimeier does git push origin :release delete the release branch on GitHub, which I mentioned my coworker already deleted? Do git fetch -p and git remote prune origin clean up the tracking info within my local repository for release branch? – Tim May 18 '17 at 15:26
  • Yes, git push origin :release deletes the remote branch. It’s not really a good idea in this case, since (a) your colleague has already done that (possibly via the GitHub UI), and (b) if anyone else adds a new branch with the same name on the server, you’ll delete that new branch... – Stephen Kitt May 18 '17 at 15:27
  • that's exactly why people shouldn't be allowed to go around and change history. – njzk2 May 18 '17 at 18:41
  • What do you suggest instead? @njzk2 – Tim May 18 '17 at 18:43
  • 1
    Welcome to the world of distributed version control! – chrylis -cautiouslyoptimistic- May 18 '17 at 22:24

4 Answers4

28

After deleting a branch on the remote side you may still see this formerly fetched remote branch locally, see:

$ git branch -a
[...]
release
remotes/origin/release
[...]

You only removed the "release" but not "remotes/origin/release". Delete it like this:

$ git branch -rd origin/release

Or remove all fetched branches which do not exist on the remote side anymore:

$ git remote prune origin 
rudimeier
  • 10,315
  • Thanks. In git branch -rd origin/release, what does -r mean? Does -d mean the same as -D? Can git branch -rd origin/release be replaced with git branch -d remotes/origin/release? – Tim May 18 '17 at 19:23
  • @Tim: From the manual; -r: List or delete (if used with -d) the remote-tracking branches.; -D: Shortcut for --delete --force. – looper May 18 '17 at 20:00
  • Thanks. Can git branch -rd origin/release be replaced with git branch -d remotes/origin/release? – Tim May 18 '17 at 20:06
  • @Tim no -r refers to remote branches, it's needed. The local and remote branches are stored in different directories, compare ls -l .git/refs/heads and ls -l .git/refs/remotes. You could also have a local branch called remotes/origin/release which would be delete without -r. This might sound confusing but you could just play around, create branches with strange names and look how does it look in .git/. – rudimeier May 18 '17 at 21:15
15

When branches are deleted remotely, you need to prune your local repository — the easiest way to do this is with

git fetch -p

This will update your local repository with all the changes made to the remote repository, but without updating any of your local branches. After running this,

git branch --remote

will no longer show the deleted remote branch.

git repositories are complete, whether on your own system or on the server. So when you first clone a repository, you get a complete copy, and your local git “knows” about all the remote branches as well as your local branches. This information isn’t synced automatically, so when your colleague deleted the release branch on the server, your local git repository didn’t lose its notion of a remote release branch. Syncing with git fetch updates all the local information on remote branches so they match the state on the server (strictly speaking, remote repository, wherever that is), but without deleting any local information on remote branches. Pruning with git fetch -p (or git fetch --prune, or git remote prune) removes the local information on remote branches which have been deleted.

Stephen Kitt
  • 434,908
  • Thanks. "update your local repository with all the changes made to the remote repository, but without updating any of your local branches". What update is that, given that it is not update of my local branches? – Tim May 18 '17 at 15:27
  • It’s all the remote updates. Your local git repository distinguishes your local branches and the remote branches, but remote branches aren’t magically synced with the server — they exist locally too (as in, stored in your local git repository). Fetching syncs your local repository with the remote repository, and updates the state of remote branches; by default deleted remote branches aren’t removed from the local information on remote branches, -p (--prune) forces that. – Stephen Kitt May 18 '17 at 15:31
  • Thanks. Why didn't deleting the release branch by git branch -D release before git checkout release make git checkout release stop getting the release branch? – Tim May 18 '17 at 17:05
  • 1
    Because git checkout release will automatically re-create a branch if there is a remote branch with that name. – Stephen Kitt May 18 '17 at 17:07
  • By "remote branch", do you mean a branch in my local repository or Github repository? If former, git branch -D release has already deleted the release branch in my local repository; If latter, a coworker has deleted the release branch on GitHub; So i am still not sure why "will automatically re-create a branch if there is a remote branch with that name"? – Tim May 18 '17 at 17:10
  • I mean a remote branch as stored in your local repository. You need to understand that there are three sets of branches: your local branches, the remote branches stored in your local repository, and the branches in the remote repository. git branch -D release updates the local branches, your colleague updated the branches in the remote repository, but the middle set stayed the same (and still had release). – Stephen Kitt May 18 '17 at 17:12
  • (1) Did git branch -D release already delete the release branch in my local repository, so there is no remote branch with that name release in my local repository, so git checkout release willnote automatically re-create a branch release? (2) Since both GitHub and my local rep already don't have a branch named release,from where can git checkout release recreate a branch release ? – Tim May 18 '17 at 17:17
  • No. git branch -D release deleted your local branch, it didn’t delete the remote branch that git knows about in your local repository. There is a remote branch with that name in your local repository. There are three sets of branches, you only updated two of them. – Stephen Kitt May 18 '17 at 17:18
3

Tim: Git is distributed VCS, so when you clone a repo from remote to your local it clones everything (history). So when you cloned your repo, it had a branch called release. Since your colleague deleted release branch remotely, till you do a prune git fetch -p or delete that branch explicitly your local will have that branch.

ManiVI
  • 131
1

Perhaps a bit tangential but the perspective of this site might help to understand the general topic of deleting branches:

http://railsware.com/blog/2014/08/11/git-housekeeping-tutorial-clean-up-outdated-branches-in-local-and-remote-repositories/

There is overlap with some of what's already been discussed here but the focus is on housekeeping: deleting branches, remote and local, that are no longer needed in a collaborative environment. In particular the git branch --merged command identifies branches that are safe to delete due to being merged to your mainline (or whatever branch you care about). If you're collaborating, some fancier mini scripts like this one will present things in a nice, digestible format with dates and authors.

for branch in `comm -12  <(git branch --merged|awk '{print($1)}') <(git branch -r --merged|awk '{print($1)}'|awk -F \/ '{print($2)}')`; do echo -e `git show --format="%ci %cr %an" $branch | head -n 1` \\t$branch; done | sort -r

(Unfortunately "nice, digestible" doesn't apply to the formatting of the scripts themselves.)

B Layer
  • 5,171