What does the --contains
option do in git for-each-ref
?
Does it only return a reference if its revlist has the commit specified after the --contains
option on the command line? (e.g. Does git for-each-ref refs/heads --contains feature/test
only return those heads that contain the commit feature/test
in their revlist? (i.e. the list of commits between them and the first commit, namely git rev-list <ref>
))?
The Git docs (v. 2.31.1; see here) are actually outdated: the Notes
section at the bottom states you can use the --merged
and --no-merged
options together, but this was made incompatible with this commit.
The definition provided in the docs is ambiguous: it reuses the word "contains" without clarifying what is meant by that. A reference is a name that points to only one SHA. The idea of "contains" suggests a reference refers to multiple commits, which only makes sense in the context of its git rev-list
.
A commit can come after or before another (simply by time of commit), but if it is not reachable from that commit (i.e. if the commit is not merged into its branch), then the commit has no knowledge of it, so it can't be said to "contain" it.
This is why --merged
and --no-merged
together made sense: it would return the commits reachable from (at least one of) --merged
and none of --no-merged
.
What is meant by "contains"?..."has immediate parent X"? "has ancestor X"? "has cousin X"?
UPDATE:
It does seem I was using an older version of Git. Using both --merged
and --no-merged
together was incompatible in v2.28.1, but is now compatible in v2.31.1. Hence, the Git docs are not outdated.
It also seems this commit was made on Mar 21, 2017, so well before v2.31.1 (not sure which version exactly it was committed with).
Second, it does seem @LeGEC's answer makes sense (vis-a-vis --contains
/--no-contains
means "give me refs that have this commit after them" and --merged
/--no-merged
means "give me refs that have this commit before them".
Still, it would be nice if the Git documentation could be given further clarified. Using the word in the definition as they've done is very vague.
Because Git is a Directed Acyclic Graph (DAG), commits point to other commits in linked-list-fashion in one direction: backwards in time towards their ancestors. Hence, the names --merged
/--no-merged
and their description in terms of "reachability" make sense.
Does "contains" mean "after and reachable" (i.e. children), or simply "after" (i.e. commits made later in time)?
Since this is a plumbing command (which are used in custom scripts), I need to know exactly what it does and how it works so that my scripts won't have any unexpected side effects.
Perhaps I misunderstood your question, please update your question if relevant.
The documentation gives a correct (but perhaps succinct ?) description of these options,
here is one way to word it differently :
--merged develop
means "comes before develop
"--no-merged master
means "doesn't come before master
"--contains feature1
means "comes after feature1
"--no-contains feature2
means "doesn't come after feature2
"These 4 options are actually compatible :
git for-each-ref --merged develop --no-merged master --contains feature1 --no-contains feature2
will list references that :
develop
, but not in master
yet,feature1
(e.g : feature1
was somehow merged into them), and doesn't contain feature2
yet[update] a ref points to a commit, and a commit has pointers to its parents. With this relation, commits in git form a graph (a DAG actually).
"merged in" (or my incorrect "comes before") means "is an ancestor of", "contains" (or my incorrect "comes after") means "is a descendant of".
You mention git rev-list
: if git rev-list commitB
lists the sha of commitA
, then you can say :
commitB
contains commitA
commitA
is merged in commitB