Git’s command is a common source of fear and confusion for Git users, especially those whom may have come from a more centralized version control system. That’s normal. Rebase is a weird, magical looking beast that just comes in and starts changing history willy-nilly. rebase Rebase is sort of like pointers; it is this confusing construct that everybody talks about but you have no idea why anybody would use it and then suddenly everything will and the whole idea becomes glaringly obvious and incredibly simple. click I am here to force that onto you so you can go into work and spread the wonder that is . click git rebase What Even is a Rebase? Git Rebase is a tool that can be used to take some commits that were made in one place and just pretend they were made in another place all along. OK but what does that ? mean Let’s look at an example. We have two branches in this repository: and . was branched off of and some commits were made on . has moved on because the world doesn’t just stop when you aren’t looking. master feature/foo feature/foo master feature/foo master Current state of affairs We want to integrate the changes from into but we don’t want to deal with having a pesky merge commit every time we perform this integration. master feature/foo Rebase is a tool that gives you the power to integrate changes that happened on the source branch without performing a merge, and thus without having a merge commit. Post-rebase. Visions of fast-forward… Commits and have been on top of , which is currently pointing at commit . You will notice that these commits are actually named and and the commit SHA-1 is different. Why is this? D F replayed master G D` F` Commits are Immutable in Git A commit has a few properties that are relevant here: a parent commit, a timestamp, and a snapshot of the repository at the time of the commit (commits are not just changesets). These values are what Git uses when it computes the SHA-1 that identifies a commit. Since commits are immutable and a SHA-1 should uniquely identify a single commit, Git has to create new commits that contain the same repository snapshot as the original commits, but each with a . different parent commit and timestamp This leads to new commits that look identical to the original commits, but have different SHA-1s. Finding the Commits How does Git know what commits to move when we run from ? git rebase master feature/foo Let’s first look at a Venn diagram of the commits on each branch. Here we see that each branch has commits , , and . has commits and that does not have. has commits and that does not have. A B C master E G feature/foo feature/foo F D master Git will perform a set subtraction, , to find the right commits. This results in commits and {commits on feature/foo} — {commits on master} D F. Can we prove this? Yes! An easy way is to use to see the exact commits that we get from this set subtraction. git log show us commits and . git log master..feature/foo should bc1f36b 640e713 Current branch is implied if you omit a branch after .. This looks good so far. Let’s get a wider view to make sure I’m not yanking chains. These SHA-1s look familiar 76f5fd1 and 22033eb are missing because we diverged from master at 7559a0b If we now perform a onto , we should see commits and immediately before the commits that were made on . rebase master 76f5fd1 22033eb feature/foo Git is replaying the commits that we expected Does this look familiar? We saw this earlier! We now have a nice linear history. You should be able to see how a fast-forward merge would happen at this point. The rebase strategy has the added bonus of knowing that if your CI pipeline passes on the feature branch, it will pass on main branch post-merge. With a non-linear merge strategy, you do not have this guarantee. Using the Force If were already pushed and another push is attempted after this rebase, Git will very politely decline to do the push. Why is this? feature/foo Git will do everything it can to prevent an accidental overwriting of history, which is a . good thing Let’s look at what Git thinks looks like on the remote repository. feature/foo Now let’s look at what we’re telling Git to do. From Git’s point of view, commits and are about to be lost. Git will give you a nice message along the lines of . D F Updates were rejected because the tip of your current branch is behind You might say, “But I can clearly see in the nice picture that you made, is further ahead than what it was before.” This is a good observation, but Git just sees that on the remote repository contains and and your local version of does not contain those commits. So in order to not lose these commits, Git will politely decline a normal , requiring you to perform a . feature/foo feature/foo bc1f36b 640e713 feature/foo git push git push --force If you take away one thing from this article, remember that at its core, rebase just finds commits that were made on some branch and creates new commits with the same content but with a new parent or commit. base Git rebase do much more by utilizing its mode, but that is out of the scope of this article. If you would like to know all that you can do with the mode, I will be writing about that soon. can --interactive --interactive If you liked what you read then 👏 to show your appreciation! Follow and for more quality software engineering content. Hackernoon Jared Ready
Share Your Thoughts