Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
174 views
in Technique[技术] by (71.8m points)

Git log graph but only some branches

I want to do something that Gitk already does, except in the command line. I want to display all the commits from one branch, plus all commits from another branch, but no other history. Let's be more specific : I am talking about a feature branch plus the main branch, but no other stuff (however much else there is). How to achieve this ?

By "Commit from a branch" I mean a commit that was explicitly committed (and pushed) on the branch, not one that was brought by a merge. It is enough for me to see that a commit is actually a merge, as I expect to see in the commit message with which other branch this is a merge, which tells me enough here.

To achieve this in Gitk : I create a view in which I list the branches I want to see, and I check "Limit to first parent".

An example.

          L-M : other stuff
             
            A-B-C-I : feature
               / 
     ... -D-E-F-J : main
      /   /   
     / G-H-K : more other stuff
    /
... potentially even more stuff contributing to main via merges (not explicitly known)
       

C is the result of the merge of B and F.

E is the result of the merge of D and H.

B is the result of the merge of A and M.

I want to see A, B, C, I, D, E, F and J, but not G, H,K, L and M.

            A-B-C-I - feature
               / 
          D-E-F-J - main

Bonus : do not see J either ... Bonus to the bonus : ... but somehow know that F was once main and label it as such.

            A-B-C-I - feature
               / 
          D-E-F - was main

Edit : If I use --first-parent main feature I almost get what I want, except the second parent merge relationships are not shown (even though they exist, Gitk shows them). What now ?

question from:https://stackoverflow.com/questions/65938233/git-log-graph-but-only-some-branches

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

There's no way to 100% reliably meet all of your requirements. LeGEC's answer addresses the specific example in your original question, but I don't guess your follow-up to that comes as much surprise.

For your basic requirement, you can try something like

git log --graph --oneilne --first-parent main feature

and if you're following typical conventions then this will likely give you what you want. But there are circumstances in which it won't. I'll come back to that.

For your "bonus", you can do something like

git log --graph --oneline --first-parent $(git merge-base main feature) feature

So instead of main you say that you want the history up to the last commit that is reachable from both branches.

I don't know a way to dynamically mark the merge base commit in the log (the additional bonus). You could tag your merge bases I guess.

git tag was_on_master $(git merge-base main feature)
git log --graph --oneline --first-parent feature was_on_master
git tag -d waS_on_master

So now... when won't it work, and why is it this way?

In git, commits do not "belong to" branches. There is no history telling you which branch a commit "was created on". The only relationship between branches and commits is that a commit either is, or is not, reachable from a given branch. In the case of merge commits, you can also use the order of the parent pointers to distinguish which "direction" the merge probably happened in.

If you're on branch_A and you say git merge branch_B, then the commit you're on (the history "from" branch_A) will be the first parent of the merge. That's what --first-parent will later follow. And, if when you give the merge command you actually have branch_A checked out (as opposed to having the same commit checked out in detached HEAD state), branch_A automatically moves onto the merge; so the assumption is that typically "first parent means the history of this branch".

But there are situations where someone might do something that messes that up. Suppose you have

... A <--(branch_A)
        
... B <--(branch_B)

and then you say

git checkout branch_A
git merge branch_B
git checkout branch_B
git merge branch_A

Unless your configuration prevents it, the 2nd merge will be handled as a fast-forward, resulting in

... A -- M <--(branch_A)(branch_B)
        /
   ... B

Now no matter which branch is checked out, git log --first-parent will go to A.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...