Some git commits are missing after creating git branch from commit id












-2















I am creating a git branch from a commit id, My expectation is it should show commit ids after specified commit id while creating a new branch. But somehow few git commits are missing in the newly created git branch.



I have a main branch which has multiple commits id:



Main Branch commit ids



I have created a new branch from main branch using git checkout -b testBranch 3331a4b command



But when fire git log --oneline command on this branch, I can see that some commits ids are missing. Please click on below links to check commit id



testBranch commit ids:
testBranch commit ids



Missing commit ids of main branch:
Missing commit ids of main branch










share|improve this question

























  • It smells like the missing commits are on a different branch. Try git log --oneline --graph --all to confirm (or contradict) my suspicion.

    – joanis
    Nov 15 '18 at 16:39


















-2















I am creating a git branch from a commit id, My expectation is it should show commit ids after specified commit id while creating a new branch. But somehow few git commits are missing in the newly created git branch.



I have a main branch which has multiple commits id:



Main Branch commit ids



I have created a new branch from main branch using git checkout -b testBranch 3331a4b command



But when fire git log --oneline command on this branch, I can see that some commits ids are missing. Please click on below links to check commit id



testBranch commit ids:
testBranch commit ids



Missing commit ids of main branch:
Missing commit ids of main branch










share|improve this question

























  • It smells like the missing commits are on a different branch. Try git log --oneline --graph --all to confirm (or contradict) my suspicion.

    – joanis
    Nov 15 '18 at 16:39
















-2












-2








-2


2






I am creating a git branch from a commit id, My expectation is it should show commit ids after specified commit id while creating a new branch. But somehow few git commits are missing in the newly created git branch.



I have a main branch which has multiple commits id:



Main Branch commit ids



I have created a new branch from main branch using git checkout -b testBranch 3331a4b command



But when fire git log --oneline command on this branch, I can see that some commits ids are missing. Please click on below links to check commit id



testBranch commit ids:
testBranch commit ids



Missing commit ids of main branch:
Missing commit ids of main branch










share|improve this question
















I am creating a git branch from a commit id, My expectation is it should show commit ids after specified commit id while creating a new branch. But somehow few git commits are missing in the newly created git branch.



I have a main branch which has multiple commits id:



Main Branch commit ids



I have created a new branch from main branch using git checkout -b testBranch 3331a4b command



But when fire git log --oneline command on this branch, I can see that some commits ids are missing. Please click on below links to check commit id



testBranch commit ids:
testBranch commit ids



Missing commit ids of main branch:
Missing commit ids of main branch







git github git-branch






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 15 '18 at 14:47









Adil B

4,11892438




4,11892438










asked Nov 15 '18 at 11:49









Pratik WaghmarePratik Waghmare

22




22













  • It smells like the missing commits are on a different branch. Try git log --oneline --graph --all to confirm (or contradict) my suspicion.

    – joanis
    Nov 15 '18 at 16:39





















  • It smells like the missing commits are on a different branch. Try git log --oneline --graph --all to confirm (or contradict) my suspicion.

    – joanis
    Nov 15 '18 at 16:39



















It smells like the missing commits are on a different branch. Try git log --oneline --graph --all to confirm (or contradict) my suspicion.

– joanis
Nov 15 '18 at 16:39







It smells like the missing commits are on a different branch. Try git log --oneline --graph --all to confirm (or contradict) my suspicion.

– joanis
Nov 15 '18 at 16:39














1 Answer
1






active

oldest

votes


















1














Side note: screenshot images are generally a bad idea as they make both searching and quoting difficult.



The problem here is that while git log --oneline displays a linear list of commits, commits are not actually linear. You're expecting that, given some apparently-linear sequence of commits:



010 final
009 earlier
008 earlier-still
007 ...
...
001 first


that starting from 010 and counting backwards will give you 10 commits, while starting from 009 and counting backwards will give you 9 commits.



That would be true if the commits were linear, but they're not.



