File: test-transactions.t

package info (click to toggle)
hg-git 1.0.1-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,432 kB
  • sloc: python: 8,200; sh: 185; makefile: 23
file content (239 lines) | stat: -rw-r--r-- 6,416 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
Transactions
============

This test excercises our transaction logic, and the behaviour when a
conversion fails or is interrupted.

Load commonly used test logic
  $ . "$TESTDIR/testutil"

Enable a few other extensions:

  $ cat >> $HGRCPATH <<EOF
  > [extensions]
  > breakage = $TESTDIR/testlib/ext-break-git-import.py
  > strip =
  > EOF

Create a git repository with 100 commits, that touches 10 different
files. We also have 10 tags.

  $ git init gitrepo
  Initialized empty Git repository in $TESTTMP/gitrepo/.git/
  $ cd gitrepo
  $ for i in $(seq 10)
  > do
  >   for f in $(seq 10)
  >   do
  >     n=$(expr $i \* $f)
  >     echo $n > $f
  >     git add $f
  >     fn_git_commit -m $n
  >   done
  >   fn_git_tag -m $i v$i
  > done
  $ cd ..

Moving or adding the Git pack
-----------------------------

As an optimisation, we want to move in the Git pack when it is safe to
do so. In a normal pull, the pack might be thin so you have to add it.
However, we know that we always created the repository in an initial
clone, so we can avoid the extra overhead.

Cloning into a new repository is definitely safe:

  $ rm -rf hgrepo
  $ hg clone -r v1 gitrepo hgrepo --debug \
  > | grep -e "git pack"
  moving git pack into $TESTTMP/hgrepo/.hg/git
  $ rm -rf hgrepo

Pulling isn't safe:

  $ hg clone -r v1 gitrepo hgrepo --quiet
  $ hg -R hgrepo pull -r v2 --debug \
  > | grep -e "git pack"
  adding git pack to $TESTTMP/hgrepo/.hg/git
  $ rm -rf hgrepo

Cloning with git.intree is also safe:

  $ hg clone -r v1 gitrepo --config git.intree=yes hgrepo --debug \
  > | grep -e "git pack"
  moving git pack into $TESTTMP/hgrepo/.git
  $ rm -rf hgrepo

The sanity check below shows why it's safe, as a preexisting git
repository prevents cloning into the directory:

  $ git init -q hgrepo
  $ hg clone gitrepo --config git.intree=yes hgrepo
  abort: destination 'hgrepo' is not empty
  [255]
  $ hg clone $TESTTMP/gitrepo --config git.intree=yes --cwd hgrepo .
  abort: destination '.' is not empty
  [255]
  $ rm -rf hgrepo

Map saving
----------

First, test that hggit.mapsavefrequency actually works

clone with mapsavefreq set

  $ hg clone gitrepo hgrepo --config hggit.mapsavefrequency=10 --debug \
  > | grep -c saving
  1
  $ rm -rf hgrepo

pull with mapsavefreq set

  $ hg init hgrepo
  $ cat >> hgrepo/.hg/hgrc <<EOF
  > [paths]
  > default = $TESTTMP/gitrepo
  > EOF
  $ hg -R hgrepo --config hggit.mapsavefrequency=10 pull --debug \
  > | grep -c saving
  10
  $ rm -rf hgrepo

The user experience
-------------------

The map save interval affects how and when changes are reported to the
user.

First, create a repository, set up to pull from git, and where we can interrupt the conversion.

  $ hg init hgrepo
  $ cat >> hgrepo/.hg/hgrc <<EOF
  > [paths]
  > default = $TESTTMP/gitrepo
  > EOF
  $ cd hgrepo

A low save interval causes a lot of reports:

  $ hg --config hggit.mapsavefrequency=25 pull
  pulling from $TESTTMP/gitrepo
  importing 100 git commits
  new changesets 1c8407413fa3:abc468b9e51b (25 drafts)
  new changesets 217c308baf47:d5d14eeedd08 (25 drafts)
  new changesets d9807ef6abcb:4678067bd500 (25 drafts)
  adding bookmark master
  new changesets c31a154888bb:eda59117ba04 (25 drafts)
  (run 'hg update' to get a working copy)

