Fossil SCM

Work around the seemingly buggy behavior of git-fast-export with regard to tags when doing an import.

drh 2011-02-16 15:00 trunk
Commit 496aacd10efc8ef2def0342282bd2d437dbf5fbb
1 file changed +65 -6
+65 -6
--- src/import.c
+++ src/import.c
@@ -58,10 +58,11 @@
5858
char **azMerge; /* Merge values */
5959
int nFile; /* Number of aFile values */
6060
int nFileAlloc; /* Number of slots in aFile[] */
6161
ImportFile *aFile; /* Information about files in a commit */
6262
int fromLoaded; /* True zFrom content loaded into aFile[] */
63
+ int tagCommit; /* True if the commit adds a tag */
6364
} gg;
6465
6566
/*
6667
** Duplicate a string.
6768
*/
@@ -148,16 +149,16 @@
148149
blob_reset(&cmpr);
149150
rid = db_last_insert_rowid();
150151
}
151152
if( zMark ){
152153
db_multi_exec(
153
- "INSERT OR IGNORE INTO xtag(tname, trid, tuuid)"
154
+ "INSERT OR IGNORE INTO xmark(tname, trid, tuuid)"
154155
"VALUES(%Q,%d,%B)",
155156
zMark, rid, &hash
156157
);
157158
db_multi_exec(
158
- "INSERT OR IGNORE INTO xtag(tname, trid, tuuid)"
159
+ "INSERT OR IGNORE INTO xmark(tname, trid, tuuid)"
159160
"VALUES(%B,%d,%B)",
160161
&hash, rid, &hash
161162
);
162163
}
163164
if( saveUuid ){
@@ -244,29 +245,54 @@
244245
zFromBranch = db_text(0, "SELECT brnm FROM xbranch WHERE tname=%Q",
245246
gg.zFromMark);
246247
}else{
247248
zFromBranch = 0;
248249
}
249
- if( fossil_strcmp(zFromBranch, gg.zBranch)!=0 ){
250
+ if( !gg.tagCommit && fossil_strcmp(zFromBranch, gg.zBranch)!=0 ){
250251
blob_appendf(&record, "T *branch * %F\n", gg.zBranch);
251252
blob_appendf(&record, "T *sym-%F *\n", gg.zBranch);
252253
if( zFromBranch ){
253254
blob_appendf(&record, "T -sym-%F *\n", zFromBranch);
254255
}
255256
}
256257
free(zFromBranch);
257258
if( gg.zFrom==0 ){
258
- blob_appendf(&record, "T +sym-trunk *\n");
259
+ blob_appendf(&record, "T *sym-trunk *\n");
259260
}
260261
db_multi_exec("INSERT INTO xbranch(tname, brnm) VALUES(%Q,%Q)",
261262
gg.zMark, gg.zBranch);
262263
blob_appendf(&record, "U %F\n", gg.zUser);
263264
md5sum_blob(&record, &cksum);
264265
blob_appendf(&record, "Z %b\n", &cksum);
265266
fast_insert_content(&record, gg.zMark, 1);
266267
blob_reset(&record);
267268
blob_reset(&cksum);
269
+
270
+ /* The "git fast-export" command might output multiple "commit" lines
271
+ ** that reference a tag using "refs/tags/TAGNAME". The tag should only
272
+ ** be applied to the last commit that is output. The problem is we do not
273
+ ** know at this time if the current commit is the last one to hold this
274
+ ** tag or not. So make an entry in the XTAG table to record this tag
275
+ ** but overwrite that entry if a later instance of the same tag appears.
276
+ **
277
+ ** This behavior seems like a bug in git-fast-export, but it is easier
278
+ ** to work around the problem than to fix git-fast-export.
279
+ */
280
+ if( gg.tagCommit && gg.zDate && gg.zUser && gg.zFrom ){
281
+ blob_appendf(&record, "D %s\n", gg.zDate);
282
+ blob_appendf(&record, "T +sym-%F %s\n", gg.zBranch, gg.zPrevCheckin);
283
+ blob_appendf(&record, "U %F\n", gg.zUser);
284
+ md5sum_blob(&record, &cksum);
285
+ blob_appendf(&record, "Z %b\n", &cksum);
286
+ db_multi_exec(
287
+ "INSERT OR REPLACE INTO xtag(tname, tcontent)"
288
+ " VALUES(%Q,%Q)", gg.zBranch, blob_str(&record)
289
+ );
290
+ blob_reset(&record);
291
+ blob_reset(&cksum);
292
+ }
293
+
268294
fossil_free(gg.zPrevBranch);
269295
gg.zPrevBranch = gg.zBranch;
270296
gg.zBranch = 0;
271297
import_reset(0);
272298
}
@@ -326,11 +352,11 @@
326352
** Convert a "mark" or "committish" into the UUID.
327353
*/
328354
static char *resolve_committish(const char *zCommittish){
329355
char *zRes;
330356
331
- zRes = db_text(0, "SELECT tuuid FROM xtag WHERE tname=%Q", zCommittish);
357
+ zRes = db_text(0, "SELECT tuuid FROM xmark WHERE tname=%Q", zCommittish);
332358
return zRes;
333359
}
334360
335361
/*
336362
** Create a new entry in the gg.aFile[] array
@@ -425,11 +451,13 @@
425451
gg.xFinish();
426452
gg.xFinish = finish_commit;
427453
trim_newline(&zLine[7]);
428454
z = &zLine[7];
429455
for(i=strlen(z)-1; i>=0 && z[i]!='/'; i--){}
456
+ gg.tagCommit = memcmp(&z[i-4], "tags", 4)==0;
430457
if( z[i+1]!=0 ) z += i+1;
458
+ if( fossil_strcmp(z, "master")==0 ) z = "trunk";
431459
gg.zBranch = fossil_strdup(z);
432460
gg.fromLoaded = 0;
433461
}else
434462
if( memcmp(zLine, "tag ", 4)==0 ){
435463
gg.xFinish();
@@ -631,11 +659,13 @@
631659
** in the future.
632660
*/
633661
void git_import_cmd(void){
634662
char *zPassword;
635663
FILE *pIn;
664
+ Stmt q;
636665
int forceFlag = find_option("force", "f", 0)!=0;
666
+
637667
find_option("git",0,0); /* Skip the --git option for now */
638668
verify_all_options();
639669
if( g.argc!=3 && g.argc!=4 ){
640670
usage("REPOSITORY-NAME");
641671
}
@@ -647,17 +677,46 @@
647677
}
648678
if( forceFlag ) unlink(g.argv[2]);
649679
db_create_repository(g.argv[2]);
650680
db_open_repository(g.argv[2]);
651681
db_open_config(0);
682
+
683
+ /* The following temp-tables are used to hold information needed for
684
+ ** the import.
685
+ **
686
+ ** The XMARK table provides a mapping from fast-import "marks" and symbols
687
+ ** into artifact ids (UUIDs - the 40-byte hex SHA1 hash of artifacts).
688
+ ** Given any valid fast-import symbol, the corresponding fossil rid and
689
+ ** uuid can found by searching against the xmark.tname field.
690
+ **
691
+ ** The XBRANCH table maps commit marks and symbols into the branch those
692
+ ** commits belong to. If xbranch.tname is a fast-import symbol for a
693
+ ** check-in then xbranch.brnm is the branch that checkin is part of.
694
+ **
695
+ ** The XTAG table records information about tags that need to be applied
696
+ ** to various branches after the import finishes. The xtag.tcontent field
697
+ ** contains the text of an artifact that will add a tag to a check-in.
698
+ ** These artifacts should all be added at the end of the import.
699
+ */
652700
db_multi_exec(
653
- "CREATE TEMP TABLE xtag(tname TEXT UNIQUE, trid INT, tuuid TEXT);"
701
+ "CREATE TEMP TABLE xmark(tname TEXT UNIQUE, trid INT, tuuid TEXT);"
654702
"CREATE TEMP TABLE xbranch(tname TEXT UNIQUE, brnm TEXT);"
703
+ "CREATE TEMP TABLE xtag(tname TEXT UNIQUE, tcontent TEXT);"
655704
);
705
+
706
+
656707
db_begin_transaction();
657708
db_initial_setup(0, 0, 1);
658709
git_fast_import(pIn);
710
+ db_prepare(&q, "SELECT tcontent FROM xtag");
711
+ while( db_step(&q)==SQLITE_ROW ){
712
+ Blob record;
713
+ db_ephemeral_blob(&q, 0, &record);
714
+ fast_insert_content(&record, 0, 0);
715
+ import_reset(0);
716
+ }
717
+ db_finalize(&q);
659718
db_end_transaction(0);
660719
db_begin_transaction();
661720
printf("Rebuilding repository meta-data...\n");
662721
rebuild_db(0, 1, 1);
663722
verify_cancel();
664723
--- src/import.c
+++ src/import.c
@@ -58,10 +58,11 @@
58 char **azMerge; /* Merge values */
59 int nFile; /* Number of aFile values */
60 int nFileAlloc; /* Number of slots in aFile[] */
61 ImportFile *aFile; /* Information about files in a commit */
62 int fromLoaded; /* True zFrom content loaded into aFile[] */
 
