Git is awesome in many ways but comes with a quite high learning curve. Adopting Git requires learning. One of the concept I teach is "don't fear git rebase"! Curiously, once this ritual becomes usual I tend to see very offending rebases.
rebase is great
Yes,
git rebase
is great! This is likely how you should integrate
changes of the mainline into your ongoing work as a contributor.
Conflicts are to be expected and
git rerere
is a nice helper. Not to
talk how
git rebase --interactive
is wonderful.
Don't rely on Git for solving your conflicts
Most users know that Git will stop and alert when hitting conflicts. Hence, it becomes natural to rebase and just see if there are conflicts to solve. Notice this is true while merging, too.
However, "blindly" rebasing is rather wrong.
What are conflicts
Conflicts are incompatible changes.
Everyone know them. When one makes changes on a file and someone else makes other changes in the same area, Git will stop at some point and complain about those incompatible changes.
I call those "textual" conflicts. Git (or whatever content manager you use) don't know how to get them solve. Human intervention is required.
However, there are many other kinds of incompatible changes that your SCM won't care at all. For those, you won't be warned.
Semantic changes
Semantic changes are about renames and the easiest to depict my point. The code base is:
def hello():
print("hi")
Locally, you use this function in your ongoing work by adding yet another call
to the
hello()
function.
# My new code block.
hello()
Since you'd like to integrate upstream changes, you start a new rebase. Everything goes fine without any apparent conflicts. Hence, you decide to release your work or request a merge.
This is WRONG. If upstream changed the function name from
hello()
to
hi()
, your freshly rebased code is sightly broken. And Git did
not warn you about that.
Other significant incompatible changes
There are many kind of other incompatible changes. It's not the point to list them all. Though, here are some that you might be missing while blindly rebasing:
- signature (arguments changes or returned type)
- locking strategy (e.g.: from pessimistic to optimistic locking)
- exception handling
- database
- CSS
- template
- events
- etc
Always read the changes introduced since the common ancestor
Checking if code changes are about to hurt is a matter of knowing what changed in which way.
Commit messages
You know how to write good commit messages. You like to write good commit messages. Help others to provide GOOD commit messages.
Commit messages are the first helpers to track down changes. You already stopped
using
git pull
in favour of
git fetch
and
git rebase
.
When doing a
git fetch
on a remote repository, Git will display the
ranges of changes. This is a good start to read them as soon as they are
fetched:
> git fetch
remote: Counting objects: 1761, done.
remote: Compressing objects: 100% (738/738), done.
remote: Total 1761 (delta 1118), reused 1523 (delta 1021)
Receiving objects: 100% (1761/1761), 2.43 MiB | 2.40 MiB/s, done.
Resolving deltas: 100% (1118/1118), done.
From git://git.kernel.org/pub/scm/git/git
e0688e9b2..9d77b0405 master -> origin/master
e7e07d5a4..7c9c2f8c3 maint -> origin/maint
76c07830f..ad4152297 next -> origin/next
+ 706d305d9...e0f560f03 pu -> origin/pu (forced update)
000dd595e..ee9787006 todo -> origin/todo
Then, inspect the logs of the new master:
> git log --decorate --topo-order e0688e9b2..9d77b0405
or inspect what was introduced since you started
MY_BRANCH
(off of
master
),
> git log --decorate --topo-order MY_BRANCH..origin/master
Read the patches
Next, read the patches including those you're not sure what the commits are about.
> git log --decorate --topo-order -p MY_BRANCH..origin/master
or, for each specific commit,
> git show 9d77b0405
Conclusion
Never ever trust a rebase (or a merge) just because there was no conflict.
Rebasing means integrating topics that could work in the mainline but might really NOT play well with yours.
Same goes while merging. Each topic can work well as-is until it's merged with other stuff.
It's definelty not the job of the SCM to warn you about all the possible conflicts. Actually, it would be too hard to achieve for a program.
It's your job to make sure that the upstream changes are fully compatible with yours while rebasing. Never ever skip all the required checks or you might go into serious troubles.
Of course, run the tests again! ,-)