问题
Start a new repo and add some commits:
#( 03/01/17@10:50am )( tim@tim ):~
mkdir test && cd test && git init
Initialised empty Git repository in /home/tim/test/.git/
.
#( 03/01/17@11:17am )( tim@tim ):~/test@master✔
touch readme && git add --all && git commit -am "readme"
[master (root-commit) 1b7f299] readme
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 readme
.
#( 03/01/17@11:17am )( tim@tim ):~/test@master✔
touch howto && git add --all && git commit -am "howto"
[master fd46c4c] howto
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 howto
.
#( 03/01/17@11:19am )( tim@tim ):~/test@master✔
touch la && git add --all && git commit -am "add la"
[master 4680089] add la
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 la
.
#( 03/01/17@11:20am )( tim@tim ):~/test@master✔
ls
howto la readme
#( 03/01/17@11:20am )( tim@tim ):~/test@master✔
echo "hello" >> readme && echo "hello" >> howto
#( 03/01/17@11:20am )( tim@tim ):~/test@master✗✗✗
git commit -am "edit readme and howto"
[master 8969440] edit readme and howto
2 files changed, 2 insertions(+)
So now we have the following commits :
commit 8969440d52e578113f609d948e6ffd06cec96fa9
Author: Tim Richardson <tim@x.com>
Date: Wed Mar 1 11:20:54 2017 +0000
edit readme and howto
commit 4680089c7c1a0ead84f6b2973fd6d9e1356fd5c0
Author: Tim Richardson <tim@x.com>
Date: Wed Mar 1 11:20:06 2017 +0000
add la
commit fd46c4cf593752ec8163d8db21042c8dd336f529
Author: Tim Richardson <tim@x.com>
Date: Wed Mar 1 11:18:09 2017 +0000
howto
commit 1b7f299c5ad4fc50ce4913ab4cdbbdc761db0487
Author: Tim Richardson <tim@x.com>
Date: Wed Mar 1 11:17:50 2017 +0000
readme
lets checkout a new branch called test and reset it to the initial commit:
#( 03/01/17@11:26am )( tim@tim ):~/test@master✔
git checkout -b test
Switched to a new branch 'test'
#( 03/01/17@11:27am )( tim@tim ):~/test@test✔
git reset --hard 1b7f299c5ad4fc50ce4913ab4cdbbdc761db0487
HEAD is now at 1b7f299 readme
If i cherry pick commit 8969440 it fails because it relies on fd46c4c and 1b7f29 but not 4680089:
#( 03/01/17@11:27am )( tim@tim ):~/test@test✔
git cherry-pick 8969440
error: could not apply 8969440... edit readme and howto
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'
however I can cherry pick 4680089c7 from 1b7f299c without any conflicts even though it is not a first degree descendant on the git log:
#( 03/01/17@11:28am )( tim@tim ):~/test@test✗✗✗
git reset --hard
HEAD is now at 1b7f299 readme
#( 03/01/17@12:10pm )( tim@tim ):~/test@test✔
git cherry-pick 4680089c7
[test de3878f] add la
Date: Wed Mar 1 11:20:06 2017 +0000
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 la
So there is a dependency graph between the patches which looks like this:
+---------+
| |
| 1b7f299 +--------+
| | |
+---------+ | +----------+
+----->+ |
| | 8969440 |
+---------+ | | |
| | | +----------+
| fd46c4c +--------+
| |
+---------+
+---------+
| |
| 4680089 |
| |
+---------+
My question is given a larger repo how can I calculate the dependency graph in terms of patches? How can I use git to tell which commits rely on others?
回答1:
The answer to the question in the title, to find the parent(s) of a commit:
git log --pretty=%p <commit>
%P
for the full sha1.
But this is not what you are expecting.
Let's say we have commit A and B in your case, and B relies on A. It's possible that A is the parent of B. Also possible B is many commits ahead of A.
Try to cherry pick B to the current branch (master
for example), and the conflict occurs. Run git status
to see which files have conflicts. Let's say they are foo.c
and bar.c
.
Run git log master..B -- foo.c bar.c
and get a set of commits which touch either foo.c
or bar.c
.
Run git log B..master -- foo.c bar.c
and get another set of commits.
Compare these two sets by commit messages and patches to find the dependency commits in the first set, excluding those that have equivalent commits in the second. Cherry-pick those you really need one by one.
The real case could be more complex. A and B could be related commits of the same bug. To cherry-pick only A or only B results in no conflict, but the bug can not be fixed if you don't cherry-pick both.
If you make a good workflow, for example squashing all the related commits into one, and track each bug/feature with the commits in the very beginning, you could save a lot of time and efforts. It's much easier to find the record and cherry-pick the commits one by one or a squashed commit than to search for the missing dependency commits. There might be conflicts but you can be sure it's not because you miss some of the dependency commits.
回答2:
You can parse the diff to find all regions in the older revision which were changed, and then use git log -L<start>,<end>:file...
(*) to search for commits which have touched this code before. So for any given commit you can search for earlier which it depends on.
I am not sure, however, if it is possible to correctly define the graph as you want it, because the relation "patch B depends on patch A" is not that regular. For example, it is possible to create successive commits A-B-C-D so that when D would depend on A and C, but not B, while C would depend on B, but not A. How would you draw the graph then?
来源:https://stackoverflow.com/questions/42531657/find-the-direct-ancestors-parents-of-a-git-commit