Regarding the edit:
git log --graph --decorate (perhaps with
--oneline) and either
--all (all branches, tags, etc), or name the branches you care about. Note that branch names (labels) can be deleted or moved at any time, though, so you can't count on the names sticking around.
Until the branch labels are moved or deleted, though, you can see which ones are "merged" (point to or below a given commit-ID) with
git branch --contains and
git branch --merged. For instance, given a commit graph that looks like this, with four branch labels as shown denoting commits
G <-- br1
A--B--C--D---H <-- br2
\ \ /
\ F--/ <-- br3
E <-- br4
you can run, e.g.:
git branch --contains br1^ # br1^ identifies commit `D`
to see "branches whose tip commits are descendents of the named commit". Those are
br2. In other words, starting at
G, we can walk backwards and reach
D; and starting at
H, we can walk backwards and reach
D. However, starting at
br3, walking backwards does not reach
D, and starting at
br4, walking backwards also does not reach
You can also run:
git branch --merged br2 # br2 identifies commit H
which (as the documentation notes) finds "branches whose tip commits are reachable from the named commit". This prints
br3. We start at
H and walk all backwards paths.
H itself is identified by label
br2, so this prints
br2. Then we walk its parents;
H has three:
F (one of these is the "first" parent, but the graph shown here does not tell us which one, and for
git branch --merged git does not care anyway). Commit
G is the commit identified by the name
br1, so this prints
D is not identified by anything. Commit
F is identified by
br3. We also check the parents of
F: these are
A and then there are no more parents. In this case they all have no labels (but if we were to add one pointing to, say, commit
git branch --merged would print that label as well).
(There is also
git branch --no-merged which, applied to commit
H, would print
br4 in this case. It's just the inverse of
--merged: print branch labels if they point to a commit that is not reachable from the given starting point.)
Branches don't actually have parent/child relationships (although you can read them into existence if you like—but the point here is that you have to invent them, as it were, from the graph). Moreover, the command sequence you suggest results in nothing happening.
Let me get more specific, because "branch" can refer to two different concepts. There's the chain of commits formed by the commit directed-graph, and there's the branch name that actually provides the "tip" of some branch, such
C--D--E <-- experiment
A--B--F--G <-- master
H--I <-- feature
The branch that the name
experiment points to ends with the tip commit
E. The branch consists of commits
E. The branch names the (single) commit
E. But we also talk about "the branch" as being
Meanwhile, the branch that the name
master points to ends with the tip commit
G. The branch consists of
G; but the branch just names
G. As before, "the branch" means two different things, depending on what we want it to mean: the tip, or the line formed by starting at the tip and working backwards.
That said, if you're "on" branch
master and do two
git checkout -b commands, that creates two new branch labels. By default those labels point to the same commit as
master. So if you start with this:
A--B--F--G <-- HEAD=master
and you run:
$ git checkout -b br1
Switched to a new branch 'br1'
$ git checkout -b br2
Switched to a new branch 'br2'
then you now have:
A--B--F--G <-- master, br1, HEAD=br2
All three labels point to the same tip commit (
G, in this case). Use
git log --decorate to see the labels. (I like to use
git log --oneline --graph --decorate, with or without
--all as well, as needed. Also, I put the
HEAD= in the above diagrams to tell you which branch you're "on".)
If you then attempt the sequence:
$ git checkout master
Switched to branch 'master'
$ git merge br1 --no-ff
you get a complaint, of sorts:
Because of this, nothing has happened.
br1 into something you can merge, by adding an empty commit to it:
$ git checkout br1
Switched to branch 'br1'
$ git commit --allow-empty -m 'empty commit'
[br1 add230d] empty commit
The graph now looks like this (I'm ignoring
feature here, and arbitrarily drawing
A--B--F--G <-- master, br2
J <-- HEAD=br1
(because the newly added commit causes the label
br1 to move to point to it).
Now it's possible to go back to
master and do a merge:
$ git checkout master
Switched to branch 'master'
This first step just moves the
A--B--F--G <-- HEAD=master, br2
J <-- br1
The next step creates a merge commit:
$ git merge --no-ff br1 -m 'merge br1'
Merge made by the 'recursive' strategy.
merge adds a new commit with two parents, to whichever branch
HEAD points to, which is
master. The label
master moves to point to the new commit, as usual. This makes it a little harder to show where
br2 points, so I'll draw a much longer ASCII arrow:
A--B--F--G---K <-- HEAD=master
J <-- HEAD=br1
Note that branch
br2 ends with
G. This is the tip of branch
G is a "tip" commit, even though it's also a parent of merge-commit
There are a bunch of key take-away messages here:
- Branch names (which we sometimes call "a branch") provide the tip of a branch.
Branches themselves are formed by the commit graph, and run as long (or short) as we want when we interpret them. After merging something in you can think of the branch as just the part that "sticks out", i.e., the stuff along the top after
B--C---o--M--o "main line"
or you can think of it as the entire thing all the way back, including commits
- Adding a new commit always results in some branch label moving forward. Normally
HEAD names a branch, and that branch label is what moves forward. (With a "detached HEAD", the
HEAD file gives a raw commit SHA-1, and
HEAD itself is modified to contain the new raw commit SHA-1.)
- A merge just creates a new commit that has two (or more) parents, like
M above. It is not possible to merge a commit with itself, as a merge commit must have at least two distinct parent commits (that's what makes it a merge commit!).
Not shown above, but also a key concept: the "first parent" of the merge is the commit that was "on the branch" before the merge (assuming
HEAD named a branch), and all other parents are the commits that were "merged in". Git itself does not really care which way a merge is done—the labels can be changed or erased—but this allows you (the user) to leave a bread-crumb trail, for yourself or anyone else who comes in later to see what was done.