Skip to content

Commit f10a7d7

Browse files
authored
Merge pull request #168 from mhagger/markdown
Convert the README and TODO to markdown
2 parents 4554378 + c83841a commit f10a7d7

6 files changed

Lines changed: 404 additions & 666 deletions

File tree

Makefile

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,5 @@
1-
RST := \
2-
README.rst \
3-
TODO.rst
4-
51
all:
62

7-
html: $(RST:.rst=.html)
8-
9-
%.html: %.rst
10-
rst2html $< >$@
11-
12-
133
module := doc/presentations/GitMerge-2013
144

155
html: $(module)/talk.html

README.md

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
# git-imerge -- incremental merge and rebase for Git
2+
3+
Perform a merge between two branches incrementally. If conflicts are encountered, figure out exactly which pairs of commits conflict, and present the user with one pairwise conflict at a time for resolution.
4+
5+
`git-imerge` has two primary design goals:
6+
7+
* Reduce the pain of resolving merge conflicts to its unavoidable minimum, by finding and presenting the smallest possible conflicts: those between the changes introduced by one commit from each branch.
8+
9+
* Allow a merge to be saved, tested, interrupted, published, and collaborated on while it is in progress.
10+
11+
I think that it is easiest to understand the concept of incremental merging visually, and therefore I recommend the video of my [git-imerge presentation from the GitMerge 2013 conference](http://www.youtube.com/watch?v=FMZ2_-Ny_zc) (20 min) as a good place to start. The full slides for that talk are available in this repository under `doc/presentations/GitMerge-2013`. At the same conference, I was interviewed about `git-imerge` by Thomas Ferris Nicolaisen for his [GitMinutes Podcast #12](http://episodes.gitminutes.com/2013/06/gitminutes-12-git-merge-2013-part-4.html).
12+
13+
To learn how to use the `git-imerge` tool itself, I suggest the blog article [git-imerge: A Practical Introduction](http://softwareswirl.blogspot.com/2013/05/git-imerge-practical-introduction.html) and also typing `git-imerge --help` and `git-imerge SUBCOMMAND --help`. If you want more information, the theory and benefits of incremental merging are described in minute detail in a series of blog articles [[1](#REF1)], as are the benefits of retaining history when doing a rebase [[2](#REF2)].
14+
15+
Multiple incremental merges can be in progress at the same time. Each incremental merge has a name, and its progress is recorded in the Git repository as references under `refs/imerge/NAME`. The current state of an incremental merge can be visualized using the `diagram` command.
16+
17+
An incremental merge can be interrupted and resumed arbitrarily, or even pushed to a server to allow somebody else to work on it.
18+
19+
`git-imerge` comes with a Bash completion script, `completions/git-imerge`, which is installed automatically when installing `git-imerge`.
20+
21+
22+
## Requirements
23+
24+
`git-imerge` requires:
25+
26+
* A Python interpreter; either
27+
28+
* Python 3.x, version 3.3 or later.
29+
30+
* Python 2.x, version 2.6 or later. If you are using Python 2.6.x, then you have to install the `argparse` module yourself, as it was only added to the standard library in Python 2.7.
31+
32+
* A recent version of Git.
33+
34+
Bash completion requires Git's completion being available.
35+
36+
37+
## Installation
38+
39+
`git-imerge` is available on PyPI_, so you can install it with `pip`:
40+
41+
$ pip install git-imerge
42+
43+
44+
or using `setup.py` if you have downloaded the source package locally:
45+
46+
$ python setup.py install
47+
48+
49+
## Instructions
50+
51+
To start a merge or rebase operation using `git-imerge`, you use commands that are similar to the corresponding `git` commands:
52+
53+
| `git-imerge` command | `git` analogue | Effect |
54+
| -------------------- | -------------- | ------ |
55+
| `git-imerge merge BRANCH` | `git merge BRANCH` | Merge ``BRANCH`` into the current branch |
56+
| `git-imerge rebase BRANCH` | `git rebase BRANCH` | Rebase the current branch on top of ``BRANCH`` |
57+
| `git-imerge revert COMMIT` | `git revert COMMIT` | Add a new commit that undoes the effect of `COMMIT` |
58+
| `git-imerge revert COMMIT1..COMMIT2` | `git revert COMMIT1..COMMIT2` | Add new commits that undo the effects of `COMMIT1..COMMIT2` |
59+
| `git-imerge drop COMMIT` | `git rebase --onto COMMIT^ COMMIT` | Entirely delete commit `COMMIT` from the history of the current branch |
60+
| `git-imerge drop COMMIT1..COMMIT2` | `git rebase --onto COMMIT1 COMMIT2` | Entirely delete commits ``COMMIT1..COMMIT2`` from the history of the current branch |
61+
62+
`git-imerge drop` is also analogous to running `git rebase --interactive`, then deleting the specified commit(s) from the history. Both the `drop` and the `revert` subcommands are included in git-imerge because the equivalent git operations can conflict, so they both can benefit from using the incremental merge approach.)
63+
64+
A few more options are available if you start the incremental merge using `git imerge start`:
65+
66+
$ git-imerge start --name=NAME --goal=GOAL [--first-parent] BRANCH
67+
68+
where
69+
70+
* `NAME` is the name for this merge (and also the default name of the branch to which the results will be saved).
71+
72+
* `GOAL` describes how you want to simplify the results (see next section).
73+
74+
After the incremental merge is started, you will be presented with any conflicts that have to be resolved. The basic procedure is similar to performing an incremental merge using `git`:
75+
76+
while not done:
77+
<fix the conflict that is presented to you>
78+
<"git add" the files that you changed>
79+
git-imerge continue
80+
81+
When you have resolved all of the conflicts, you finish the incremental merge by typing:
82+
83+
git-imerge finish
84+
85+
That should be enough to get you going. All of these subcommands have additional options; to learn about them type:
86+
87+
git-imerge --help
88+
git-imerge SUBCMD --help
89+
90+
91+
### Simplifying results
92+
93+
When the incremental merge is finished, you can simplify its results in various ways before recording it in your project's permanent history by using either the `finish` or `simplify` command. The "goal" of the incremental merge can be one of the following:
94+
95+
* `merge` — keep only a simple merge of the second branch into the first branch, discarding all intermediate merges. The end result is similar to what you would get from
96+
97+
git checkout BRANCH1
98+
git merge BRANCH2
99+
100+
* `rebase` — keep the versions of the commits from the second branch rebased onto the first branch. The end result is similar to what you would get from
101+
102+
git checkout BRANCH2
103+
git rebase BRANCH1
104+
105+
* `rebase-with-history` — like `rebase`, except that it retains the old versions of the rebased commits in the history. It is equivalent to merging the commits from `BRANCH2` into `BRANCH1`, one commit at a time. In other words, it transforms this:
106+
107+
o---o---o---o BRANCH1
108+
\
109+
A---B---C---D BRANCH2
110+
111+
into this:
112+
113+
o---o---o---o---A'--B'--C'--D' NEW_BRANCH
114+
\ / / / /
115+
--------A---B---C---D
116+
117+
It is safe to rebase an already-published branch using this
118+
approach. See [[2](#REF2)] for more information.
119+
120+
* `full` — don't simplify the incremental merge at all: do all of the intermediate merges and retain them all in the permanent history. In other words, it transforms this:
121+
122+
o---o---1---2---3 BRANCH1
123+
\
124+
A---B---C---D BRANCH2
125+
126+
into this:
127+
128+
o---o---1---2---3
129+
\ \ \ \
130+
A---A1--A2--A3
131+
\ \ \ \
132+
B---B1--B2--B3
133+
\ \ \ \
134+
C---C1--C2--C3
135+
\ \ \ \
136+
D---D1--D2--D3 NEW_BRANCH
137+
138+
This approach retains the complete history and ancestry information, which gives the maximum flexibility for conducting future merges. On the other hand, it clutters up the permanent Git history considerably.
139+
140+
* `border` — this experimental goal retains the rebase of `BRANCH2` onto `BRANCH1` and also the rebase of `BRANCH1` onto `BRANCH2`, plus a merge commit that includes both branches. In other words, it transforms this:
141+
142+
o---o---1---2---3 BRANCH1
143+
\
144+
A---B---C---D BRANCH2
145+
146+
into this:
147+
148+
o---o---1---2---3
149+
\ \
150+
A A2
151+
\ \
152+
B B2
153+
\ \
154+
C C2
155+
\ \
156+
D---D1--D2--D3 NEW_BRANCH
157+
158+
This approach leaves more history than a simple merge or rebase, possibly making future merges easier.
159+
160+
* `border-with-history` — this experimental goal retains the `rebase-with-history of` `BRANCH2` onto `BRANCH1` and also the rebase (without history) of `BRANCH1` onto `BRANCH2`, plus a merge commit that includes both branches. In other words, it transforms this:
161+
162+
o---o---1---2---3 BRANCH1
163+
\
164+
A---B---C---D BRANCH2
165+
166+
into this:
167+
168+
o---o---1---2---3
169+
\ \
170+
A-----------A3
171+
\ \
172+
B-----------B3
173+
\ \
174+
C-----------C3
175+
\ \
176+
D---D1--D2--D3 NEW_BRANCH
177+
178+
This approach leaves more history and ancestry information than a simple merge or rebase, possibly making future merges easier.
179+
180+
* `border-with-history2` — this experimental goal retains the `rebase-with-history` of `BRANCH1` onto `BRANCH2` and also the `rebase-with-history` of `BRANCH2` onto `BRANCH1`, plus a merge commit that includes both branches. In other words, it transforms this:
181+
182+
o---o---1---2---3 BRANCH1
183+
\
184+
A---B---C---D BRANCH2
185+
186+
into this:
187+
188+
o---o---1---2---3
189+
\ \ \ \
190+
A--- --- ---A3
191+
\ \ \ \
192+
B--- --- ---B3
193+
\ \ \ \
194+
C--- --- ---C3
195+
\ \ \ \
196+
D---D1--D2--D3 NEW_BRANCH
197+
198+
This approach leaves more history and ancestry information than a simple merge or rebase, possibly making future merges easier.
199+
200+
201+
## Technical notes
202+
203+
### Suspending/resuming
204+
205+
When `git-imerge` needs to ask the user to do a merge manually, it creates a temporary branch `refs/heads/imerge/NAME` to hold the result. If you want to suspend an incremental merge to do something else before continuing, all you need to do is abort any pending merge using `git merge --abort` and switch to your other branch. When you are ready to resume the incremental merge, just type `git imerge continue`.
206+
207+
If you need to completely abort an in-progress incremental merge, first remove the temporary branches `git-imerge` creates using `git-imerge remove`, then checkout the branch you were in before you started the incremental merge with `git checkout ORIGINAL_BRANCH`.
208+
209+
210+
### Storage
211+
212+
`git-imerge` records all of the intermediate state about an incremental merge in the Git object database as a bunch of references under `refs/imerge/NAME`, where `NAME` is the name of the imerge:
213+
214+
* `refs/imerge/NAME/state` points to a blob that describes the current state of the imerge in JSON format; for example,
215+
216+
* The tips of the two branches that are being merged
217+
218+
* The current "blocker" merges (merges that the user will have to do by hand), if any
219+
220+
* The simplification goal
221+
222+
* The name of the branch to which the result will be written.
223+
224+
* `refs/imerge/NAME/manual/I-J` and `refs/imerge/NAME/auto/I-J` refer to the manual and automatic merge commits, respectively, that have been done so far as part of the incremental merge. `I` and `J` are integers indicating the location `(I,J)` of the merge in the incremental merge diagram.
225+
226+
227+
### Transferring an in-progress imerge between repositories
228+
229+
It might sometimes be convenient to transfer an in-progress incremental merge from one Git repository to another. For example, you might want to make a backup of the current state, or continue an imerge at home that you started at work, or ask a colleague to do a particular pairwise merge for you. Since all of the imerge state is stored in the Git object database, this can be done by pushing/fetching the references named in the previous section. For example,
230+
231+
$ git push --prune origin +refs/imerge/NAME/*:refs/imerge/NAME/*
232+
233+
or
234+
235+
$ git fetch --prune origin +refs/imerge/NAME/*:refs/imerge/NAME/*
236+
237+
Please note that these commands _overwrite_ any state that already existed in the destination repository. There is currently no support for combining the work done by two people in parallel on an incremental merge, so for now you'll just have to take turns.
238+
239+
240+
### Interaction with `git rerere`
241+
242+
`git rerere` is a nice tool that records how you resolve merge conflicts, and if it sees the same conflict again it tries to automatically reuse the same resolution.
243+
244+
Since `git-imerge` attempts so many similar test merges, it is easy to imagine `rerere` getting confused. Moreover, `git-imerge` relies on a merge resolving (or not resolving) consistently if it is carried out more than once. Having `rerere` store extra information behind the scenes could therefore confuse `git-imerge`.
245+
246+
Indeed, in testing it appeared that during incremental merges, the interaction of `git-imerge` with `rerere` was sometimes causing merge conflicts to be resolved incorrectly. Therefore, `git-imerge` explicitly turns rerere off temporarily whenever it runs any `git` commands.
247+
248+
249+
### Log messages for pairwise merge commits
250+
251+
When `git imerge continue` or `git imerge record` finds a resolved merge in the working tree, it commits that merge then incorporates it into the incremental merge. Usually it just uses Git's autogenerated commit message for such commits. If you want to be prompted to edit such commit messages, you can either specify `--edit` on the command line or change the default in your configuration:
252+
253+
$ git config --global imerge.editmergemessages true
254+
255+
256+
## Testing
257+
258+
`git-imerge` uses [`tox`](https://tox.readthedocs.io/) to run tests. To run the test suite with the system's default Python:
259+
260+
$ tox
261+
262+
To run with a specific Python version, such as 3.7, pass the `-e` argument to `tox`:
263+
264+
$ tox -e py37
265+
266+
267+
## License
268+
269+
`git-imerge` is released as open-source software under the GNU General Public License (GPL), version 2 or later. See file `COPYING` for more information.
270+
271+
272+
## References
273+
274+
<a name="REF1">[1]</a>
275+
* http://softwareswirl.blogspot.com/2012/12/the-conflict-frontier-of-nightmare-merge.html
276+
* http://softwareswirl.blogspot.com/2012/12/mapping-merge-conflict-frontier.html
277+
* http://softwareswirl.blogspot.com/2012/12/real-world-conflict-diagrams.html
278+
* http://softwareswirl.blogspot.com/2013/05/git-incremental-merge.html
279+
* http://softwareswirl.blogspot.com/2013/05/one-merge-to-rule-them-all.html
280+
* http://softwareswirl.blogspot.com/2013/05/incremental-merge-vs-direct-merge-vs.html
281+
* http://softwareswirl.blogspot.com/2013/05/git-imerge-practical-introduction.html
282+
283+
<a name="REF2">[2]</a>
284+
* http://softwareswirl.blogspot.com/2009/04/truce-in-merge-vs-rebase-war.html
285+
* http://softwareswirl.blogspot.com/2009/08/upstream-rebase-just-works-if-history.html
286+
* http://softwareswirl.blogspot.com/2009/08/rebase-with-history-implementation.html

0 commit comments

Comments
 (0)