Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Git merge in depth

Anton Chikin
November 29, 2016

Git merge in depth

How exactly 3-way recursive merge and rebase work.

Anton Chikin

November 29, 2016
Tweet

Other Decks in Technology

Transcript

  1. git merge in depth
    Anton Chikin

    View full-size slide

  2. test
    branch
    merge
    master
    to branch
    test
    branch
    merge
    branch
    to master
    test
    master

    View full-size slide

  3. test
    branch
    merge
    master
    to branch
    test
    branch
    merge
    branch
    to master
    test
    master
    WAT

    View full-size slide

  4. I don’t trust merge!

    View full-size slide

  5. master
    branch

    View full-size slide

  6. master
    branch

    View full-size slide

  7. master
    branch

    View full-size slide

  8. master
    branch

    View full-size slide

  9. master
    branch

    View full-size slide

  10. master
    branch
    ?

    View full-size slide

  11. master
    branch
    ?
    var a = “foo”
    def getData(string
    path)
    var data = Map()
    for l in
    visit(path)
    data[l.slot] =
    l.data
    return
    data.JSON()
    var a = “foo”
    def getData(URI
    path)
    var data =
    Array()
    for l in
    visit(path)
    data[l.id] =
    l.data
    return data

    View full-size slide

  12. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    master
    branch

    View full-size slide

  13. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    master
    branch
    ?

    View full-size slide

  14. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    master
    branch
    ?
    ?

    View full-size slide

  15. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    master
    branch
    ?
    ?
    ?

    View full-size slide

  16. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    master
    branch
    ?
    ?
    ?
    ?

    View full-size slide

  17. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    master
    branch
    ?
    ?
    ?
    ?
    Nearest common ancestor
    var a = “foo”
    def getData(string
    path)
    var data = {}
    for l in
    visit(path)
    data[l.slot] =
    l.data
    return data

    View full-size slide

  18. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    master
    branch

    View full-size slide

  19. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch

    View full-size slide

  20. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”

    View full-size slide

  21. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”

    View full-size slide

  22. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path) def getData(URI path)
    def getData(string path)

    View full-size slide

  23. ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path)
    def getData(URI path)
    def getData(string path)

    View full-size slide

  24. def getData(string path)
    ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path)
    def getData(URI path)
    var data = {}

    View full-size slide

  25. def getData(string path)
    ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path)
    def getData(URI path)
    var data = {}
    ?????????????

    View full-size slide

  26. def getData(string path)
    ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path)
    def getData(URI path)
    var data = {}
    ?????????????

    View full-size slide

  27. def getData(string path)
    <<<<<<< HEAD
    var data = Map()
    ||||||| merged common ancestors
    var data = {}
    =======
    var data = Array()
    >>>>>>> branch

    View full-size slide

  28. def getData(string path)
    ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path)
    def getData(URI path)
    var data = {}
    var data = Map()
    for l in visit(path)

    View full-size slide

  29. def getData(string path)
    ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path)
    def getData(URI path)
    var data = {}
    var data = Map()
    for l in visit(path)

    View full-size slide

  30. def getData(string path)
    ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path)
    def getData(URI path)
    var data = {}
    var data = Map()
    for l in visit(path)
    data[l.id] = l.data

    View full-size slide

  31. def getData(string path)
    ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path)
    def getData(URI path)
    var data = {}
    var data = Map()
    for l in visit(path)
    data[l.id] = l.data

    View full-size slide

  32. def getData(string path)
    ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path)
    def getData(URI path)
    var data = {}
    var data = Map()
    for l in visit(path)
    data[l.id] = l.data
    return data.JSON()

    View full-size slide

  33. def getData(string path)
    ?
    var a = “foo”
    def getData(string path)
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    var a = “foo”
    def getData(URI path)
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    def getData(string path)
    var data = {}
    for l in visit(path)
    data[l.slot] = l.data
    return data
    ancestor
    merge
    ancestor
    master
    branch
    var data = Map()
    for l in visit(path)
    data[l.slot] = l.data
    return data.JSON()
    for l in visit(path)
    data[l.slot] = l.data
    return data
    var data = Array()
    for l in visit(path)
    data[l.id] = l.data
    return data
    var a = “foo”
    var a = “foo”
    var a = “foo”
    var a = “foo”
    def getData(string path)
    def getData(URI path)
    var data = {}
    var data = Map()
    for l in visit(path)
    data[l.id] = l.data
    return data.JSON()

    View full-size slide

  34. master
    branch
    ?

    View full-size slide

  35. master
    branch

    View full-size slide

  36. master
    branch
    merge master into branch

    View full-size slide

  37. master
    branch
    merge master into branch

    View full-size slide

  38. branch
    merge branch into master
    master

    View full-size slide

  39. recursive 3-way merge

    View full-size slide

  40. master
    Let’s take a look at a more complicated picture

    View full-size slide

  41. master
    hotfix
    Let’s take a look at a more complicated picture

    View full-size slide

  42. master
    hotfix
    Let’s take a look at a more complicated picture

    View full-size slide

  43. master
    feature
    hotfix
    Let’s take a look at a more complicated picture

    View full-size slide

  44. master
    hotfix
    feature
    Let’s take a look at a more complicated picture

    View full-size slide

  45. master
    hotfix
    feature
    Let’s take a look at a more complicated picture

    View full-size slide

  46. master
    M
    hotfix
    feature
    Let’s take a look at a more complicated picture

    View full-size slide

  47. master
    M
    M
    hotfix
    feature
    Let’s take a look at a more complicated picture

    View full-size slide

  48. master
    M
    M
    ?
    hotfix
    feature
    Let’s take a look at a more complicated picture

    View full-size slide

  49. master
    M
    M
    ?
    hotfix
    feature
    Let’s take a look at a more complicated picture
    nearest common ancestor

    View full-size slide

  50. master
    M
    M
    ?
    hotfix
    feature
    How to deal with two nearest common ancestors?
    nearest common ancestor
    nearest common ancestor

    View full-size slide

  51. master
    M
    M
    ?
    hotfix
    nearest common ancestor
    Step 1: find nearest common ancestor
    of those ancestors

    View full-size slide

  52. master
    M
    M
    ?
    hotfix
    Step 2: merge them into “fake” commit
    nearest common ancestor

    View full-size slide

  53. master
    M
    M
    ?
    hotfix
    Step 3: Merge our commits using that “fake” ancestor
    nearest common ancestor

    View full-size slide

  54. master
    M
    M
    hotfix
    M
    nearest common ancestor
    This process can be recursive

    View full-size slide

  55. master
    M
    M
    hotfix
    feature
    M

    View full-size slide

  56. And what about rebase?

    View full-size slide

  57. master
    branch
    master
    A B C

    View full-size slide

  58. master
    branch
    master
    A B C
    nearest common ancestor
    Again, find NCO

    View full-size slide

  59. master
    branch
    master
    diff B diff C
    diff A
    A B C
    Create diffs between each commits starting from NCO

    View full-size slide

  60. master
    branch
    master
    A B C
    diff B diff C
    diff A
    Move branch head to master

    View full-size slide

  61. master
    branch
    master
    A B C
    A’
    diff B diff C
    Apply each diff on top of latest master commit

    View full-size slide

  62. master
    branch
    master
    A B C
    A’ B’
    diff C
    Apply each diff on top of latest master commit

    View full-size slide

  63. master
    branch
    master
    A B C
    A’ B’ C’
    Apply each diff on top of latest master commit

    View full-size slide

  64. @1,1
    - A
    + B
    What does it mean to “apply diff”?
    Diff format is quite simple:
    In the first line

    View full-size slide

  65. @1,1
    - A
    + B
    Diff format is quite simple:
    In the first line
    replace “A”
    What does it mean to “apply diff”?

    View full-size slide

  66. @1,1
    - A
    + B
    Diff format is quite simple:
    In the first line
    replace “A”
    with “B”
    What does it mean to “apply diff”?

    View full-size slide

  67. A
    B
    C
    @1,1
    - A
    + B
    B
    B
    C
    What does it mean to “apply diff”?

    View full-size slide

  68. D
    B
    C
    @1,1
    - A
    + B
    ????????
    B
    C
    What if first line in file is not “A” but “D”?
    Same as in merge - conflict!
    What does it mean to “apply diff”?

    View full-size slide

  69. D
    B
    C
    @1,1
    - A
    + B
    ????????
    B
    C
    What if first line in file is not “A” but “D”?
    Same as in merge - conflict!
    What does it mean to “apply diff”?

    View full-size slide

  70. master
    branch
    branch
    master
    A’ B’ C’
    A B C
    M
    Merge and rebase give you different branch structure
    but the same result

    View full-size slide

  71. Merge commits “train station”

    View full-size slide

  72. Merge commits “subway”

    View full-size slide

  73. Finally
    - don’t be afraid of recursive merge
    - merge a ->b == merge b ->a
    - merge == rebase
    - prefer merge over rebase
    - merge will never never let you down

    View full-size slide

  74. •http://think-like-a-git.net/
    •http://git-school.github.io/visualizing-git/
    Resources

    View full-size slide

  75. git merge in depth
    Anton Chikin

    View full-size slide