Reputation: 1039
If you commit a file(s) to multiple branches, how can you look up which branches that commit is a part of?
Upvotes: 0
Views: 610
Reputation: 487755
The answer might be git branch --contains
, but the question is not well formed.
In Git, a commit is a complete snapshot of every file. More precisely, each commit identifies what Git calls a tree object, and the tree itself lists file names, their modes (100644 or 100755), and what Git calls a blob hash ID—the "true name" of the file stored in Git's internal database, by which Git can extract the file's data. (Each tree can also list sub-trees, which then list more file names and so on.)
A commit also has a hash ID. This hash ID is unique: it identifies that one particular commit. But 2512f15446149235156528dafbe75930c712b29e
is not exactly useful to humans; we like nice names like v2.16.0
. So Git allows us to use branch and/or tag names to identify one specific commit.
Every commit can also list additional commit hash IDs, and most list exactly one such hash ID. These are the commit's parent commits. When the commit we call v2.16.0
has exactly one parent (e0d575025a80c83c3eaec82a217714610f0ab115
, in fact), it means that commit 2512f15...
comes after e0d57502...
in history—or in Git's terms, history is that 2512f15...
is immediately preceded by e0d57502...
. If we start at the later commit, we can move back in time to look at the earlier one. If we compare the two saved snapshots, we'll see what changed in that time period:
$ git show 2512f15446149235156528dafbe75930c712b29e
commit 2512f15446149235156528dafbe75930c712b29e (tag: v2.16.0)
Author: Junio C Hamano ... [snippage]
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 258aff35c..e4c858d35 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.16.0-rc2
+DEF_VER=v2.16.0
LF='
'
Meanwhile, a branch name like master
simply identifies one specific commit:
$ git rev-parse master
5be1f00a9a701532232f57958efab4be8c959a29
If we start at this commit and work backwards through time, following each commit to its parent commit(s), perhaps we will reach commit 2512f15446149235156528dafbe75930c712b29e
:
$ git branch --contains 2512f15446149235156528dafbe75930c712b29e
* master
and yes, in fact, master
(commit 5be1f00...
) does eventually reach back to 2512f15...
.
So, one possible answer to your question is to use git branch --contains
: give it a commit hash ID, and it will tell you every branch name that, if Git starts from the commit to which that branch name points and works backwards, eventually leads to that particular commit.
But there's a problem: you phrased this as:
If you commit a file(s) to multiple branches ...
and when you run git commit
, what Git does is to create a new commit. The new-commit-creation process makes a new commit, which clearly does not—at least not yet—exist on any branch:
$ git write-tree
8ccb7d4fa49449a843b00aca64baf99feb10e2ab
This is a new tree made from the index: it's the snapshot for the new commit.
$ git commit-tree -p HEAD -m message 8ccb7d4fa49449a843b00aca64baf99feb10e2ab
aa123a5b9d43186143b6e43cfeca434a67bab9f3
$ git cat-file -p aa123a5b9d43186143b6e43cfeca434a67bab9f3 | sed 's/@/ /'
tree 8ccb7d4fa49449a843b00aca64baf99feb10e2ab
parent 5be1f00a9a701532232f57958efab4be8c959a29
author Chris Torek <chris.torek gmail.com> 1518104686 -0800
committer Chris Torek <chris.torek gmail.com> 1518104686 -0800
message
$ git branch --contains aa123a5b9d43186143b6e43cfeca434a67bab9f3
$
So no branch contains this new commit, yet. But when we use the normal way to make commits (rather than git write-tree
and git commit-tree
), the last step is that git commit
itself changes the current branch—in my case, master
—so that the current branch name points to the new commit just made.
This means that if I were to run:
$ git add somefile
$ git commit
I'd get a new commit that has, as its snapshot, everything in the index right now plus the added file somefile
. Git would make my master
branch point to this one new commit I just added. Since the commit is new, no other branch could possibly lead back to this new commit. Hence only one branch can contain it, that being the branch I'm on right now.
Hence:
how can you look up which branches that commit is a part of?
If you've only just now made the commit, that one single commit is only on one branch: it's on the branch you are on right now. And this conflicts with the conditional part of the question:
If you commit a file(s) to multiple branches ...
The (single) commit C is only "on" the one branch you were on when you made it. You didn't really commit the file to a branch, you committed the file to a commit (well, that's kind of vacuous, but true enough) and then added the commit to the branch.
Later, you might have moved other branch names—perhaps via git merge
or git reset
commands—and/or created additional new branch names that either point to commit C, or have commit C in their history (as formed by following their actual head commit parent hash IDs). It's at that time that you can find multiple branch names that contain commit C.
Or, you could be asking an entirely different question, such as: "If I have some number of commits that have, in their stored trees, a file whose path is P, and I have other commits where there is no file with path P, how can I find all the commits reachable from all current branch heads in which the stored commit has a file whose path is P?" In this case the answer is not git branch --contains
, but that's not the question I have answered.
Upvotes: 2