Reset the repository

  $ hg strip --no-backup 'all()'
  $ hg gclear
  clearing out the git cache data

And with phases? No mention of draft changesets, as we publish changes
during the conversion:

  $ hg --config hggit.mapsavefrequency=25 --config hggit.usephases=yes pull
  pulling from $TESTTMP/gitrepo
  importing 100 git commits
  new changesets 1c8407413fa3:abc468b9e51b
  new changesets 217c308baf47:d5d14eeedd08
  new changesets d9807ef6abcb:4678067bd500
  updating bookmark master
  new changesets c31a154888bb:eda59117ba04
  (run 'hg update' to get a working copy)

Reset the repository

  $ hg strip --no-backup 'all()'
  $ hg gclear
  clearing out the git cache data

Interruptions
-------------

How does hg-git behave if a conversion fails or is interrupted?

Ideally, we would always save the results of whatever happened, but
that causes a significant slowdown. Transactions are an important
optimisation within Mercurial.

Test an error in a pull:

  $ ABORT_AFTER=99 hg pull
  pulling from $TESTTMP/gitrepo
  importing 100 git commits
  transaction abort!
  rollback completed
  abort: aborted after 99 commits!
  [255]
  $ hg log -l 10 -T '{rev} {gitnode}\n'

Test the user exiting in the first transaction:

  $ EXIT_AFTER=5 hg --config hggit.mapsavefrequency=10 pull
  pulling from $TESTTMP/gitrepo
  importing 100 git commits
  transaction abort!
  rollback completed
  interrupted!
  [255]
  $ hg log -l 10 -T '{rev} {gitnode}\n'

Check that we have no state, but clear it just in case

  $ ls -d .hg/git*
  .hg/git
  $ hg gclear
  clearing out the git cache data

Test the user exiting in the middle of a conversion, after the first
transaction:

  $ EXIT_AFTER=15 hg --config hggit.mapsavefrequency=10 pull
  pulling from $TESTTMP/gitrepo
  importing 100 git commits
  new changesets 1c8407413fa3:7c8c534a5fbe (10 drafts)
  transaction abort!
  rollback completed
  interrupted!
  [255]
  $ hg log -l 10 -T '{rev} {gitnode}\n'
  9 7cbb16ec981b308e1e2b181f8e1f22c8f409f44e
  8 42da70ed92bbecf9f348ba59c93646be723d0bf2
  7 17e841146e5744b81af9959634d82c20a5d7df52
  6 c31065bf97bf014815e37cdfbdef2c32c687f314
  5 fcf21b8e0520ec1cced1d7593d13f9ee54721269
  4 46acd02d0352e4b92bd6a099bb0490305d847a18
  3 61eeda444b37b8aa3892d5f04c66c5441d21dd66
  2 e55db11bb0472791c7af3fc636772174cdea4a36
  1 17a2672b3c24c02d568f99d8d55ccae2bf362d5c
  0 4e195b4c6e77604b70a8ad3b01306adbb9b1c7e7
  $ cd ..
  $ rm -rf hgrepo

And with a clone into an existing directory using an in-tree
repository. Mercurial deletes the repository on errors, and so should
we do with the Git repository, ideally. The current design doesn't
make that easy to do, so this test mostly exists to document the
current behaviour.

  $ mkdir hgrepo
  $ EXIT_AFTER=15 \
  > hg --config hggit.mapsavefrequency=10 --config git.intree=yes \
  > --cwd hgrepo \
  > clone -U $TESTTMP/gitrepo .
  importing 100 git commits
  transaction abort!
  rollback completed
  interrupted!
  [255]
the leftover below only appears in Mercurial 5.9+; it is unintentional
TODO: once the first rc is released, change (?) to (hg59 !)
  $ ls -A hgrepo
  .git (?)
  $ rm -rf hgrepo