🚧 This instance is under construction; expect occasional downtime. Runners available in /repos. Questions? Ask in #wikimedia-gitlab on libera.chat, or under GitLab on Phabricator.

README.org 7.07 KB
Newer Older
Matthew Vernon's avatar
Matthew Vernon committed
1
2
* A demonstration of using ~git rebase~ to improve your merge requests

3
4
This repository contains the notes for a demonstration of using 
~git rebase~ to improve your merge requests. It also contains the examples
Matthew Vernon's avatar
Matthew Vernon committed
5
used in the demonstration, so you can clone the repository and try
6
7
yourself if you wish (see the bottom of this README for notes on how
to do so).
Matthew Vernon's avatar
Matthew Vernon committed
8
9
10
11
12
13
14
15
16
17
18
19

** TL;DR

The key take-home messages from this demonstration:

1. Don't rebase branches you expect others to pull
2. Do consider rebasing branches to make merge requests easier to
   review, and code history easier to follow in future
3. Do start with a clean working tree
4. ~gitk~ and ~git rebase -i~ are your friends
5. Nearly all mistakes can be rectified if you've not pushed them yet

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
** What is rebasing?

Suppose we are on a branch ~topic~ and we run ~git rebase master~.
Roughly, what happens is that the commits on the ~topic~ branch are
unwound back to the point at which ~topic~ diverged from ~master~,
and then replaced on top of the tip of ~master~. Stealing the example
from ~git-rebase(1)~:

Before ~rebase~:

:       A---B---C topic
:      /  
: D---E---F---G master

After ~rebase~:

:               A'--B'--C' topic
:              /
: D---E---F---G master

If anyone was working on a branch they had made off ~topic~, they are
now *very sad* and will have to do some work to sort out the mess -
there's a whole section called "Recovering from Upstream Rebase" in
the ~git rebase~ manual that explains in detail. Suffice for now to
emphasise: *do not rebase branches you have pushed where others might
pull them* (unless you have agreed that this is a rebasing branch,
which is a workflow outwith the scope of this demo). Merge Requests
47
48
are rather an exception to the general rule here. This is why you need
to add ~--force~ to push a rebased branch.
Matthew Vernon's avatar
Matthew Vernon committed
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

** A simple rebase example - branch ~one~

Branch ~one~ is a branch off an older commit of ~master~. It's simply
added a single file in one commit. A Merge Request based off this
branch will note "Request to merge ~one~ into ~master~ (N commits
behind". Usually gitlab is clever enough to only show you the changes
made on this branch, but it sometimes gets confused and shows you
changes made to master since the branch diverged. In the latter case,
particularly, it can be useful to rebase and re-push the branch to
make reviewing the MR easier.

So, check out branch ~one~, and use ~gitk --all~ to look at its
relationship with master; then rebase with ~git rebase master~, and
reload ~gitk~ (under the "File" menu) to see how it looks now. If you
then refresh the MR (by using ~git push --force origin one~ or
similar), you'll see the "N commits behind" will have gone away.

67
68
69
70
71
72
73
74
** Interactive rebasing

The tool you'll most often want to use to tidy up a branch/MR is
interactive rebasing, ~git rebase -i~. This launches an editor (so
make sure you've got a useful one configured!) giving you the list of
commits on your branch and a comment that tells you your options for
handling each commit:

75
76
77
78
79
80
: p, pick = use commit
: r, reword = use commit, but edit the commit message
: e, edit = use commit, but stop for amending
: s, squash = use commit, but meld into previous commit
: f, fixup = like "squash", but discard this commit's log message
: x, exec = run command (the rest of the line) using shell
81
82
83
84
85
86
87

All of these have their uses, and do roughly what the help text says
that they do. Additionally, you can re-order commits (by re-ordering
them in the file you're presented with by git) and discard commits
entirely. I often find a combination of ~reword~ and ~fixup~
particularly useful in tidying up a set of commits before getting an
MR approved.
Matthew Vernon's avatar
WCPGW?    
Matthew Vernon committed
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122

** Interactive rebasing example - branch ~two~

Branch ~two~ is a branch with a number of commits on it, all affecting
the file ~two.txt~. If you have a look at the commits (or inspect the
file itself with ~git blame~), you'll see that this isn't a nice set
of coherent commits — there's a typo corrected in the second quatrain,
and then a small fixup to the first quatrain committed after the third
quatrain was completed. It would be much nicer to turn this into 4
commits in order, one for each section of the sonnet.

So, checkout the branch ~two~, and do ~git rebase -i master~. Then go
ahead and tidy up the commits; I suggest using fixup on the "Make
metre a bit clearer" commit and moving it to just after the "First
quatrain" commit and similarly making the spelling correction a
fixup. Then inspect your work (with ~git blame~ or ~gitk~ or looking
at the MR in gitlab), and see how it's now much more coherent.

** If it goes wrong

The git UI isn't as friendly as it might be, and sometimes a rebase
will go wrong. Most commonly, this is a conflict, similar to how you
get merge conflicts sometimes. In this case, git will stop and tell
you about the conflict, and you can use ~git status~ and ~git diff~ to
inspect the state of your working tree. As with merge conflicts, git
will leave ~<<<<<<~ markers round conflicted areas; sort these out by
hand, ~git add~ the relevant files, and then you can tell git to carry
on with the rebase with ~git rebase --continue~. If this looks like
too much work, or you think it's going horribly wrong, you can always
do ~git rebase --abort~ which will put you back where you started.

If in any doubt *don't push the result*, and ask a colleague for
help. Most errors can be fixed before they've been pushed, and it can
be harder to sort a mess out once its been pushed (and then pulled by
other people). Have fun :-)
123
124
125
126
127
128
129
130
131

** Copying this Repository to try the examples yourself

You may be able to straighforwardly "fork" this repo on gitlab, but it
can be a bit fiddly — for example, you can't fork a copy of your own
repository into your own space, because the fork must have the same
name as the original. To make a copy, you can do the following:

1. Make a new "project" in gitlab in your user area. For this example,
132
   we'll call it ~deleteme~ in the ~MVernon~ user area
133
2. Make a bare clone of the original readme:
134
   ~git clone --bare git@gitlab.wikimedia.org:MVernon/rebasing_demo.git~
135
3. Do a mirror push from that clone to your new repository:
136
   ~git push --mirror git@gitlab.wikimedia.org:MVernon/deleteme~
137
138
4. Delete the original bare clone
5. Clone your new repository:
139
   ~git clone git@gitlab.wikimedia.org:MVernon/deleteme~
140
141
142
143

You'll then have your own respository with all the branches in place -
you can use the gitlab UI to turn them into merge requests in the
usual way.
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
** Copyright

Copyright (C) 2017 Genome Research Limited\\
Author: Matthew Vernon <mv3@sanger.ac.uk>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see http://www.gnu.org/licenses/