The actual numbers are, of course, not sequential, and not decimal—they're hash IDs, like 3331a4b (which is already short for something much longer that simply starts with 3331a4b). So you already know you can't just use the number as a simple index. Let's replace the sequential numbers (001 through 010) or hash IDs (3331a4b and such) with single uppercase letters A B ... H, and actually draw the commits made in a small repository with ten commits, with the last commit being a merge commit:



A  <-B  <-C  <-D  <-----H
/
E <-F <-G


These arrows—the ones coming from E pointing to C and from H pointing to G do not have an arrow-tip (because it's too hard to draw in text), but those connectors are arrows as well—allow Git to work backwards from the last commit to the first.



In fact, every Git commit contains some set of parent commit hash IDs. We say that the commit points to its parent (with arrows as drawn above). Most commits have exactly one parent, and these commits form a simple, backwards, linear chain, like that going from C back to A. Here, everything is well-behaved: when you start at C there is only one path back to A.



At least one commit, the very first one ever made, has no parent hash, because it was the first commit ever made and there is no earlier commit for it to point-to. This is where the action stops. Note that the action starts at the end and works backwards.



Some commits, like commit H in the example above, have two parents. Here, things get tricky, because Git can walk backwards from H to either G, or to D. (You may see where this is going already.) The git log command uses a specific method to linearize its backwards walk, which we will get to in a moment.



A branch name like master or develop actually points to a commit—one particular commit—such as commit H, so we can draw these things a little more simply, like this, and then add the branch names on the right, at the end:



A--B--C--D------H   <-- master
/
E--F--G <-- develop


knowing that the internal links between commits are backwards arrows. (So as to not require ever changing a commit, the arrows themselves are embedded inside the children, pointing back to their parent commits—nothing inside a commit can ever move or change; all of a commit's contents are fixed for all eternity. The children know who their parents are when the children are born, but until the children are born, the parents cannot know who their children will be, so the parents cannot point forward to the children.)



The tricky part here is that the names, like master or develop, do move: the name master got here by way of a git merge command, perhaps run via git pull, or perhaps run directly by someone, or via a GitHub "merge pull request" button, or similar. At some point earlier, the drawing looked like this:



A--B--C--D   <-- master

E--F--G <-- develop


Commit H did not yet exist, and starting from master and working backwards, git log would enumerate commits D, then C, then B, then A; starting from develop and working backwards, git log would enumerate commits G, then F, then E, then C, then B, then A.



At this point, someone ran git checkout master; git merge develop, or did something equivalent. This created new commit H, pointing back to G and D, and giving us our now-up-to-date drawing.



Now, suppose that you attach a new branch name to commit F or E. If you have been viewing git log output based on master, and have been assuming that commit D comes before commit E, you might expect to see commits starting from F or E, working backwards through and including D. But as soon as we draw the graph of the commits, and attach a label to F or E, you will see that we should not expect commit D to show up:



A--B--C--D------H   <-- master
/
E--F--G <-- develop
.
.....<-- testBranch


The fact that D is reachable from H (master, at the moment) does not imply that D will be reachable from testBranch.



In more complex graphs, the set of commits reachable starting at some branch-tip and working backwards can be much more difficult to see: the graphs become tangled and hard to view or visualize. Still, using git log --graph (with or without --oneline) can help here.



How git log linearizes a nonlinear graph



Since git log must show one commit at a time—one per line with --oneline, or using more than one output line without it—it needs a queue of pending commits. This queue typically starts out with just the one commit you name:



$ git log <hash>


or:



$ git log <branchname>


or with no arguments, the current (HEAD) commit. Git will take the commit out of the queue, show it, then put its parent(s) into the queue. If the commit just shown is a merge commit, with two (or more) parents, the queue has now become deeper.



Git then takes whichever commit is at the front of the queue and shows that commit. That commit has some parent(s); if the parent(s) have not yet been shown and are not already in the queue, Git puts them into the queue.



The order in which commits are shown is therefore dependent on where they go in the queue. When the queue is empty—as it often is—and there's only a single parent, that single parent becomes the single entry in the queue, and is immediately shown, removing it from the queue so that the queue is empty again. This is how a simple linear chain shows up as a simple linear chain: we might put commit G in the queue, then take it back out and show it and put F in the queue, then take it back out and show it and put E in the queue, and so on.



If you start git log with more than one commit:



$ git log master develop


(assuming the names master and develop point to two different commits—it's possible to have two branch names pointing to the same commit), the queue will start out with more than one commit in it, so once again, the order of commits in the queue will matter. Git will show the front-of-queue commit first, whether that's the one that master names, or the one that develop names. Having shown that commit, Git will insert its parent(s) into the queue if appropriate, and only then have a chance, depending on where the other commit is in the queue now, to show the other commit you named on the command line.



The default for queue insertion order is the commit timestamp, with a newer (later timestamp) commit going to the front of the queue. You can control this order to some extent with --date-order, --author-date-order, --topo-order, and --reverse. Using --graph forces --topo-order. For details, see the git log documentation.






share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53318835%2fsome-git-commits-are-missing-after-creating-git-branch-from-commit-id%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    Side note: screenshot images are generally a bad idea as they make both searching and quoting difficult.



    The problem here is that while git log --oneline displays a linear list of commits, commits are not actually linear. You're expecting that, given some apparently-linear sequence of commits:



    010 final
    009 earlier
    008 earlier-still
    007 ...
    ...
    001 first


    that starting from 010 and counting backwards will give you 10 commits, while starting from 009 and counting backwards will give you 9 commits.



    That would be true if the commits were linear, but they're not.



    The actual numbers are, of course, not sequential, and not decimal—they're hash IDs, like 3331a4b (which is already short for something much longer that simply starts with 3331a4b). So you already know you can't just use the number as a simple index. Let's replace the sequential numbers (001 through 010) or hash IDs (3331a4b and such) with single uppercase letters A B ... H, and actually draw the commits made in a small repository with ten commits, with the last commit being a merge commit:



    A  <-B  <-C  <-D  <-----H
    /
    E <-F <-G


    These arrows—the ones coming from E pointing to C and from H pointing to G do not have an arrow-tip (because it's too hard to draw in text), but those connectors are arrows as well—allow Git to work backwards from the last commit to the first.



    In fact, every Git commit contains some set of parent commit hash IDs. We say that the commit points to its parent (with arrows as drawn above). Most commits have exactly one parent, and these commits form a simple, backwards, linear chain, like that going from C back to A. Here, everything is well-behaved: when you start at C there is only one path back to A.



    At least one commit, the very first one ever made, has no parent hash, because it was the first commit ever made and there is no earlier commit for it to point-to. This is where the action stops. Note that the action starts at the end and works backwards.



    Some commits, like commit H in the example above, have two parents. Here, things get tricky, because Git can walk backwards from H to either G, or to D. (You may see where this is going already.) The git log command uses a specific method to linearize its backwards walk, which we will get to in a moment.



    A branch name like master or develop actually points to a commit—one particular commit—such as commit H, so we can draw these things a little more simply, like this, and then add the branch names on the right, at the end:



    A--B--C--D------H   <-- master
    /
    E--F--G <-- develop


    knowing that the internal links between commits are backwards arrows. (So as to not require ever changing a commit, the arrows themselves are embedded inside the children, pointing back to their parent commits—nothing inside a commit can ever move or change; all of a commit's contents are fixed for all eternity. The children know who their parents are when the children are born, but until the children are born, the parents cannot know who their children will be, so the parents cannot point forward to the children.)



    The tricky part here is that the names, like master or develop, do move: the name master got here by way of a git merge command, perhaps run via git pull, or perhaps run directly by someone, or via a GitHub "merge pull request" button, or similar. At some point earlier, the drawing looked like this:



    A--B--C--D   <-- master

    E--F--G <-- develop


    Commit H did not yet exist, and starting from master and working backwards, git log would enumerate commits D, then C, then B, then A; starting from develop and working backwards, git log would enumerate commits G, then F, then E, then C, then B, then A.



    At this point, someone ran git checkout master; git merge develop, or did something equivalent. This created new commit H, pointing back to G and D, and giving us our now-up-to-date drawing.



    Now, suppose that you attach a new branch name to commit F or E. If you have been viewing git log output based on master, and have been assuming that commit D comes before commit E, you might expect to see commits starting from F or E, working backwards through and including D. But as soon as we draw the graph of the commits, and attach a label to F or E, you will see that we should not expect commit D to show up:



    A--B--C--D------H   <-- master
    /
    E--F--G <-- develop
    .
    .....<-- testBranch


    The fact that D is reachable from H (master, at the moment) does not imply that D will be reachable from testBranch.



    In more complex graphs, the set of commits reachable starting at some branch-tip and working backwards can be much more difficult to see: the graphs become tangled and hard to view or visualize. Still, using git log --graph (with or without --oneline) can help here.



    How git log linearizes a nonlinear graph



    Since git log must show one commit at a time—one per line with --oneline, or using more than one output line without it—it needs a queue of pending commits. This queue typically starts out with just the one commit you name:



    $ git log <hash>


    or:



    $ git log <branchname>


    or with no arguments, the current (HEAD) commit. Git will take the commit out of the queue, show it, then put its parent(s) into the queue. If the commit just shown is a merge commit, with two (or more) parents, the queue has now become deeper.



    Git then takes whichever commit is at the front of the queue and shows that commit. That commit has some parent(s); if the parent(s) have not yet been shown and are not already in the queue, Git puts them into the queue.



    The order in which commits are shown is therefore dependent on where they go in the queue. When the queue is empty—as it often is—and there's only a single parent, that single parent becomes the single entry in the queue, and is immediately shown, removing it from the queue so that the queue is empty again. This is how a simple linear chain shows up as a simple linear chain: we might put commit G in the queue, then take it back out and show it and put F in the queue, then take it back out and show it and put E in the queue, and so on.



    If you start git log with more than one commit:



    $ git log master develop


    (assuming the names master and develop point to two different commits—it's possible to have two branch names pointing to the same commit), the queue will start out with more than one commit in it, so once again, the order of commits in the queue will matter. Git will show the front-of-queue commit first, whether that's the one that master names, or the one that develop names. Having shown that commit, Git will insert its parent(s) into the queue if appropriate, and only then have a chance, depending on where the other commit is in the queue now, to show the other commit you named on the command line.



    The default for queue insertion order is the commit timestamp, with a newer (later timestamp) commit going to the front of the queue. You can control this order to some extent with --date-order, --author-date-order, --topo-order, and --reverse. Using --graph forces --topo-order. For details, see the git log documentation.






    share|improve this answer




























      1














      Side note: screenshot images are generally a bad idea as they make both searching and quoting difficult.



      The problem here is that while git log --oneline displays a linear list of commits, commits are not actually linear. You're expecting that, given some apparently-linear sequence of commits:



      010 final
      009 earlier
      008 earlier-still
      007 ...
      ...
      001 first


      that starting from 010 and counting backwards will give you 10 commits, while starting from 009 and counting backwards will give you 9 commits.



      That would be true if the commits were linear, but they're not.



      The actual numbers are, of course, not sequential, and not decimal—they're hash IDs, like 3331a4b (which is already short for something much longer that simply starts with 3331a4b). So you already know you can't just use the number as a simple index. Let's replace the sequential numbers (001 through 010) or hash IDs (3331a4b and such) with single uppercase letters A B ... H, and actually draw the commits made in a small repository with ten commits, with the last commit being a merge commit:



      A  <-B  <-C  <-D  <-----H
      /
      E <-F <-G


      These arrows—the ones coming from E pointing to C and from H pointing to G do not have an arrow-tip (because it's too hard to draw in text), but those connectors are arrows as well—allow Git to work backwards from the last commit to the first.



      In fact, every Git commit contains some set of parent commit hash IDs. We say that the commit points to its parent (with arrows as drawn above). Most commits have exactly one parent, and these commits form a simple, backwards, linear chain, like that going from C back to A. Here, everything is well-behaved: when you start at C there is only one path back to A.



      At least one commit, the very first one ever made, has no parent hash, because it was the first commit ever made and there is no earlier commit for it to point-to. This is where the action stops. Note that the action starts at the end and works backwards.



      Some commits, like commit H in the example above, have two parents. Here, things get tricky, because Git can walk backwards from H to either G, or to D. (You may see where this is going already.) The git log command uses a specific method to linearize its backwards walk, which we will get to in a moment.



      A branch name like master or develop actually points to a commit—one particular commit—such as commit H, so we can draw these things a little more simply, like this, and then add the branch names on the right, at the end:



      A--B--C--D------H   <-- master
      /
      E--F--G <-- develop


      knowing that the internal links between commits are backwards arrows. (So as to not require ever changing a commit, the arrows themselves are embedded inside the children, pointing back to their parent commits—nothing inside a commit can ever move or change; all of a commit's contents are fixed for all eternity. The children know who their parents are when the children are born, but until the children are born, the parents cannot know who their children will be, so the parents cannot point forward to the children.)



      The tricky part here is that the names, like master or develop, do move: the name master got here by way of a git merge command, perhaps run via git pull, or perhaps run directly by someone, or via a GitHub "merge pull request" button, or similar. At some point earlier, the drawing looked like this:



      A--B--C--D   <-- master

      E--F--G <-- develop


      Commit H did not yet exist, and starting from master and working backwards, git log would enumerate commits D, then C, then B, then A; starting from develop and working backwards, git log would enumerate commits G, then F, then E, then C, then B, then A.



      At this point, someone ran git checkout master; git merge develop, or did something equivalent. This created new commit H, pointing back to G and D, and giving us our now-up-to-date drawing.



      Now, suppose that you attach a new branch name to commit F or E. If you have been viewing git log output based on master, and have been assuming that commit D comes before commit E, you might expect to see commits starting from F or E, working backwards through and including D. But as soon as we draw the graph of the commits, and attach a label to F or E, you will see that we should not expect commit D to show up:



      A--B--C--D------H   <-- master
      /
      E--F--G <-- develop
      .
      .....<-- testBranch


      The fact that D is reachable from H (master, at the moment) does not imply that D will be reachable from testBranch.



      In more complex graphs, the set of commits reachable starting at some branch-tip and working backwards can be much more difficult to see: the graphs become tangled and hard to view or visualize. Still, using git log --graph (with or without --oneline) can help here.



      How git log linearizes a nonlinear graph



      Since git log must show one commit at a time—one per line with --oneline, or using more than one output line without it—it needs a queue of pending commits. This queue typically starts out with just the one commit you name:



      $ git log <hash>


      or:



      $ git log <branchname>


      or with no arguments, the current (HEAD) commit. Git will take the commit out of the queue, show it, then put its parent(s) into the queue. If the commit just shown is a merge commit, with two (or more) parents, the queue has now become deeper.



      Git then takes whichever commit is at the front of the queue and shows that commit. That commit has some parent(s); if the parent(s) have not yet been shown and are not already in the queue, Git puts them into the queue.



      The order in which commits are shown is therefore dependent on where they go in the queue. When the queue is empty—as it often is—and there's only a single parent, that single parent becomes the single entry in the queue, and is immediately shown, removing it from the queue so that the queue is empty again. This is how a simple linear chain shows up as a simple linear chain: we might put commit G in the queue, then take it back out and show it and put F in the queue, then take it back out and show it and put E in the queue, and so on.



      If you start git log with more than one commit:



      $ git log master develop


      (assuming the names master and develop point to two different commits—it's possible to have two branch names pointing to the same commit), the queue will start out with more than one commit in it, so once again, the order of commits in the queue will matter. Git will show the front-of-queue commit first, whether that's the one that master names, or the one that develop names. Having shown that commit, Git will insert its parent(s) into the queue if appropriate, and only then have a chance, depending on where the other commit is in the queue now, to show the other commit you named on the command line.



      The default for queue insertion order is the commit timestamp, with a newer (later timestamp) commit going to the front of the queue. You can control this order to some extent with --date-order, --author-date-order, --topo-order, and --reverse. Using --graph forces --topo-order. For details, see the git log documentation.






      share|improve this answer


























        1












        1








        1







        Side note: screenshot images are generally a bad idea as they make both searching and quoting difficult.



        The problem here is that while git log --oneline displays a linear list of commits, commits are not actually linear. You're expecting that, given some apparently-linear sequence of commits:



        010 final
        009 earlier
        008 earlier-still
        007 ...
        ...
        001 first


        that starting from 010 and counting backwards will give you 10 commits, while starting from 009 and counting backwards will give you 9 commits.



        That would be true if the commits were linear, but they're not.



        The actual numbers are, of course, not sequential, and not decimal—they're hash IDs, like 3331a4b (which is already short for something much longer that simply starts with 3331a4b). So you already know you can't just use the number as a simple index. Let's replace the sequential numbers (001 through 010) or hash IDs (3331a4b and such) with single uppercase letters A B ... H, and actually draw the commits made in a small repository with ten commits, with the last commit being a merge commit:



        A  <-B  <-C  <-D  <-----H
        /
        E <-F <-G


        These arrows—the ones coming from E pointing to C and from H pointing to G do not have an arrow-tip (because it's too hard to draw in text), but those connectors are arrows as well—allow Git to work backwards from the last commit to the first.



        In fact, every Git commit contains some set of parent commit hash IDs. We say that the commit points to its parent (with arrows as drawn above). Most commits have exactly one parent, and these commits form a simple, backwards, linear chain, like that going from C back to A. Here, everything is well-behaved: when you start at C there is only one path back to A.



        At least one commit, the very first one ever made, has no parent hash, because it was the first commit ever made and there is no earlier commit for it to point-to. This is where the action stops. Note that the action starts at the end and works backwards.



        Some commits, like commit H in the example above, have two parents. Here, things get tricky, because Git can walk backwards from H to either G, or to D. (You may see where this is going already.) The git log command uses a specific method to linearize its backwards walk, which we will get to in a moment.



        A branch name like master or develop actually points to a commit—one particular commit—such as commit H, so we can draw these things a little more simply, like this, and then add the branch names on the right, at the end:



        A--B--C--D------H   <-- master
        /
        E--F--G <-- develop


        knowing that the internal links between commits are backwards arrows. (So as to not require ever changing a commit, the arrows themselves are embedded inside the children, pointing back to their parent commits—nothing inside a commit can ever move or change; all of a commit's contents are fixed for all eternity. The children know who their parents are when the children are born, but until the children are born, the parents cannot know who their children will be, so the parents cannot point forward to the children.)



        The tricky part here is that the names, like master or develop, do move: the name master got here by way of a git merge command, perhaps run via git pull, or perhaps run directly by someone, or via a GitHub "merge pull request" button, or similar. At some point earlier, the drawing looked like this:



        A--B--C--D   <-- master

        E--F--G <-- develop


        Commit H did not yet exist, and starting from master and working backwards, git log would enumerate commits D, then C, then B, then A; starting from develop and working backwards, git log would enumerate commits G, then F, then E, then C, then B, then A.



        At this point, someone ran git checkout master; git merge develop, or did something equivalent. This created new commit H, pointing back to G and D, and giving us our now-up-to-date drawing.



        Now, suppose that you attach a new branch name to commit F or E. If you have been viewing git log output based on master, and have been assuming that commit D comes before commit E, you might expect to see commits starting from F or E, working backwards through and including D. But as soon as we draw the graph of the commits, and attach a label to F or E, you will see that we should not expect commit D to show up:



        A--B--C--D------H   <-- master
        /
        E--F--G <-- develop
        .
        .....<-- testBranch


        The fact that D is reachable from H (master, at the moment) does not imply that D will be reachable from testBranch.



        In more complex graphs, the set of commits reachable starting at some branch-tip and working backwards can be much more difficult to see: the graphs become tangled and hard to view or visualize. Still, using git log --graph (with or without --oneline) can help here.



        How git log linearizes a nonlinear graph



        Since git log must show one commit at a time—one per line with --oneline, or using more than one output line without it—it needs a queue of pending commits. This queue typically starts out with just the one commit you name:



        $ git log <hash>


        or:



        $ git log <branchname>


        or with no arguments, the current (HEAD) commit. Git will take the commit out of the queue, show it, then put its parent(s) into the queue. If the commit just shown is a merge commit, with two (or more) parents, the queue has now become deeper.



        Git then takes whichever commit is at the front of the queue and shows that commit. That commit has some parent(s); if the parent(s) have not yet been shown and are not already in the queue, Git puts them into the queue.



        The order in which commits are shown is therefore dependent on where they go in the queue. When the queue is empty—as it often is—and there's only a single parent, that single parent becomes the single entry in the queue, and is immediately shown, removing it from the queue so that the queue is empty again. This is how a simple linear chain shows up as a simple linear chain: we might put commit G in the queue, then take it back out and show it and put F in the queue, then take it back out and show it and put E in the queue, and so on.



        If you start git log with more than one commit:



        $ git log master develop


        (assuming the names master and develop point to two different commits—it's possible to have two branch names pointing to the same commit), the queue will start out with more than one commit in it, so once again, the order of commits in the queue will matter. Git will show the front-of-queue commit first, whether that's the one that master names, or the one that develop names. Having shown that commit, Git will insert its parent(s) into the queue if appropriate, and only then have a chance, depending on where the other commit is in the queue now, to show the other commit you named on the command line.



        The default for queue insertion order is the commit timestamp, with a newer (later timestamp) commit going to the front of the queue. You can control this order to some extent with --date-order, --author-date-order, --topo-order, and --reverse. Using --graph forces --topo-order. For details, see the git log documentation.






        share|improve this answer













        Side note: screenshot images are generally a bad idea as they make both searching and quoting difficult.



        The problem here is that while git log --oneline displays a linear list of commits, commits are not actually linear. You're expecting that, given some apparently-linear sequence of commits:



        010 final
        009 earlier
        008 earlier-still
        007 ...
        ...
        001 first


        that starting from 010 and counting backwards will give you 10 commits, while starting from 009 and counting backwards will give you 9 commits.



        That would be true if the commits were linear, but they're not.



        The actual numbers are, of course, not sequential, and not decimal—they're hash IDs, like 3331a4b (which is already short for something much longer that simply starts with 3331a4b). So you already know you can't just use the number as a simple index. Let's replace the sequential numbers (001 through 010) or hash IDs (3331a4b and such) with single uppercase letters A B ... H, and actually draw the commits made in a small repository with ten commits, with the last commit being a merge commit:



        A  <-B  <-C  <-D  <-----H
        /
        E <-F <-G


        These arrows—the ones coming from E pointing to C and from H pointing to G do not have an arrow-tip (because it's too hard to draw in text), but those connectors are arrows as well—allow Git to work backwards from the last commit to the first.



        In fact, every Git commit contains some set of parent commit hash IDs. We say that the commit points to its parent (with arrows as drawn above). Most commits have exactly one parent, and these commits form a simple, backwards, linear chain, like that going from C back to A. Here, everything is well-behaved: when you start at C there is only one path back to A.



        At least one commit, the very first one ever made, has no parent hash, because it was the first commit ever made and there is no earlier commit for it to point-to. This is where the action stops. Note that the action starts at the end and works backwards.



        Some commits, like commit H in the example above, have two parents. Here, things get tricky, because Git can walk backwards from H to either G, or to D. (You may see where this is going already.) The git log command uses a specific method to linearize its backwards walk, which we will get to in a moment.



        A branch name like master or develop actually points to a commit—one particular commit—such as commit H, so we can draw these things a little more simply, like this, and then add the branch names on the right, at the end:



        A--B--C--D------H   <-- master
        /
        E--F--G <-- develop


        knowing that the internal links between commits are backwards arrows. (So as to not require ever changing a commit, the arrows themselves are embedded inside the children, pointing back to their parent commits—nothing inside a commit can ever move or change; all of a commit's contents are fixed for all eternity. The children know who their parents are when the children are born, but until the children are born, the parents cannot know who their children will be, so the parents cannot point forward to the children.)



        The tricky part here is that the names, like master or develop, do move: the name master got here by way of a git merge command, perhaps run via git pull, or perhaps run directly by someone, or via a GitHub "merge pull request" button, or similar. At some point earlier, the drawing looked like this:



        A--B--C--D   <-- master

        E--F--G <-- develop


        Commit H did not yet exist, and starting from master and working backwards, git log would enumerate commits D, then C, then B, then A; starting from develop and working backwards, git log would enumerate commits G, then F, then E, then C, then B, then A.



        At this point, someone ran git checkout master; git merge develop, or did something equivalent. This created new commit H, pointing back to G and D, and giving us our now-up-to-date drawing.



        Now, suppose that you attach a new branch name to commit F or E. If you have been viewing git log output based on master, and have been assuming that commit D comes before commit E, you might expect to see commits starting from F or E, working backwards through and including D. But as soon as we draw the graph of the commits, and attach a label to F or E, you will see that we should not expect commit D to show up:



        A--B--C--D------H   <-- master
        /
        E--F--G <-- develop
        .
        .....<-- testBranch


        The fact that D is reachable from H (master, at the moment) does not imply that D will be reachable from testBranch.



        In more complex graphs, the set of commits reachable starting at some branch-tip and working backwards can be much more difficult to see: the graphs become tangled and hard to view or visualize. Still, using git log --graph (with or without --oneline) can help here.



        How git log linearizes a nonlinear graph



        Since git log must show one commit at a time—one per line with --oneline, or using more than one output line without it—it needs a queue of pending commits. This queue typically starts out with just the one commit you name:



        $ git log <hash>


        or:



        $ git log <branchname>


        or with no arguments, the current (HEAD) commit. Git will take the commit out of the queue, show it, then put its parent(s) into the queue. If the commit just shown is a merge commit, with two (or more) parents, the queue has now become deeper.



        Git then takes whichever commit is at the front of the queue and shows that commit. That commit has some parent(s); if the parent(s) have not yet been shown and are not already in the queue, Git puts them into the queue.



        The order in which commits are shown is therefore dependent on where they go in the queue. When the queue is empty—as it often is—and there's only a single parent, that single parent becomes the single entry in the queue, and is immediately shown, removing it from the queue so that the queue is empty again. This is how a simple linear chain shows up as a simple linear chain: we might put commit G in the queue, then take it back out and show it and put F in the queue, then take it back out and show it and put E in the queue, and so on.



        If you start git log with more than one commit:



        $ git log master develop


        (assuming the names master and develop point to two different commits—it's possible to have two branch names pointing to the same commit), the queue will start out with more than one commit in it, so once again, the order of commits in the queue will matter. Git will show the front-of-queue commit first, whether that's the one that master names, or the one that develop names. Having shown that commit, Git will insert its parent(s) into the queue if appropriate, and only then have a chance, depending on where the other commit is in the queue now, to show the other commit you named on the command line.



        The default for queue insertion order is the commit timestamp, with a newer (later timestamp) commit going to the front of the queue. You can control this order to some extent with --date-order, --author-date-order, --topo-order, and --reverse. Using --graph forces --topo-order. For details, see the git log documentation.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 15 '18 at 16:51









        torektorek

        187k18236318




        187k18236318






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53318835%2fsome-git-commits-are-missing-after-creating-git-branch-from-commit-id%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            這個網誌中的熱門文章

            Tangent Lines Diagram Along Smooth Curve

            Yusuf al-Mu'taman ibn Hud

            Zucchini