blog.lazkani.io/content/posts/git-rebase-and-strategies.md

159 lines
5.6 KiB
Markdown

+++
title = "Git! Rebase and Strategies"
author = ["Elia el Lazkani"]
date = 2019-08-10
lastmod = 2019-08-10
tags = ["git", "rebase", "strategies"]
categories = ["revision-control"]
draft = false
+++
In the previous topic, I talked about git remotes because it felt
natural after branching and merging.
Now, the time has come to talk a little bit about `rebase` and some good
cases to use it for.
<!--more-->
## Requirements {#requirements}
This has not changed people, it is still _git_.
## Rebase {#rebase}
In _git_ there are 2 ways of integrating your changes from one branch
into another.
We already talked about one; `git-merge`. For more information about `git-merge` consult the [git basic branching and merging](https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging#%5Fbasic%5Fmerging) manual.
The other is `git-rebase`.
While `git-rebase` has a lot of different uses, the basic use of it is described in the [git branching rebasing](https://git-scm.com/book/en/v2/Git-Branching-Rebasing) manual as:
> "With the `rebase` command, you can take all the changes that were committed on one branch and replay them on a different branch."
In other words, all the commits you have made into the branch you are on will be set aside.
Then, all the changes in the branch you are rebasing from will be applied to your branch.
Finally, all your changes, that were set aside previously, will be applied back to your branch.
The beauty about this process is that you can keep your branch updated with upstream, while coding your changes.
By the end of the process of adding your feature, your changes are ready to be merged upstream straight away.
This is due to the fact that all the conflicts would've been resolved in each rebase.
<div class="admonition note">
<p class="admonition-title">Note</p>
Branch and branch often!
if you merge, merge and merge often!
or rebase, and rebase often!
</div>
### Usage {#usage}
Rebase is used just like merge in our case.
First, let's create a branch and make a change in that branch.
```text
$ git checkout -b rebasing-example
Switched to a new branch 'rebasing-example'
$ printf "\n# Rebase\n\nThis is a rebase branch.\n" >> README.md
$ git add README.md
$ git commit -m "Adding rebase section"
[rebasing-example 4cd0ffe] Adding rebase section
1 file changed, 4 insertions(+)
$
```
Now let's assume someone (or yourself) made a change to the `master` branch.
```text
$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
$ printf "# Master\n\nThis is a master branch" >> master.md
$ git add master.md
$ git commit -m "Adding master file"
[master 7fbdab9] Adding master file
1 file changed, 3 insertions(+)
create mode 100644 master.md
$
```
I want to take a look at how the tree looks like before I attempt any changes.
```text
$ git log --graph --oneline --all
* 7fbdab9 (HEAD -> master) Adding master file
| * 4cd0ffe (rebasing-example) Adding rebase section
|/
* 4f6bb31 (origin/master) Adding the git remote section
* 0bd01aa Second commit
```
After both of our commits, the tree diverged.
We are pointing to the **master** branch, I know that because `HEAD` points to _master_.
That commit is different than the commit that `rebase-example` branch points to.
These changes were introduced by someone else while I was adding the rebase section in the `README.md` file and they might be crucial for my application.
In short, I was those changes in the code I am working on right now.
Let's do that.
```text
$ git checkout rebasing-example
Switched to branch 'rebasing-example'
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: Adding rebase section
```
And, let's look at the tree of course.
```text
$ git log --graph --oneline --all
* 1b2aa4a (HEAD -> rebasing-example) Adding rebase section
* 7fbdab9 (master) Adding master file
* 4f6bb31 (origin/master) Adding the git remote section
* 0bd01aa Second commit
```
The tree lookr linear now. `HEAD` is pointing to our branch.
That commit points to the `7fbdab9` commit which the _master_ branch also points to.
So rebase set aside `1b2aa4a` to apply `7fbdab9` and then re-applied it back. Pretty neat huh ?!
## My Strategy {#my-strategy}
I'm going to be honest with you. I do not know the different kinds of merge strategies.
I've glazed at names of a few but I've never looked at them closely enough to see which one is what.
What I use, I've used for a while. I learned it from somewhere and changed a few things in it to make it work for me.
First of all, I always fork a repository.
I tend to stay away from creating a branch on the upstream repository unless it's my own personal project.
On my fork, I freely roam. I am the king of my own fork and I create as many branches as I please.
I start with an assumption. The assumption is that my _master_ branch is, for all intents and purposes, upstream.
This means I keep it up to date with upstream's main branch.
When I make a branch, I make a branch from _master_, this way I know it's up to date with upstream.
I do my work on my branch. Every few hours, I update my _master_ branch. After I update my _master_
branch, I _rebase_ the _master_ branch into my branch and voilà I'm up to date.
By the time my changes are ready to be merged back into upstream for any
reason, they are ready to go.
That **MR** is gonna be ready to be merged in a jiffy.
## Conclusion {#conclusion}
From what I've read, I use one of those strategies described on some
website. I don't know which one. But to me, it doesn't matter because it
works for me. And if I need to adapt that for one reason or another, I
can.