* master: (94 commits)
Fixed update-hook example allow-users format.
Documentation/git-svn: updated design philosophy notes
t/t4014: test "am -3" with mode-only change.
git-commit.sh: Shell script cleanup
preserve executable bits in zip archives
Fix lapsus in builtin-apply.c
git-push: documentation and tests for pushing only branches
git-svnimport: Use separate arguments in the pipe for git-rev-parse
contrib/fast-import: add perl version of simple example
contrib/fast-import: add simple shell example
rev-list --bisect: Bisection "distance" clean up.
rev-list --bisect: Move some bisection code into best_bisection.
rev-list --bisect: Move finding bisection into do_find_bisection.
Document ls-files --with-tree=<tree-ish>
git-commit: partial commit of paths only removed from the index
git-commit: Allow partial commit of file removal.
send-email: make message-id generation a bit more robust
git-apply: fix whitespace stripping
git-gui: Disable native platform text selection in "lists"
apply --index-info: fall back to current index for mode changes
...
@ -4,34 +4,24 @@ A git core tutorial for developers
@@ -4,34 +4,24 @@ A git core tutorial for developers
Introduction
------------
This is trying to be a short tutorial on setting up and using a git
repository, mainly because being hands-on and using explicit examples is
often the best way of explaining what is going on.
This tutorial explains how to use the "core" git programs to set up and
work with a git repository.
In normal life, most people wouldn't use the "core" git programs
directly, but rather script around them to make them more palatable.
Understanding the core git stuff may help some people get those scripts
done, though, and it may also be instructive in helping people
understand what it is that the higher-level helper scripts are actually
doing.
If you just need to use git as a revision control system you may prefer
to start with link:tutorial.html[a tutorial introduction to git] or
link:user-manual.html[the git user manual].
However, an understanding of these low-level tools can be helpful if
you want to understand git's internals.
The core git is often called "plumbing", with the prettier user
interfaces on top of it called "porcelain". You may not want to use the
plumbing directly very often, but it can be good to know what the
plumbing does for when the porcelain isn't flushing.
The material presented here often goes deep describing how things
work internally. If you are mostly interested in using git as a
SCM, you can skip them during your first pass.
[NOTE]
And those "too deep" descriptions are often marked as Note.
[NOTE]
If you are already familiar with another version control system,
like CVS, you may want to take a look at
link:everyday.html[Everyday GIT in 20 commands or so] first
before reading this.
Deeper technical details are often marked as Notes, which you can
skip on your first reading.
Creating a git repository
@ -1686,5 +1676,3 @@ merge two at a time, documenting how you resolved the conflicts,
@@ -1686,5 +1676,3 @@ merge two at a time, documenting how you resolved the conflicts,
and the reason why you preferred changes made in one side over
the other. Otherwise it would make the project history harder
Instead of explicitly specifying which refs to update,
update all refs that locally exist.
update all heads that locally exist.
\--force::
Usually, the command refuses to update a remote ref that
@ -70,7 +70,7 @@ With '--all' flag, all refs that exist locally are transferred to
@@ -70,7 +70,7 @@ With '--all' flag, all refs that exist locally are transferred to
the remote side. You cannot specify any '<ref>' if you use
this flag.
Without '--all' and without any '<ref>', the refs that exist
Without '--all' and without any '<ref>', the heads that exist
both on the local side and on the remote side are updated.
When one or more '<ref>' are specified explicitly, it can be either a
@ -182,7 +182,7 @@ has that commit at all). Since the object name is computed as a hash over the
@@ -182,7 +182,7 @@ has that commit at all). Since the object name is computed as a hash over the
contents of the commit, you are guaranteed that the commit can never change
without its name also changing.
In fact, in <<git-internals>> we shall see that everything stored in git
In fact, in <<git-concepts>> we shall see that everything stored in git
history, including file data and directory contents, is stored in an object
with a name that is a hash of its contents.
@ -2708,190 +2708,202 @@ See gitlink:git-config[1] for more details on the configuration
@@ -2708,190 +2708,202 @@ See gitlink:git-config[1] for more details on the configuration
options mentioned above.
[[git-internals]]
Git internals
=============
[[git-concepts]]
Git concepts
============
Git depends on two fundamental abstractions: the "object database", and
the "current directory cache" aka "index".
Git is built on a small number of simple but powerful ideas. While it
is possible to get things done without understanding them, you will find
git much more intuitive if you do.
We start with the most important, the <<def_object_database,object
database>> and the <<def_index,index>>.
[[the-object-database]]
The Object Database
-------------------
The object database is literally just a content-addressable collection
of objects. All objects are named by their content, which is
approximated by the SHA1 hash of the object itself. Objects may refer
to other objects (by referencing their SHA1 hash), and so you can
build up a hierarchy of objects.
All objects have a statically determined "type" which is
determined at object creation time, and which identifies the format of
the object (i.e. how it is used, and how it can refer to other
objects). There are currently four different object types: "blob",
"tree", "commit", and "tag".
We already saw in <<understanding-commits>> that all commits are stored
under a 40-digit "object name". In fact, all the information needed to
represent the history of a project is stored in objects with such names.
In each case the name is calculated by taking the SHA1 hash of the
contents of the object. The SHA1 hash is a cryptographic hash function.
What that means to us is that it is impossible to find two different
objects with the same name. This has a number of advantages; among
others:
- Git can quickly determine whether two objects are identical or not,
just by comparing names.
- Since object names are computed the same way in ever repository, the
same content stored in two repositories will always be stored under
the same name.
- Git can detect errors when it reads an object, by checking that the
object's name is still the SHA1 hash of its contents.
(See <<object-details>> for the details of the object formatting and
SHA1 calculation.)
There are four different types of objects: "blob", "tree", "commit", and
"tag".
- A <<def_blob_object,"blob" object>> is used to store file data.
- A <<def_tree_object,"tree" object>> is an object that ties one or more
"blob" objects into a directory structure. In addition, a tree object
can refer to other tree objects, thus creating a directory hierarchy.
- A <<def_commit_object,"commit" object>> ties such directory hierarchies
together into a <<def_DAG,directed acyclic graph>> of revisions - each
commit contains the object name of exactly one tree designating the
directory hierarchy at the time of the commit. In addition, a commit
refers to "parent" commit objects that describe the history of how we
arrived at that directory hierarchy.
- A <<def_tag_object,"tag" object>> symbolically identifies and can be
used to sign other objects. It contains the object name and type of
another object, a symbolic name (of course!) and, optionally, a
signature.
A <<def_blob_object,"blob" object>> cannot refer to any other object,
and is, as the name implies, a pure storage object containing some
user data. It is used to actually store the file data, i.e. a blob
object is associated with some particular version of some file.
A <<def_tree_object,"tree" object>> is an object that ties one or more
"blob" objects into a directory structure. In addition, a tree object
can refer to other tree objects, thus creating a directory hierarchy.
A <<def_commit_object,"commit" object>> ties such directory hierarchies
together into a <<def_DAG,directed acyclic graph>> of revisions - each
"commit" is associated with exactly one tree (the directory hierarchy at
the time of the commit). In addition, a "commit" refers to one or more
"parent" commit objects that describe the history of how we arrived at
that directory hierarchy.
As a special case, a commit object with no parents is called the "root"
commit, and is the point of an initial project commit. Each project
must have at least one root, and while you can tie several different
root objects together into one project by creating a commit object which
has two or more separate roots as its ultimate parents, that's probably
just going to confuse people. So aim for the notion of "one root object
per project", even if git itself does not enforce that.
A <<def_tag_object,"tag" object>> symbolically identifies and can be
used to sign other objects. It contains the identifier and type of
another object, a symbolic name (of course!) and, optionally, a
signature.
The object types in some more detail:
Regardless of object type, all objects share the following
characteristics: they are all deflated with zlib, and have a header
that not only specifies their type, but also provides size information
about the data in the object. It's worth noting that the SHA1 hash
that is used to name the object is the hash of the original data
plus this header, so `sha1sum` 'file' does not match the object name
for 'file'.
(Historical note: in the dawn of the age of git the hash
was the sha1 of the 'compressed' object.)
[[commit-object]]
Commit Object
~~~~~~~~~~~~~
As a result, the general consistency of an object can always be tested
independently of the contents or the type of the object: all objects can
be validated by verifying that (a) their hashes match the content of the
file and (b) the object successfully inflates to a stream of bytes that
forms a sequence of <ascii type without space> {plus} <space> {plus} <ascii decimal
As you can see, a tree object contains a list of entries, each with a
mode, object type, SHA1 name, and name, sorted by name. It represents
the contents of a single directory tree.
The object type may be a blob, representing the contents of a file, or
another tree, representing the contents of a subdirectory. Since trees
and blobs, like all other objects, are named by the SHA1 hash of their
contents, two trees have the same SHA1 name if and only if their
contents (including, recursively, the contents of all subdirectories)
are identical. This allows git to quickly determine the differences
between two related tree objects, since it can ignore any entries with
identical object names.
(Note: in the presence of submodules, trees may also have commits as
entries. See gitlink:git-submodule[1] and gitlink:gitmodules.txt[1]
for partial documentation.)
Note that the files all have mode 644 or 755: git actually only pays
attention to the executable bit.
[[blob-object]]
Blob Object
-----------
~~~~~~~~~~~
A "blob" object is nothing but a binary blob of data, and doesn't
refer to anything else. There is no signature or any other
verification of the data, so while the object is consistent (it 'is'
indexed by its sha1 hash, so the data itself is certainly correct), it
has absolutely no other attributes. No name associations, no
permissions. It is purely a blob of data (i.e. normally "file
contents").
You can use gitlink:git-show[1] to examine the contents of a blob; take,
for example, the blob in the entry for "COPYING" from the tree above:
In particular, since the blob is entirely defined by its data, if two
files in a directory tree (or in multiple different versions of the
repository) have the same contents, they will share the same blob
object. The object is totally independent of its location in the
directory tree, and renaming a file does not change the object that
file is associated with in any way.
A blob is typically created when gitlink:git-update-index[1]
is run, and its data can be accessed by gitlink:git-cat-file[1].
------------------------------------------------
$ git show 6ff87c4664
[[tree-object]]
Tree Object
-----------
Note that the only valid version of the GPL as far as this project
is concerned is _this_ particular version of the license (ie v2, not
v2.2 or v3.x or whatever), unless explicitly otherwise stated.
...
------------------------------------------------
The next hierarchical object type is the "tree" object. A tree object
is a list of mode/name/blob data, sorted by name. Alternatively, the
mode data may specify a directory mode, in which case instead of
naming a blob, that name is associated with another TREE object.
Like the "blob" object, a tree object is uniquely determined by the
set contents, and so two separate but identical trees will always
share the exact same object. This is true at all levels, i.e. it's
true for a "leaf" tree (which does not refer to any other trees, only
blobs) as well as for a whole subdirectory.
For that reason a "tree" object is just a pure data abstraction: it
has no history, no signatures, no verification of validity, except
that since the contents are again protected by the hash itself, we can
trust that the tree is immutable and its contents never change.
So you can trust the contents of a tree to be valid, the same way you
can trust the contents of a blob, but you don't know where those
contents 'came' from.
Side note on trees: since a "tree" object is a sorted list of
"filename+content", you can create a diff between two trees without
actually having to unpack two trees. Just ignore all common parts,
and your diff will look right. In other words, you can effectively
(and efficiently) tell the difference between any two random trees by
O(n) where "n" is the size of the difference, rather than the size of
the tree.
Side note 2 on trees: since the name of a "blob" depends entirely and
exclusively on its contents (i.e. there are no names or permissions
involved), you can see trivial renames or permission changes by
noticing that the blob stayed the same. However, renames with data
changes need a smarter "diff" implementation.
A tree is created with gitlink:git-write-tree[1] and
its data can be accessed by gitlink:git-ls-tree[1].
Two trees can be compared with gitlink:git-diff-tree[1].
A "blob" object is nothing but a binary blob of data. It doesn't refer
to anything else or have attributes of any kind.
[[commit-object]]
Commit Object
-------------
Since the blob is entirely defined by its data, if two files in a
directory tree (or in multiple different versions of the repository)
have the same contents, they will share the same blob object. The object
is totally independent of its location in the directory tree, and
renaming a file does not change the object that file is associated with.
The "commit" object is an object that introduces the notion of
history into the picture. In contrast to the other objects, it
doesn't just describe the physical state of a tree, it describes how
we got there, and why.
A "commit" is defined by the tree-object that it results in, the
parent commits (zero, one or more) that led up to that point, and a
comment on what happened. Again, a commit is not trusted per se:
the contents are well-defined and "safe" due to the cryptographically
strong signatures at all levels, but there is no reason to believe
that the tree is "good" or that the merge information makes sense.
The parents do not have to actually have any relationship with the
result, for example.
Note on commits: unlike some SCM's, commits do not contain
rename information or file mode change information. All of that is
implicit in the trees involved (the result tree, and the result trees
of the parents), and describing that makes no sense in this idiotic
file manager.
A commit is created with gitlink:git-commit-tree[1] and
its data can be accessed by gitlink:git-cat-file[1].
Note that any tree or blob object can be examined using
gitlink:git-show[1] with the <revision>:<path> syntax. This can
sometimes be useful for browsing the contents of a tree that is not
currently checked out.
[[trust]]
Trust
-----
~~~~~
An aside on the notion of "trust". Trust is really outside the scope
of "git", but it's worth noting a few things. First off, since
everything is hashed with SHA1, you 'can' trust that an object is
intact and has not been messed with by external sources. So the name
of an object uniquely identifies a known state - just not a state that
you may want to trust.
If you receive the SHA1 name of a blob from one source, and its contents
from another (possibly untrusted) source, you can still trust that those
contents are correct as long as the SHA1 name agrees. This is because
the SHA1 is designed so that it is infeasible to find different contents
that produce the same hash.
Furthermore, since the SHA1 signature of a commit refers to the
SHA1 signatures of the tree it is associated with and the signatures
of the parent, a single named commit specifies uniquely a whole set
of history, with full contents. You can't later fake any step of the
way once you have the name of a commit.
Similarly, you need only trust the SHA1 name of a top-level tree object
to trust the contents of the entire directory that it refers to, and if
you receive the SHA1 name of a commit from a trusted source, then you
can easily verify the entire history of commits reachable through
parents of that commit, and all of those contents of the trees referred
to by those commits.
So to introduce some real trust in the system, the only thing you need
to do is to digitally sign just 'one' special note, which includes the
@ -2908,103 +2920,294 @@ To assist in this, git also provides the tag object...
@@ -2908,103 +2920,294 @@ To assist in this, git also provides the tag object...
[[tag-object]]
Tag Object
----------
~~~~~~~~~~
A tag object contains an object, object type, tag name, the name of the
person ("tagger") who created the tag, and a message, which may contain
a signature, as can be seen using the gitlink:git-cat-file[1]:
------------------------------------------------
$ git cat-file tag v1.5.0
object 437b1b20df4b356c9342dac8d38849f24ef44f27
type commit
tag v1.5.0
tagger Junio C Hamano <junkio@cox.net> 1171411200 +0000
Note that in older documentation you may see the index called the
"current directory cache" or just the "cache". It has three important
properties:
1. The index contains all the information necessary to generate a single
(uniquely determined) tree object.
+
For example, running gitlink:git-commit[1] generates this tree object
from the index, stores it in the object database, and uses it as the
tree object associated with the new commit.
2. The index enables fast comparisons between the tree object it defines
and the working tree.
+
It does this by storing some additional data for each entry (such as
the last modified time). This data is not displayed above, and is not
stored in the created tree object, but it can be used to determine
quickly which files in the working directory differ from what was
stored in the index, and thus save git from having to read all of the
data from such files to look for changes.
3. It can efficiently represent information about merge conflicts
between different tree objects, allowing each pathname to be
associated with sufficient information about the trees involved that
you can create a three-way merge between them.'
you can create a three-way merge between them.
+
We saw in <<conflict-resolution>> that during a merge the index can
store multiple versions of a single file (called "stages"). The third
column in the gitlink:git-ls-files[1] output above is the stage
number, and will take on values other than 0 for files with merge
conflicts.
The index is thus a sort of temporary staging area, which is filled with
a tree which you are in the process of working on.
If you blow the index away entirely, you generally haven't lost any
information as long as you have the name of the tree that it described.
[[low-level-operations]]
Low-level git operations
========================
Many of the higher-level commands were originally implemented as shell
scripts using a smaller core of low-level git commands. These can still
be useful when doing unusual things with git, or just as a way to
understand its inner workings.
[[object-manipulation]]
Object access and manipulation
------------------------------
Those are the ONLY three things that the directory cache does. It's a
cache, and the normal operation is to re-generate it completely from a
known tree object, or update/compare it with a live tree that is being
developed. If you blow the directory cache away entirely, you generally
haven't lost any information as long as you have the name of the tree
that it described.
The gitlink:git-cat-file[1] command can show the contents of any object,
though the higher-level gitlink:git-show[1] is usually more useful.
At the same time, the index is also the staging area for creating
new trees, and creating a new tree always involves a controlled
modification of the index file. In particular, the index file can
have the representation of an intermediate tree that has not yet been
instantiated. So the index can be thought of as a write-back cache,
which can contain dirty information that has not yet been written back
to the backing store.
The gitlink:git-commit-tree[1] command allows constructing commits with
arbitrary parents and trees.
A tree can be created with gitlink:git-write-tree[1] and its data can be
accessed by gitlink:git-ls-tree[1]. Two trees can be compared with
gitlink:git-diff-tree[1].
A tag is created with gitlink:git-mktag[1], and the signature can be
verified by gitlink:git-verify-tag[1], though it is normally simpler to
use gitlink:git-tag[1] for both.
[[the-workflow]]
The Workflow
------------
High-level operations such as gitlink:git-commit[1],
gitlink:git-checkout[1] and git-reset[1] work by moving data between the
working tree, the index, and the object database. Git provides
low-level operations which perform each of these steps individually.
Generally, all "git" operations work on the index file. Some operations
work *purely* on the index file (showing the current state of the
index), but most operations move data to and from the index file. Either
from the database or from the working directory. Thus there are four
main combinations:
index), but most operations move data between the index file and either
the database or the working directory. Thus there are four main
combinations:
[[working-directory-to-index]]
working directory -> index
~~~~~~~~~~~~~~~~~~~~~~~~~~
You update the index with information from the working directory with
the gitlink:git-update-index[1] command. You
generally update the index information by just specifying the filename
you want to update, like so:
The gitlink:git-update-index[1] command updates the index with
information from the working directory. You generally update the
index information by just specifying the filename you want to update,
like so:
-------------------------------------------------
$ git-update-index filename
$ git update-index filename
-------------------------------------------------
but to avoid common mistakes with filename globbing etc, the command
@ -3028,6 +3231,9 @@ stat information. It will 'not' update the object status itself, and
@@ -3028,6 +3231,9 @@ stat information. It will 'not' update the object status itself, and
it will only update the fields that are used to quickly test whether
an object still matches its old backing store object.
The previously introduced gitlink:git-add[1] is just a wrapper for
gitlink:git-update-index[1].
[[index-to-object-database]]
index -> object database
~~~~~~~~~~~~~~~~~~~~~~~~
@ -3035,7 +3241,7 @@ index -> object database
@@ -3035,7 +3241,7 @@ index -> object database
You write your current index file to a "tree" object with the program
-------------------------------------------------
$ git-write-tree
$ git write-tree
-------------------------------------------------
that doesn't come with any options - it will just write out the
(The same is true of "git-fsck" itself, btw - but since
git-fsck never actually *changes* the repository, it just reports
on what it found, git-fsck itself is never "dangerous" to run.
Running it while somebody is actually changing the repository can cause
confusing and scary messages, but it won't actually do anything bad. In
contrast, running "git prune" while somebody is actively changing the
repository is a *BAD* idea).
The structured objects can further have their structure and
connectivity to other objects verified. This is generally done with
the `git-fsck` program, which generates a full dependency graph
of all objects, and verifies their internal consistency (in addition
to just verifying their superficial consistency through the hash).
[[birdview-on-the-source-code]]
A birds-eye view of Git's source code
@ -3926,25 +4023,26 @@ Appendix B: Notes and todo list for this manual
@@ -3926,25 +4023,26 @@ Appendix B: Notes and todo list for this manual
This is a work in progress.
The basic requirements:
- It must be readable in order, from beginning to end, by
someone intelligent with a basic grasp of the UNIX
command line, but without any special knowledge of git. If
necessary, any other prerequisites should be specifically
mentioned as they arise.
- Whenever possible, section headings should clearly describe
the task they explain how to do, in language that requires
no more knowledge than necessary: for example, "importing
patches into a project" rather than "the git-am command"
- It must be readable in order, from beginning to end, by someone
intelligent with a basic grasp of the UNIX command line, but without
any special knowledge of git. If necessary, any other prerequisites
should be specifically mentioned as they arise.
- Whenever possible, section headings should clearly describe the task
they explain how to do, in language that requires no more knowledge
than necessary: for example, "importing patches into a project" rather
than "the git-am command"
Think about how to create a clear chapter dependency graph that will
allow people to get to important topics without necessarily reading
everything in between.
Scan Documentation/ for other stuff left out; in particular:
howto's
some of technical/?
hooks
list of commands in gitlink:git[1]
- howto's
- some of technical/?
- hooks
- list of commands in gitlink:git[1]
Scan email archives for other stuff left out
@ -3973,3 +4071,5 @@ Write a chapter on using plumbing and writing scripts.
@@ -3973,3 +4071,5 @@ Write a chapter on using plumbing and writing scripts.
@ -68,6 +72,7 @@ static int progress = 1;
@@ -68,6 +72,7 @@ static int progress = 1;
static int window = 10;
static uint32_t pack_size_limit;
static int depth = 50;
static int delta_search_threads = 1;
static int pack_to_stdout;
static int num_preferred_base;
static struct progress progress_state;
@ -78,7 +83,6 @@ static unsigned long delta_cache_size = 0;
@@ -78,7 +83,6 @@ static unsigned long delta_cache_size = 0;
static unsigned long max_delta_cache_size = 0;
static unsigned long cache_max_small_delta_size = 1000;
static unsigned long window_memory_usage = 0;
static unsigned long window_memory_limit = 0;
/*
@ -1291,6 +1295,31 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size,
@@ -1291,6 +1295,31 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size,
* We search for deltas _backwards_ in a list sorted by type and
* by size, so that we see progressively smaller and smaller files.
@ -1300,7 +1329,7 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size,
@@ -1300,7 +1329,7 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size,
* one.
*/
static int try_delta(struct unpacked *trg, struct unpacked *src,
@ -188,7 +188,7 @@ static int count_interesting_parents(struct commit *commit)
@@ -188,7 +188,7 @@ static int count_interesting_parents(struct commit *commit)
return count;
}
static inline int halfway(struct commit_list *p, int distance, int nr)
static inline int halfway(struct commit_list *p, int nr)
{
/*
* Don't short-cut something we are not going to return!
@ -201,8 +201,7 @@ static inline int halfway(struct commit_list *p, int distance, int nr)
@@ -201,8 +201,7 @@ static inline int halfway(struct commit_list *p, int distance, int nr)
* 2 and 3 are halfway of 5.
* 3 is halfway of 6 but 2 and 4 are not.
*/
distance *= 2;
switch (distance - nr) {
switch (2 * weight(p) - nr) {
case -1: case 0: case 1:
return 1;
default:
@ -254,6 +253,30 @@ static void show_list(const char *debug, int counted, int nr,
@@ -254,6 +253,30 @@ static void show_list(const char *debug, int counted, int nr,
}
#endif /* DEBUG_BISECT */
static struct commit_list *best_bisection(struct commit_list *list, int nr)
{
struct commit_list *p, *best;
int best_distance = -1;
best = list;
for (p = list; p; p = p->next) {
int distance;
unsigned flags = p->item->object.flags;
if (revs.prune_fn && !(flags & TREECHANGE))
continue;
distance = weight(p);
if (nr - distance < distance)
distance = nr - distance;
if (distance > best_distance) {
best = p;
best_distance = distance;
}
}
return best;
}
/*
* zero or positive weight is the number of interesting commits it can
* reach, including itself. Especially, weight = 0 means it does not
@ -267,39 +290,12 @@ static void show_list(const char *debug, int counted, int nr,
@@ -267,39 +290,12 @@ static void show_list(const char *debug, int counted, int nr,
* unknown. After running count_distance() first, they will get zero
@ -35,7 +35,7 @@ static int run_gpg_verify(const char *buf, unsigned long size, int verbose)
@@ -35,7 +35,7 @@ static int run_gpg_verify(const char *buf, unsigned long size, int verbose)
@ -97,6 +97,21 @@ if there is already one that displays the same directory."
@@ -97,6 +97,21 @@ if there is already one that displays the same directory."
@ -40,4 +40,18 @@ test_expect_success '--cherry-pick bar does not come up empty' '
@@ -40,4 +40,18 @@ test_expect_success '--cherry-pick bar does not come up empty' '
! test -z "$(git rev-list --left-right --cherry-pick B...C -- bar)"
'
test_expect_success '--cherry-pick with independent, but identical branches' '
git symbolic-ref HEAD refs/heads/independent &&
rm .git/index &&
echo Hallo > foo &&
git add foo &&
test_tick &&
git commit -m "independent" &&
echo Bello > foo &&
test_tick &&
git commit -m "independent, too" foo &&
test -z "$(git rev-list --left-right --cherry-pick \