63 } gg;
64
65 /*
66 ** Duplicate a string.
67 */
@@ -148,16 +149,16 @@
148 blob_reset(&cmpr);
149 rid = db_last_insert_rowid();
150 }
151 if( zMark ){
152 db_multi_exec(
153 "INSERT OR IGNORE INTO xtag(tname, trid, tuuid)"
154 "VALUES(%Q,%d,%B)",
155 zMark, rid, &hash
156 );
157 db_multi_exec(
158 "INSERT OR IGNORE INTO xtag(tname, trid, tuuid)"
159 "VALUES(%B,%d,%B)",
160 &hash, rid, &hash
161 );
162 }
163 if( saveUuid ){
@@ -244,29 +245,54 @@
244 zFromBranch = db_text(0, "SELECT brnm FROM xbranch WHERE tname=%Q",
245 gg.zFromMark);
246 }else{
247 zFromBranch = 0;
248 }
249 if( fossil_strcmp(zFromBranch, gg.zBranch)!=0 ){
250 blob_appendf(&record, "T *branch * %F\n", gg.zBranch);
251 blob_appendf(&record, "T *sym-%F *\n", gg.zBranch);
252 if( zFromBranch ){
253 blob_appendf(&record, "T -sym-%F *\n", zFromBranch);
254 }
255 }
256 free(zFromBranch);
257 if( gg.zFrom==0 ){
258 blob_appendf(&record, "T +sym-trunk *\n");
259 }
260 db_multi_exec("INSERT INTO xbranch(tname, brnm) VALUES(%Q,%Q)",
261 gg.zMark, gg.zBranch);
262 blob_appendf(&record, "U %F\n", gg.zUser);
263 md5sum_blob(&record, &cksum);
264 blob_appendf(&record, "Z %b\n", &cksum);
265 fast_insert_content(&record, gg.zMark, 1);
266 blob_reset(&record);
267 blob_reset(&cksum);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268 fossil_free(gg.zPrevBranch);
269 gg.zPrevBranch = gg.zBranch;
270 gg.zBranch = 0;
271 import_reset(0);
272 }
@@ -326,11 +352,11 @@
326 ** Convert a "mark" or "committish" into the UUID.
327 */
328 static char *resolve_committish(const char *zCommittish){
329 char *zRes;
330
331 zRes = db_text(0, "SELECT tuuid FROM xtag WHERE tname=%Q", zCommittish);
332 return zRes;
333 }
334
335 /*
336 ** Create a new entry in the gg.aFile[] array
@@ -425,11 +451,13 @@
425 gg.xFinish();
426 gg.xFinish = finish_commit;
427 trim_newline(&zLine[7]);
428 z = &zLine[7];
429 for(i=strlen(z)-1; i>=0 && z[i]!='/'; i--){}
 
430 if( z[i+1]!=0 ) z += i+1;
 
431 gg.zBranch = fossil_strdup(z);
432 gg.fromLoaded = 0;
433 }else
434 if( memcmp(zLine, "tag ", 4)==0 ){
435 gg.xFinish();
@@ -631,11 +659,13 @@
631 ** in the future.
632 */
633 void git_import_cmd(void){
634 char *zPassword;
635 FILE *pIn;
 
636 int forceFlag = find_option("force", "f", 0)!=0;
 
637 find_option("git",0,0); /* Skip the --git option for now */
638 verify_all_options();
639 if( g.argc!=3 && g.argc!=4 ){
640 usage("REPOSITORY-NAME");
641 }
@@ -647,17 +677,46 @@
647 }
648 if( forceFlag ) unlink(g.argv[2]);
649 db_create_repository(g.argv[2]);
650 db_open_repository(g.argv[2]);
651 db_open_config(0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
652 db_multi_exec(
653 "CREATE TEMP TABLE xtag(tname TEXT UNIQUE, trid INT, tuuid TEXT);"
654 "CREATE TEMP TABLE xbranch(tname TEXT UNIQUE, brnm TEXT);"
 
655 );
 
 
656 db_begin_transaction();
657 db_initial_setup(0, 0, 1);
658 git_fast_import(pIn);
 
 
 
 
 
 
 
 
659 db_end_transaction(0);
660 db_begin_transaction();
661 printf("Rebuilding repository meta-data...\n");
662 rebuild_db(0, 1, 1);
663 verify_cancel();
664
--- src/import.c
+++ src/import.c
@@ -58,10 +58,11 @@
58 char **azMerge; /* Merge values */
59 int nFile; /* Number of aFile values */
60 int nFileAlloc; /* Number of slots in aFile[] */
61 ImportFile *aFile; /* Information about files in a commit */
62 int fromLoaded; /* True zFrom content loaded into aFile[] */
63 int tagCommit; /* True if the commit adds a tag */
64 } gg;
65
66 /*
67 ** Duplicate a string.
68 */
@@ -148,16 +149,16 @@
149 blob_reset(&cmpr);
150 rid = db_last_insert_rowid();
151 }
152 if( zMark ){
153 db_multi_exec(
154 "INSERT OR IGNORE INTO xmark(tname, trid, tuuid)"
155 "VALUES(%Q,%d,%B)",
156 zMark, rid, &hash
157 );
158 db_multi_exec(
159 "INSERT OR IGNORE INTO xmark(tname, trid, tuuid)"
160 "VALUES(%B,%d,%B)",
161 &hash, rid, &hash
162 );
163 }
164 if( saveUuid ){
@@ -244,29 +245,54 @@
245 zFromBranch = db_text(0, "SELECT brnm FROM xbranch WHERE tname=%Q",
246 gg.zFromMark);
247 }else{
248 zFromBranch = 0;
249 }
250 if( !gg.tagCommit && fossil_strcmp(zFromBranch, gg.zBranch)!=0 ){
251 blob_appendf(&record, "T *branch * %F\n", gg.zBranch);
252 blob_appendf(&record, "T *sym-%F *\n", gg.zBranch);
253 if( zFromBranch ){
254 blob_appendf(&record, "T -sym-%F *\n", zFromBranch);
255 }
256 }
257 free(zFromBranch);
258 if( gg.zFrom==0 ){
259 blob_appendf(&record, "T *sym-trunk *\n");
260 }
261 db_multi_exec("INSERT INTO xbranch(tname, brnm) VALUES(%Q,%Q)",
262 gg.zMark, gg.zBranch);
263 blob_appendf(&record, "U %F\n", gg.zUser);
264 md5sum_blob(&record, &cksum);
265 blob_appendf(&record, "Z %b\n", &cksum);
266 fast_insert_content(&record, gg.zMark, 1);
267 blob_reset(&record);
268 blob_reset(&cksum);
269
270 /* The "git fast-export" command might output multiple "commit" lines
271 ** that reference a tag using "refs/tags/TAGNAME". The tag should only
272 ** be applied to the last commit that is output. The problem is we do not
273 ** know at this time if the current commit is the last one to hold this
274 ** tag or not. So make an entry in the XTAG table to record this tag
275 ** but overwrite that entry if a later instance of the same tag appears.
276 **
277 ** This behavior seems like a bug in git-fast-export, but it is easier
278 ** to work around the problem than to fix git-fast-export.
279 */
280 if( gg.tagCommit && gg.zDate && gg.zUser && gg.zFrom ){
281 blob_appendf(&record, "D %s\n", gg.zDate);
282 blob_appendf(&record, "T +sym-%F %s\n", gg.zBranch, gg.zPrevCheckin);
283 blob_appendf(&record, "U %F\n", gg.zUser);
284 md5sum_blob(&record, &cksum);
285 blob_appendf(&record, "Z %b\n", &cksum);
286 db_multi_exec(
287 "INSERT OR REPLACE INTO xtag(tname, tcontent)"
288 " VALUES(%Q,%Q)", gg.zBranch, blob_str(&record)
289 );
290 blob_reset(&record);
291 blob_reset(&cksum);
292 }
293
294 fossil_free(gg.zPrevBranch);
295 gg.zPrevBranch = gg.zBranch;
296 gg.zBranch = 0;
297 import_reset(0);
298 }
@@ -326,11 +352,11 @@
352 ** Convert a "mark" or "committish" into the UUID.
353 */
354 static char *resolve_committish(const char *zCommittish){
355 char *zRes;
356
357 zRes = db_text(0, "SELECT tuuid FROM xmark WHERE tname=%Q", zCommittish);
358 return zRes;
359 }
360
361 /*
362 ** Create a new entry in the gg.aFile[] array
@@ -425,11 +451,13 @@
451 gg.xFinish();
452 gg.xFinish = finish_commit;
453 trim_newline(&zLine[7]);
454 z = &zLine[7];
455 for(i=strlen(z)-1; i>=0 && z[i]!='/'; i--){}
456 gg.tagCommit = memcmp(&z[i-4], "tags", 4)==0;
457 if( z[i+1]!=0 ) z += i+1;
458 if( fossil_strcmp(z, "master")==0 ) z = "trunk";
459 gg.zBranch = fossil_strdup(z);
460 gg.fromLoaded = 0;
461 }else
462 if( memcmp(zLine, "tag ", 4)==0 ){
463 gg.xFinish();
@@ -631,11 +659,13 @@
659 ** in the future.
660 */
661 void git_import_cmd(void){
662 char *zPassword;
663 FILE *pIn;
664 Stmt q;
665 int forceFlag = find_option("force", "f", 0)!=0;
666
667 find_option("git",0,0); /* Skip the --git option for now */
668 verify_all_options();
669 if( g.argc!=3 && g.argc!=4 ){
670 usage("REPOSITORY-NAME");
671 }
@@ -647,17 +677,46 @@
677 }
678 if( forceFlag ) unlink(g.argv[2]);
679 db_create_repository(g.argv[2]);
680 db_open_repository(g.argv[2]);
681 db_open_config(0);
682
683 /* The following temp-tables are used to hold information needed for
684 ** the import.
685 **
686 ** The XMARK table provides a mapping from fast-import "marks" and symbols
687 ** into artifact ids (UUIDs - the 40-byte hex SHA1 hash of artifacts).
688 ** Given any valid fast-import symbol, the corresponding fossil rid and
689 ** uuid can found by searching against the xmark.tname field.
690 **
691 ** The XBRANCH table maps commit marks and symbols into the branch those
692 ** commits belong to. If xbranch.tname is a fast-import symbol for a
693 ** check-in then xbranch.brnm is the branch that checkin is part of.
694 **
695 ** The XTAG table records information about tags that need to be applied
696 ** to various branches after the import finishes. The xtag.tcontent field
697 ** contains the text of an artifact that will add a tag to a check-in.
698 ** These artifacts should all be added at the end of the import.
699 */
700 db_multi_exec(
701 "CREATE TEMP TABLE xmark(tname TEXT UNIQUE, trid INT, tuuid TEXT);"
702 "CREATE TEMP TABLE xbranch(tname TEXT UNIQUE, brnm TEXT);"
703 "CREATE TEMP TABLE xtag(tname TEXT UNIQUE, tcontent TEXT);"
704 );
705
706
707 db_begin_transaction();
708 db_initial_setup(0, 0, 1);
709 git_fast_import(pIn);
710 db_prepare(&q, "SELECT tcontent FROM xtag");
711 while( db_step(&q)==SQLITE_ROW ){
712 Blob record;
713 db_ephemeral_blob(&q, 0, &record);
714 fast_insert_content(&record, 0, 0);
715 import_reset(0);
716 }
717 db_finalize(&q);
718 db_end_transaction(0);
719 db_begin_transaction();
720 printf("Rebuilding repository meta-data...\n");
721 rebuild_db(0, 1, 1);
722 verify_cancel();
723

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button