Home > Software engineering >  Stop git from merging branch_a into current when pulling remote/branch_a into branch_a
Stop git from merging branch_a into current when pulling remote/branch_a into branch_a

Time:06-23

I am writing a script to update all of our repositories to the latest code on our main develop branch. It's basically:

git -C ./$project pull origin develop:develop

I cannot be sure that the person running the script isn't actively working on a feature branch, nor can I guarantee that the branch they are on is branched from develop. Therefore I wish to ONLY pull origin/develop into develop and nothing else. No more actions.

Currently when doing this, git pulls develop into develop and then tries to merge develop into the current branch. I don't want this last step. I scoured the docs for pull and fetch and didn't find anything that could help. Is there a way to do this without having to manually check if theres changes, stash, pop, etc.

CodePudding user response:

TL;DR

Don't do this at all. Have people use origin/develop directly. Teach them how and why. All they need to do then is use git fetch.

Failing that, use git fetch origin develop:develop and be prepared for some people to have a problem.

Long

git pull literally means:

  1. run git fetch; then
  2. run a second Git command.

You can choose whether the second command is git merge or git rebase but either way you'll affect the current branch based on what you git fetch-ed in step 1.

Based on your comment here:

... what i've got, git pull origin develop:develop and that does in fact pull develop into develop while i'm on feature/something. However, git THEN tries to merge develop into feature/something ...

Technically, git pull origin develop:develop does not pull their (origin's) develop into your (local) develop, because pull means fetch second command. All it does is fetch their develop into your develop—and that gives you an answer:

git fetch origin develop:develop

Remember that most1 git pull arguments are passed directly to git fetch. It's that first command that is doing all the work here! So just invoke it. But there are some issues here, so read on.


1The exceptions here are:

  • options that are specific to the second command, and
  • options that are "eaten" by git pull itself, such as the one to specify which second command to use.

What could go wrong?

The git fetch command means:

  • Call up some other Git repository (in this case origin), using the URL stored under a remote: a short name for some other Git repository. A remote, like origin, is just a name under which Git can store some information:

    • a URL for fetch and/or push (you can have a different push URL);
    • some defaults and/or magic for fetch and/or push;
    • other (unspecified: Git reserves the right to add new stuff in the future).
  • Have them list out their branch and tag names and the commits that go with these;

  • download new commits if / as needed / desired; and

  • based on the earlier steps, update any remote-tracking names (origin/* names in this case) as directed by some of the magic settings stored in under the remote's name.

To do this, git fetch needs the name of a remote, like origin. You can run it with one:

git fetch origin

or without:

git fetch

If you run it without one, Git will guess which remote to use. If you have only one remote—which is the typical case; most repositories just have one remote named origin—that's the one Git will guess and therefore use, so you can run git fetch with no arguments at all.

Having added a remote name, however, as in git fetch origin, you can then go on to list branch names as they're seen in the remote:

git fetch origin develop

for instance. When you do this, you're telling your Git software that, although their Git may list out a dozen, or a million, branch names, you're only interested in updating one, namely develop. That is, you want your origin/develop updated, based on their develop, and you're willing to skip updating all other origin/* names.2 Or you could run:

git fetch origin br1 br2 br7

and thereby update your origin/br1, your origin/br2, and your origin/br7.

Each of these additional arguments—which absolutely require the origin in front because they have to come after a remote; the first argument will be assumed to be a remote: git fetch br1 develop means "fetch develop from remote br1" whether or not br1 is a branch name—is what git fetch calls a refspec. It's a very simple kind of refspec, because a full refspec is made up of four parts:

  • an optional leading plus sign ;
  • a left hand name, such as develop;
  • a right hand name, such as develop; and
  • a separator colon (:) character that splits the left and right sides.

You get to omit the separator when you're writing just a left-side name, hence git fetch origin develop works fine. If you're going to provide a right-side name, though, you must include the colon.

When we do use the colon here, that tells git fetch that it should attempt to create or update one of our names, in our repository. This may fail. In particular it will fail if develop is the current branch, and in several other cases. Hence:

git fetch origin develop

will work,3 but:

git fetch origin develop:develop

might fail. So we need to handle the failure cases, or find an even-better way to deal with this.

There's another problem that occurs when develop is the current branch in any added working tree from git worktree add, and many versions of Git (from the point git worktree add was added in Git 2.5 until Git 2.35 was released) fail to detect this. We'll touch on this later, but let's look at the issues with updating the local branch name develop in the normal (main) working tree first.


2The usual reason to do this here is to make this git fetch go faster. This will probably make the next git fetch that fetches everything—the default—slower, since that one now has more to fetch. So it's a "pay me now or pay me later" situation, and, as it turns out, paying now is often actually cheaper than paying later, as the total cost is often lower (reduced overhead plus, sometimes, better compression). But not always—and "when to pay" is something you get to decide for yourself.

3If your network is down, or there's no develop on origin, git fetch origin can fail too. But in these two cases we can't get anything at all done here, so we don't have to worry about them.

  •  Tags:  
  • git
  • Related