0

I need to git pull all branches from a remote repository, but I want to exclude one particular branch. This is my attempt, based on what I read at https://git-scm.com/docs/git-pull , looking at the part, on excluding branches:

$ git ls-remote | grep Bad-branch
From git@gitlab.mycompany.com:analytics/path/repo.git
181647289762f00110d67199adec2559a5dbbbe6        refs/heads/Bad-branch

$ git pull origin ^refs/heads/Bad-branch
There are no candidates for merging among the refs that you just fetched.
Generally this means that you provided a wildcard refspec which had no
matches on the remote end.

That is not working, as you can see. How can I specify a branch to exclude?

I also referenced these posts, but I don't want to modify a config file, just a temporary command line specification to ignore the branch until it is removed.

EDIT: For clarity, here is the actual git call that breaks, because I'm on Windows and the path name that gets generated from the branch name gives a filename that is too long:

$ git pull
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 2), reused 3 (delta 2), pack-reused 0
Unpacking objects: 100% (3/3), 384 bytes | 16.00 KiB/s, done.
error: cannot lock ref 'refs/remotes/origin/TCCFOUR-19049-Algo-ProductionModuleLowDeltaT.R-distribution.supply.temperature.in.control.exception-displayed-as-YesNo-in-RDR-but-TrueFalse-in-analytic': Unable to create 'C:/Users/IRINZN/work/projects/analytic-r-docker-setup/analytic-r-cc4-algorithms/.git/refs/remotes/origin/TCCFOUR-19049-Algo-ProductionModuleLowDeltaT.R-distribution.supply.temperature.in.control.exception-displayed-as-YesNo-in-RDR-but-TrueFalse-in-analytic.lock': Filename too long
mpettis
  • 3,222
  • 4
  • 28
  • 35
  • How many branches are we talking about? – Scott Hunter Jun 17 '21 at 19:19
  • @ScottHunter one branch only in this case. The problem is that someone made a too-long branch name that is too long for windows paths (but ok on Linux/BSD systems). While I wait for the author to delete it, I want to be able to sync my repository. – mpettis Jun 17 '21 at 20:08
  • @matt Well my normal workflow is to do a pull, and now that is breaking. I thought I could modify my pull request to not break. The git-pull documentation references the ability to exclude refspecs. But if I really just have to fetch rather than pull, and can exclude on fetch calls, I'll take a solution like that. – mpettis Jun 17 '21 at 20:09
  • But the point is that with fetch you don't need to exclude anything, as it has no effect whatever on "your" files (the files in your local branches). So no problem. I'm having trouble grasping what actual problem you think you _do_ have. Of course maybe I'm just being slow. – matt Jun 17 '21 at 20:11
  • @matt no I appreciate the help. I'm not an advanced git-er, so what I do is probably not canonical. Simply, I am usually on master, which I want to usually pull updates to, so I do git pull. When I do this, new branches are coming along for the ride and get fetch-ed, it seems. This bad branch is one of those branches, and it breaks my normal pull of master when I just issue `git pull`. Perhaps I can avoid that with a more precise call, but that is the problem I'm having. I'll update the question with what happens when I do a `git pull`. – mpettis Jun 17 '21 at 20:16
  • 1
    Get your colleague to create a shorter branch name and then delete the long one, and then chastise him or her for not knowing the difference between your issue tracker and git branches. You can write an essay in the issue tracker, the branch names should be concise and to the point, you do not need to write the full justification for the branch in its name. Also you can run `git config --system core.longpaths true` which tells git to try to use longer filepaths, but still, that branch name is bogus. – Lasse V. Karlsen Jun 17 '21 at 20:29
  • @LasseV.Karlsen between when I wrote this question and this answer now, the colleague has deleted that branch, and I did tell him it was unnecessary (the ticket identifier is enough for the branch name). So my immediate problem is gone. But I think it would still be helpful to know how to do this if it pops up again. – mpettis Jun 17 '21 at 20:36

2 Answers2

3

Your final edit is pretty important.

The fact that Git has a poorly implemented database for branch names and tag names and remote-tracking names and so on, combined with file name length limits on Windows, is what led to the problem. It's not related to git pull at all, but rather to the way Git handles creation and update of remote-tracking names (refs/remotes/origin/TCCFOUR-19049-Algo-ProductionModul...). So, what you want to do, temporarily, while the ridiculous branch name exists in the other repository and is causing these problems, is avoid asking your own Git to create this remote-tracking name.

