158 lines
5.8 KiB
Org Mode
158 lines
5.8 KiB
Org Mode
|
#+BEGIN_COMMENT
|
||
|
.. title: Git! Rebase and Strategies
|
||
|
.. date: 2019-08-10
|
||
|
.. slug: git-rebase-and-strategies
|
||
|
.. updated: 2019-08-10
|
||
|
.. status: published
|
||
|
.. tags: git, revision-control
|
||
|
.. category: revision-control
|
||
|
.. authors: Elia el Lazkani
|
||
|
.. description: Getting a little handle on git rebase
|
||
|
.. type: text
|
||
|
#+END_COMMENT
|
||
|
|
||
|
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.
|
||
|
|
||
|
{{{TEASER_END}}}
|
||
|
|
||
|
* Requirements
|
||
|
This has not changed people, it is still /git/.
|
||
|
|
||
|
* 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 [[https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging#_basic_merging][git basic branching and merging]] manual.
|
||
|
|
||
|
The other is =git-rebase=.
|
||
|
|
||
|
While =git-rebase= has a lot of different uses, the basic use of it is described in the [[https://git-scm.com/book/en/v2/Git-Branching-Rebasing][git branching rebasing]] manual as:
|
||
|
|
||
|
#+BEGIN_QUOTE
|
||
|
"With the =rebase= command, you can take all the changes that were committed on one branch and replay them on a different branch."
|
||
|
#+END_QUOTE
|
||
|
|
||
|
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.
|
||
|
|
||
|
#+BEGIN_EXPORT html
|
||
|
<div class="admonition note">
|
||
|
<p class="admonition-title">Note</p>
|
||
|
#+END_EXPORT
|
||
|
Branch and branch often!
|
||
|
if you merge, merge and merge often!
|
||
|
or rebase, and rebase often!
|
||
|
#+BEGIN_EXPORT html
|
||
|
</div>
|
||
|
#+END_EXPORT
|
||
|
|
||
|
** Usage
|
||
|
Rebase is used just like merge in our case.
|
||
|
|
||
|
First, let's create a branch and make a change in that branch.
|
||
|
|
||
|
#+BEGIN_EXAMPLE
|
||
|
$ 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(+)
|
||
|
$
|
||
|
#+END_EXAMPLE
|
||
|
|
||
|
Now let's assume someone (or yourself) made a change to the =master= branch.
|
||
|
|
||
|
#+BEGIN_EXAMPLE
|
||
|
$ 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
|
||
|
$
|
||
|
#+END_EXAMPLE
|
||
|
|
||
|
I want to take a look at how the tree looks like before I attempt any changes.
|
||
|
|
||
|
#+BEGIN_EXAMPLE
|
||
|
$ 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
|
||
|
#+END_EXAMPLE
|
||
|
|
||
|
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.
|
||
|
|
||
|
#+BEGIN_EXAMPLE
|
||
|
$ 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
|
||
|
#+END_EXAMPLE
|
||
|
|
||
|
|
||
|
And, let's look at the tree of course.
|
||
|
|
||
|
#+BEGIN_EXAMPLE
|
||
|
$ 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
|
||
|
#+END_EXAMPLE
|
||
|
|
||
|
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
|
||
|
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
|
||
|
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.
|