1

I wanted to test git branch --contains, so I found a commit from a branch that I had not checked out before, older-branch.

On a different, more current branch (lets call it newer-branch), I did git fetch to make sure I was up-to-date with upstream. Then I did, git branch older-branch --contains COMMITHASH

But this did not return older-branch.

Furthermore, when I did git branch --contains COMMITHASH it showed newer-branch however it did not show older-branch in the list.

Confused, I did git checkout older-branch and then git branch contains older-branch --contains COMMITHASH and it returned older-branch! I then did git branch --contains COMMITHASH and it showed older-branch along with the newer branch that I originally tested out these git commands on!

I then switched back to the newer-branch. This time, when I did git branch older-branch --contains COMMITHASH it showed older-branch! Why is this?

maddie
  • 1,854
  • 4
  • 30
  • 66
  • It looks like some of the commands you're specifying are not standard Git commands. For example, `git contains` and `git older-branch` are not built-in Git commands. You may want to edit your post and make it reflect a standard set of commands. – bk2204 Feb 06 '20 at 17:08
  • @bk2204 you're right! i corrected my post. thank you for pointing this out – maddie Feb 06 '20 at 18:37

1 Answers1

1

Your question is still full of odd-looking constructs like:

git branch contains older-branch --contains COMMITHASH

but I think I understand what you are doing and asking. (Note that a more-focused question could get a more-focused answer.) I think the answer you want is git branch -r --contains. But in case it isn't....

The basic mistake you are making here is thinking that branch names actually mean anything to Git. :-) More specifically, you're assuming that your branch names get updated automatically when some other Git repository updates their branch names.

This is not the case.

When you run git fetch, you have your Git call up some other Git repository somewhere. Typically you will have exactly one other Git repository, which you will call origin. You can, however, list multiple different other Git repositories. You just have to make up a unique name for each one.

Now, suppose the Git repository over at origin, which resides at some URL url, has three branch names: master, develop, and feature. When you run:

$ git clone <url>

you get a Git repository of your own. Your Git repository now knows of another Git repository—the one at url—and has saved that URL under the name origin:

$ git remote
origin
$ git remote show origin
* remote origin
  Fetch URL: ...
  ... lots more stuff ...

The second git remote command here actually called up that other Git to get information from it. Most commands, by far, in Git don't call up any other Git: they only look inside your Git repository.

At this point, your Git repository has only one branch name, almost certainly master.1 If you run git branch to list your branch names, you'll see that one branch.

Does this mean that branches develop and feature don't exist in your repository? The answer to that is both no and yes. The problem is determining what you mean by branch. See also What exactly do we mean by "branch"?

The commits you might care about here do exist. And in fact, some names you might want to use exist too! The names that don't exist are the branch names develop and feature.

If you run:

git branch --contains <hash-id>

you will definitely not see the name develop, because you do not have the name develop.

I did git fetch to make sure I was up-to-date with upstream.

That is the—or a, at least—right thing to do.

... Confused, I did git checkout older-branch and then [git branch --contains worked for me]

This is because git checkout will sometimes create a new branch name.

The key here is once again the ambiguous meaning of the word branch. If you mean branch name, you must have the name. But if you mean something else, well....

Besides branch names, your own Git repository has what I now call remote-tracking names. Git calls them remote-tracking branch names—but they are not branch names at all.

When you run git fetch origin, or a git fetch that uses origin, your Git calls up the Git over at origin. They have a conversation, and your Git will obtain any commits they have, that you don't, that your Git would like to take. Your Git will then update your remote-tracking names.

Your remote-tracking names in this case would be origin/master, origin/develop, and origin/feature. Your Git creates one for every branch name your Git sees in their Git.

These remote-tracking names remember, for you / your Git, that their Git had branch names, and what commit hash IDs those branch names held. A git fetch will update them. (If they've deleted some branch names, you can use git fetch --prune to have your Git delete your corresponding remote-tracking names. Without a pruning option, your Git will hang on to extra remote-tracking names. This prune mode probably should be the default, but for historical reasons, isn't.)

Your branch names are just that: yours. Just because Fred has added, deleted, and changed some of his branch names, that doesn't mean your Git will change yours. If you connect your Git to a remote named fred, your Git will update your fred/* names automatically, because your Fred-tracking names, while yours, are meant for remembering Fred's. The same goes with your origin-tracking names.

When you did git checkout older-branch, though, your git checkout command looked through your branch names. The name older-branch wasn't in there. Rather than just giving up right away and saying: you don't have that branch, your Git went on to look at all of your remote-tracking names.

If you have one remote-tracking name that looks enough like the branch name you asked for, your Git now creates a branch name of your own, corresponding to that remote-tracking name. So if you have origin/older-branch, well, now you do have older-branch. The commit identified by older-branch will be the same commit hash ID that origin/older-branch identifies right now

Now that you do have a branch name, it's up to you to maintain it. It's probably wiser to delete it and use origin/older-branch directly. The git branch command won't list remote-tracking names by default, but with the -r option, that's exactly what it will list. So git branch -r --contains will list those remote-tracking names where the remote-tracking name's commit is a descendant of the commit hash you specify on the command line.


1The other Git gets to say which branch name you get by default, if you didn't get specific in your git clone command about which branch your git clone should create. But unless someone sets it up otherwise, the other Git says I recommend master so that's what you usually get anyway.

torek
  • 448,244
  • 59
  • 642
  • 775