The simplest method is to run git fetch or git pull with a refspec1 that limits the git fetch action:

git fetch origin foobranch

for instance, if you want to update refs/remotes/origin/foobranch. When that completes, you can run:

git merge origin/foobranch

or:

git rebase origin/foobranch

as appropriate. Should you wish to do both of these in rapid sequence without inspecting the git fetch result first, you can use the convenience git pull command:

git pull origin foobranch

which will run:

git fetch origin foobranch

(fetching just the one named branch and updating your corresponding origin/ name) followed by the git merge or git rebase that you have configured as your default second-command for git pull.


1Refspec is a technical term. Here, it translates, rather roughly, as "branch name", but that's an enormous oversimplification. But let's not bother with the details here, and leave that for other answers.


Side notes

I generally prefer to run these as two separate commands, both for sanity—otherwise you're left wondering why one is foobranch and one is origin/foobranch—and for the ability to run other Git commands between the fetch and the final command.

If you're still wondering why one is foobranch and the other is origin/foobranch, git fetch itself is the reason: when you run git fetch origin, you are telling your Git call up some other Git at the URL I stored under the name origin. Your Git has their Git, which is connected to their Git repository, list out their branch names. They have their own branch names, because every Git repository has its own branch names. Your branch names are not their branch names. You and they share commits, but not branch names.

Anyway, once they have listed out all their branch names, your Git now has an opportunity to get the commits, so that you and they can share them. So your Git goes through the commits that are on their branches to see whether you have them already. (Remember that one commit can be on many branches, so even if they have a thousand new branches, you could have all of the commits already!) Your Git then obtains any new commits you'll need, first. Then, having gotten all the commits, your Git takes each of their branch names and creates or updates a corresponding remote-tracking name in your own repository. Your Git does this by sticking origin/ in front of each branch name.

When you run git fetch origin, you're telling your Git: Get me all of their commits and branches. When you run git fetch origin foobranch, you're telling your Git: Look at all their branches, but only get me updates for foobranch. So this limits your fetch to just those commits needed to update your origin/foobranch.

Once the fetch is done and has quit, you'll refer to their latest commit using your name, origin/foobranch, rather than their name, foobranch. Should you wish to call one of your own branches foobranch too, that's your business: they don't care what names you use. You probably do care what names you use, and use the same names they use on purpose. But that's not something they need to care about. That's something you do.

torek
  • 448,244
  • 59
  • 642
  • 775
  • This was way more helpful to me than what I asked for in the scope of my original question. I understand the structure of git much better from this answer. – mpettis Jun 19 '21 at 04:15
2

You can update only a single branch with a git pull origin <branch-name>

However, if you are needing to know about new branches this won't work and I don't know of a way to exclude that. You will need to have the branch removed.

git pull is a combination of two commands. git fetch and git merge. git fetch goes to the remote and checks to see that status of your existing remote branches and if any new ones exist. This is where your command is breaking as git is trying to create a local status of this new remote branch. If you do git branch -r you will see a list of all the remote branches that your local knows about.

Schleis
  • 41,516
  • 7
  • 68
  • 87
  • A part of git I don't understand... If I do a `git pull` while on the master branch, why is it attempting to pull down that other branch, as opposed to just pulling down master updates? – mpettis Jun 17 '21 at 20:33
  • 1
    @mpettis added an update to the answer that explains what is happening. Hopefully that helps – Schleis Jun 17 '21 at 20:41
  • very helpful, thanks. So both pull and fetch should break, I believe. So the original question remains as to whether or not I can exclude checking/fetching a list of remote branches. It would seem like a list like that could be supplied as a command line option, and the git-pull spec talks about how to exclude refspecs, but I must be interpreting something about it wrong... – mpettis Jun 17 '21 at 21:05
  • 1
    @mpettis from what I can tell, no you can't exclude branches however based on your comments of the workflow if you want to update a specific branch you can use the command in my answer. You should also be able to get a specific branch but you won't be able to discover new branches – Schleis Jun 17 '21 at 21:43