git rebase for beginners

    In continuation of the article on what to say git so that it does what you need and before the article how to create a PR in someone else's Open Source project on GitHub, I think it is worthwhile to talk about what git rebase is.

    I myself do not really understand this topic and do not like to use it, for the reasons described below, so I ask you to comment, I will supplement it if possible.

    So git works with commits. Each commit is a set of changes. Each commit has a unique hash. When branches merge with merge:

    # git merge "another_branch"
    

    then all the commits are saved - the comments of the commit are saved, its hash + as a rule, another artificial commit is added. At the same time, commits can alternate with each other. This is not always convenient. Let's say your commit decided to roll back - to look in the general list where your commit and where not your is not very nice. And in general - in the general story I want to see really important changes, and not “oh, I forgot to put it;”. In order to glue several commits into one, you can use rebase. Although there is a squash & commit button in the GitHub interface - this is when you create a pull request (PR) from one branch to another (usually from your working branch to the main one) and after going through all the formalities, you can click squash & commit, update the comment and your changes appear in the main branch as one commit.

    Other options to combine several commits into one
    I used to do this. Then I watched the changes in the IDE, did the precommit review, then committed and pushed to the server. From the pros - you can use the entire code, see all changes in the IDE. Sometimes it’s more convenient than through the web UI, which is on GitHub.
    # git checkout master && git pull && git branch -b <НоваяВетка> && git merge <СтараяВеткаГдеМногоКомитов> --squash






    Caution rebase can change the hash of the commit and lead to merge conflicts, especially if several people are working on the same branch.

    I want to write about two cases of using rebase:

    1. When changes are included from one branch to another, not through merge, but through rebase:

      # git rebase "another_branch"
      

      This allows your local commits to be delivered after all the commits that have been submitted to the “another_branch” branch. The hashes of your commits will change.
    2. When you can edit several of your commits with your hands - for example, glue them, change the comment:

      # git rebase -i {HEAD~_commit_count_|commit_hash}
      

      Note: it is worth setting up the editor that will be used by git before invoking this command. Personally, I prefer mcedit.

    So you did everything in your cozy little twig and decided to share this commit with the world, but the world wants only one commit from you. `git rebase -i` will launch the editor and offer to edit the commits (the order of the commits is from top to bottom, unlike git log). You can leave the commit as is, you can change the comment, you can glue it with the previous one. As a rule, your first commit should be left as is, and all the rest should be changed to
    pick "commit_hash" "comment" → fixup "commit_hash" "comment".

    In this case, all comments that were in fixup commits are lost and the comment from the first commit is used. If comments were dear to you, you should use squash instead of fixup.

    But if the development process was long, then most likely you had to do the merge of the main branch. And all your commits will be mixed with general commits and gluing yours with not yours will be a difficult task. Therefore, before doing `git rebase -i <>`, you should do `git rebase`. git rebase puts all your commits at the end of the list of all commits (as you can see by running git log) and then run git rebase -i`, in all lines except the first, replace pick → {fixup | squash} and voila - you have one commit.

    If you somehow messed up the process of editing the `git rebase -i <>` commit, then you should not press Control + C - the exit code does not bother the exit code from the git editor. He will just take the file and do everything on it. Just delete or comment out all the lines in the file. git will understand that you didn’t want anything.

    After manipulating rebase, push with the -F option is required. All this is because we are rewriting changing the history of commits and git honestly warns us about this.
    # git push -f

    Git rebase example
    I’ll write after what I did. Given - 2 branches - master and b1. In the process, we made commits : Commits in master and b1 were made independently. I wrote in one list so that the order in which everything was done was clear. Here is the list of commits in each brunch: We make git merge master in b1 A new synthetic commit has been added Now we do rebase Note that our local commits are at the end of the list, the commit numbers have changed, the synthetic commit has disappeared. Well, finally, we glue our commits into one file. The file was after our editing. It turned out Such things

    Initial commit - ветка master - 2fbbe67
    b1.1 - ветка b1 - 85eac43
    master after b1.1 - ветка мастер b505f18
    b1.2 - ветка b1 - 2d7d4ea
    +1 - ветка master - 8dcef6c




    # git checkout master && git log
    8dcef6c "+1"
    b505f18 "master after b1.1"
    2fbbe67 "Initial commit"

    # git checkout b1 && git log
    2d7d4ea "b1.2"
    85eac43 "b1.1"
    2fbbe67 "Initial commit"




    # git checkout b1 && git merge master && git log
    5383781 "Merge branch 'master' into b1"
    8dcef6c "+1"
    2d7d4ea "b1.2"
    b505f18 "master after b1.1"
    85eac43 "b1.1"
    2fbbe67 "Initial commit"






    # git checkout b1 && git rebase master && git log
    7f18e47 "b1.2"
    6fb80cb "b1.1"
    8dcef6c "+1"
    b505f18 "master after b1.1"
    2fbbe67 "Initial commit"






    # git rebase -i HEAD~2




    pick 6fb80cb b1.1
    pick 7f18e47 b1.2




    pick 6fb80cb b1.1
    fixup 7f18e47 b1.2




    # git checkout b1 && git log
    9062cd7 "b1.1"
    8dcef6c "+1"
    b505f18 "master after b1.1"
    2fbbe67 "Initial commit"



    Also popular now: