forked from mackyle/topgit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
README
2792 lines (2235 loc) · 123 KB
/
README
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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
=========================================
TopGit -- A different patch queue manager
=========================================
DESCRIPTION
-----------
TopGit aims to make handling of large amounts of interdependent topic
branches easier. In fact, it is designed especially for the case where
you maintain a queue of third-party patches on top of another (perhaps
Git-controlled) project and want to easily organize, maintain and submit
them -- TopGit achieves that by keeping a separate topic branch for each
patch and providing some tools to maintain the branches.
See also:
:REQUIREMENTS_: Installation requirements
:SYNOPSIS_: Command line example session
:USAGE_: Command line details
:`NO UNDO`_: Where's the undo!!!
:CONVENTIONS_: Suggestions for organizing your TopGit branches
:`EXTRA SETTINGS`_: Various possible "topgit.*" config settings
:ALIASES_: Git-like TopGit command aliases
:NAVIGATION_: Getting around with "next" and "prev"
:`WAYBACK MACHINE`_: Turn back the clock and then come back
:GLOSSARY_: All the TopGit vocabulary in one place
:TECHNICAL_: How it works behind the scenes
:`TESTING TOPGIT`_: How to run the TopGit test suite
REQUIREMENTS
------------
TopGit is a collection of POSIX shell scripts so a POSIX-compliant shell is
required along with some standard POSIX-compliant utilities (e.g. sed, awk,
cat, etc.). Git version 1.8.5 or later is also required.
To use TopGit with linked working trees (the ``git worktree add`` command),
at least Git version 2.5.0 (obviously, since that's when the ``git worktree``
command first appeared) is needed in which case linked working trees are then
fully supported for use with TopGit.
The scripts need to be preprocessed and installed. The Makefile that does
this requires a POSIX make utility (using "``make``" and "``make install``")
and some version of ``perl`` in the ``PATH`` somewhere (the ``perl`` binary
is needed for correct help text file generation prior to the actual install).
Once installed, TopGit uses only POSIX-compliant utilities (except that it
also requires, obviously, Git).
Running the tests (see `TESTING TOPGIT`_) has the same requirements as for
installation (i.e. POSIX plus Perl).
It is possible to use the DESTDIR functionality to install TopGit to a
staging area on one machine, archive that and then unarchive it on another
machine to perform an install (provided the build prefix and other options are
compatible with the final installed location).
INSTALLATION
------------
See the file ``INSTALL``.
GIT REPOSITORY
--------------
The TopGit git repository can be found at <http://repo.or.cz/topgit/pro>.
RATIONALE
---------
Why not use something like StGIT or Guilt or ``rebase -i`` for maintaining
your patch queue? The advantage of these tools is their simplicity;
they work with patch *series* and defer to the reflog facility for
version control of patches (reordering of patches is not
version-controlled at all). But there are several disadvantages -- for
one, these tools (especially StGIT) do not actually fit well with plain
Git at all: it is basically impossible to take advantage of the index
effectively when using StGIT. But more importantly, these tools
horribly fail in the face of a distributed environment.
TopGit has been designed around three main tenets:
(i) TopGit is as thin a layer on top of Git as possible. You
still maintain your index and commit using Git; TopGit will only
automate a few indispensable tasks.
(ii) TopGit is anxious about *keeping* your history. It will
never rewrite your history, and all metadata is also tracked
by Git, smoothly and non-obnoxiously. It is good to have a
*single* point when the history is cleaned up, and that is at
the point of inclusion in the upstream project; locally, you
can see how your patch has evolved and easily return to older
versions.
(iii) TopGit is specifically designed to work in a
distributed environment. You can have several instances of
TopGit-aware repositories and smoothly keep them all
up-to-date and transfer your changes between them.
As mentioned above, the main intended use-case for TopGit is tracking
third-party patches, where each patch is effectively a single topic
branch. In order to flexibly accommodate even complex scenarios when
you track many patches where many are independent but some depend on
others, TopGit ignores the ancient Quilt heritage of patch series and
instead allows the patches to freely form graphs (DAGs just like Git
history itself, only "one level higher"). For now, you have to manually
specify which patches the current one depends on, but TopGit might help
you with that in the future in a darcs-like fashion.
A glossary_ plug: The union (i.e. merge) of patch dependencies is called
a *base* of the patch (topic branch).
Of course, TopGit is perhaps not the right tool for you:
(i) TopGit is not complicated, but StGIT et al. are somewhat
simpler, conceptually. If you just want to make a linear
purely-local patch queue, deferring to StGIT instead might
make more sense.
(ii) When using TopGit, your history can get a little hairy
over time, especially with all the merges rippling through.
;-)
SYNOPSIS
--------
::
## Create and evolve a topic branch
$ tg create t/gitweb/pathinfo-action
tg: Automatically marking dependency on master
tg: Creating t/gitweb/pathinfo-action base from master...
$ ..hack..
$ git commit
$ ..fix a mistake..
$ git commit
## Create another topic branch on top of the former one
$ tg create t/gitweb/nifty-links
tg: Automatically marking dependency on t/gitweb/pathinfo-action
tg: Creating t/gitweb/nifty-links base from t/gitweb/pathinfo-action...
$ ..hack..
$ git commit
## Create another topic branch on top of master and submit
## the resulting patch upstream
$ tg create t/revlist/author-fixed master
tg: Creating t/revlist/author-fixed base from master...
$ ..hack..
$ git commit
$ tg patch -m
tg: Sent t/revlist/author-fixed
From: [email protected]
Subject: [PATCH] Fix broken revlist --author when --fixed-string
## Create another topic branch depending on two others non-trivially
$ tg create t/whatever t/revlist/author-fixed t/gitweb/nifty-links
tg: Creating t/whatever base from t/revlist/author-fixed...
tg: Merging t/whatever base with t/gitweb/nifty-links...
Merge failed!
tg: Please commit merge resolution and call: tg update --continue
tg: It is also safe to abort this operation using `git reset --hard`
tg: but please remember you are on the base branch now;
tg: you will want to switch to a different branch.
$ ..resolve..
$ git commit
$ tg update --continue
$ ..hack..
$ git commit
## Update a single topic branch and propagate the changes to
## a different one
$ git checkout t/gitweb/nifty-links
$ ..hack..
$ git commit
$ git checkout t/whatever
$ tg info
Topic Branch: t/whatever (1 commit)
Subject: [PATCH] Whatever patch
Base: 3f47ebc1
Depends: t/revlist/author-fixed t/gitweb/nifty-links
Needs update from:
t/gitweb/nifty-links (1 commit)
$ tg update
tg: Updating base with t/gitweb/nifty-links changes...
Merge failed!
tg: Please commit merge resolution and call `tg update --continue`
tg: (use `tg status` to see more options)
$ ..resolve..
$ git commit
$ tg update --continue
tg: Updating t/whatever against new base...
Merge failed!
tg: Please commit merge resolution and call `tg update --continue`
tg: (use `tg status` to see more options)
$ ..resolve..
$ git commit
$ tg update --continue
## Update a single topic branch and propagate the changes
## further through the dependency chain
$ git checkout t/gitweb/pathinfo-action
$ ..hack..
$ git commit
$ git checkout t/whatever
$ tg info
Topic Branch: t/whatever (1/2 commits)
Subject: [PATCH] Whatever patch
Base: 0ab2c9b3
Depends: t/revlist/author-fixed t/gitweb/nifty-links
Needs update from:
t/gitweb/pathinfo-action (<= t/gitweb/nifty-links) (1 commit)
$ tg update
tg: Recursing to t/gitweb/nifty-links...
[t/gitweb/nifty-links] tg: Updating base with t/gitweb/pathinfo-action changes...
Merge failed!
[t/gitweb/nifty-links] tg: Please commit merge resolution and call `tg update --continue`
[t/gitweb/nifty-links] tg: (use `tg status` to see more options)
$ ..resolve..
$ git commit
$ tg update --continue
[t/gitweb/nifty-links] tg: Updating t/gitweb/nifty-links against new base...
Merge failed!
[t/gitweb/nifty-links] tg: Please commit merge resolution and call `tg update --continue`
[t/gitweb/nifty-links] tg: (use `tg status` to see more options)
$ ..resolve..
$ git commit
$ tg update --continue
tg: Updating base with t/gitweb/nifty-links changes...
tg: Updating t/whatever against new base...
## Clone a TopGit-controlled repository
$ git clone URL repo
$ cd repo
$ tg remote --populate origin
...
$ git fetch
$ tg update
## Add a TopGit remote to a repository and push to it
$ git remote add foo URL
$ tg remote foo
$ tg push -r foo
## Update from a non-default TopGit remote
$ git fetch foo
$ tg -r foo summary
$ tg -r foo update
CONVENTIONS
-----------
When using TopGit there are several common conventions used when working with
TopGit branches. None of them are enforced, they are only suggestions.
There are three typical uses for a TopGit branch:
1. [PATCH]
Normal TopGit branches that represent a single patch. These are known
as "patch" TopGit branches.
2. [BASE]
Empty TopGit branches with no dependencies (an empty ``.topdeps`` file)
that represent a base upon which other "normal" TopGit branches depend.
These are known as "base" TopGit branches (not to be confused with
the refs/top-bases/... refs).
3. [STAGE]
Empty TopGit branches that serve as a staging area to bring together
several other TopGit branches into one place so they can be used/tested
all together. These are known as "stage" TopGit branches.
An "empty" TopGit branch is one that does not have any changes of its own --
it may still have dependencies though ("stage" branches do, "base" branches do
not). The ``tg summary`` output shows empty branches with a ``0`` in the
listing. Normal "patch" branches that have not been annihilated, "base" and
"stage" branches fall into this category. (Annihilated branches are normally
omitted from the ``tg summary`` output but can be shown if given explicitly as
an argument to the ``tg summary`` command. However, the message line will be
incorrect since an annihilated branch has no ``.topmsg`` file of its own.)
A "patch" branch name typically starts with ``t/`` whereas "base" and "stage"
branch names often do not.
A "base" branch is created by using the ``--base`` option of ``tg create``
(aka ``--no-deps``) which will automatically suggest a "[BASE]" message prefix
rather than "[PATCH]". A "stage" branch is created like a normal patch branch
except that the only changes that will ever be made to it are typically to
add/remove dependencies. Its subject prefix must be manually changed to
"[STAGE]" to reflect its purpose.
Since both "base" and "stage" branches typically only have a use for the
"Subject:" line from their ``.topmsg`` file, they are quite easily created
using the ``--topmsg`` option of ``tg create``.
Use of "stage" and "base" branches is completely optional. However, without
use of a "stage" branch it will be difficult to test multiple independent
patches together all at once. A "base" branch is merely a convenience that
provides more explicit control over when a common base for a set of patches
gets updated as well as providing a branch that shows in ``tg summary`` output
and participates in ``tg remote --populate`` setup.
Occasionally the functionality of a "base" branch is needed but it may not
be possible to add any `.topdeps` or `.topmsg` files to the desired branch
(perhaps it's externally controlled). `BARE BRANCHES`_ can be used in this
case, but while TopGit allows them it deliberately does not provide assistance
in setting them up.
Another advantage to using a "stage" branch is that if a new "patch" branch
is created remotely and that new branch is added to a pre-existing "stage"
branch on the remote then when the local version of the "stage" branch is
updated (after fetching remote updates of course), that new dependency will
be merged into the local "stage" branch and the local version of the new remote
"patch" branch will be automatically set up at "tg update" time.
When using the ``tg tag`` command to create tags that record the current state
of one or more TopGit branches, the tags are often created with a name that
starts with ``t/``.
One last thing, you have enabled ``git rerere`` haven't you?
NO UNDO
-------
Beware, there is no "undo" after running a ``tg update``!
Well, that's not entirely correct. Since ``tg update`` never discards commits
an "undo" operation is technically feasible provided the old values of all the
refs that were affected by the ``tg update`` operation can be determined and
then they are simply changed back to their previous values.
In practice though, it can be extremely tedious and error prone looking through
log information to try and determine what the correct previous values were.
Although, since TopGit tries to make sure reflogs are enabled for top-bases
refs, using Git's ``@{date}`` notation on all the refs dumped out by a
``tg tag --refs foo``, where "foo" is the branch that was updated whose update
needs to be undone, may work.
Alternatively, ``tg tag --stash`` can be used prior to the update and then
``tg revert`` used after the update to restore the previous state. This
assumes, of course, that you remember to run ``tg tag --stash`` first.
The ``tg update`` command understands a ``--stash`` option that tells it to
automatically run ``tg tag --stash`` before it starts making changes (if
everything is up-to-date it won't run the stash command at all).
The ``--stash`` option is the default nowadays when running ``tg update``,
add the ``--no-stash`` option to turn it off.
There is a preference for this. Setting the config value ``topgit.autostash``
to ``false`` will implicitly add the ``--no-stash`` option to any ``tg update``
command unless an explicit ``--stash`` option is given.
If you are likely to ever want to undo a ``tg update``, setting
``topgit.autostash`` to ``false`` is highly discouraged!
Note that if you have foolishly disabled the autostash functionality and
suddenly find yourself in an emergency "WHERE'S THE UNDO???" situation you
*may* be able to use the special ``TG_STASH`` ref. But only if you're quick.
It's only set if you've foolishly disabled autostash and it always overwrites
the previous ``TG_STASH`` value if there was one (there's no reflog for it)
and it will most likely *not* survive a ``git gc`` (even an automatic one) no
matter what gc expiration values are used.
Note that the tags saved by ``tg tag --stash`` are stored in the
``refs/tgstash`` ref and its reflog. Unfortunately, while Git is happy to
maintain the reflog (once it's been enabled which ``tg tag`` guarantees for
``refs/tgstash``), Git is unable to view an annotated/signed tag's reflog!
Instead Git dereferences the tag and shows the wrong thing.
Use the ``tg tag -g`` command to view the ``refs/tgstash`` reflog instead.
WAYBACK MACHINE
---------------
After reading about `NO UNDO`_ and the `tg tag`_ command used to provide a
semblance of undo in some cases, you have the foundation to understand the
wayback machine.
The "wayback machine" provides a way to go back to a previous ref state as
stored in a TopGit tag created by `tg tag`_. It actually normally returns to a
hybrid state as it does not prune (unless you prefix the wayback tag with
a ``:``). In other words, any refs that have been newly created since the
target tag was made will continue to exist in the "wayback" view of things
(unless you used a pruning wayback tag -- one prefixed with a ``:``).
Any operations that are read-only and do not require working tree files (e.g.
the ``-i`` or ``-w`` options of `tg patch`_) are allowed using the wayback
machine. Simply add a global ``-w <tgtag>`` option to the command.
This functionality can be extremely useful for quickly examing/querying a
previous state recorded some time ago with a `tg tag`_.
As the wayback machine uses a separate caching area, except initial operations
to be less speedy, but repeated wayback operations on the same wayback tag
should happen at normal speed.
One new command exists expressly for use with the wayback machine.
The `tg shell`_ command will spawn an interactive shell or run a specific shell
command in a temporary writable and non-bare repository that has its ref
namespace set to the (possibly pruned if it's a pruning wayback tag) wayback
tag's view of the world. This pretty much lifts all wayback restrictions, but
read the description for `tg shell`_ for more details. There is an option
available to specify the location where this "temporary" directory is created
thereby allowing it to persist, but the same warnings then apply as using the
``git clone --shared`` command.
EXTRA SETTINGS
--------------
TopGit supports various config settings:
:`tg create`_: ``format.signoff`` template Signed-off-by line
:ALIASES_: ``topgit.alias.*`` for Git-like command aliases
:`tg update`_: ``topgit.autostash`` automatic stash control
:`tg create`_: ``topgit.bcc`` default "Bcc:" value for create
:`tg create`_: ``topgit.cc`` default "Cc:" value for create
:`tg patch`_: ``topgit.from`` "From:" fixups by ``tg patch``
:`REMOTE HANDLING`_: ``topgit.remote`` TopGit's default remote
:SEQUESTRATION_: ``topgit.sequester`` for sequestration control
:`tg update`_: ``topgit.setAutoUpdate`` => ``rerere.autoUpdate``
:`tg export`_: ``topgit.subjectMode`` export [...] tag removal
:`tg create`_: ``topgit.subjectPrefix`` "[$prefix PATCH] foo"
:`tg create`_: ``topgit.to`` default "To:" value for create
:`tg migrate-bases`_: ``topgit.top-bases`` for refs bases location
ALIASES
-------
These work exactly like Git's aliases except they are stored under
``topgit.alias.*`` instead. See the ``git help config`` output under
the ``alias.*`` section for details. Do note that while alias nesting is
explicitly permitted, a maximum nesting depth of 10 is enforced to help
detect accidental aliasing loops and keep them from wedging the machine.
For example, to create an ``lc`` alias for the ``tg log --compact`` command
this command may be used:
::
git config --global topgit.alias.lc "log --compact"
To make it specific to a particular repository just omit the ``--global``
option from the command.
NAVIGATION
----------
From Previous to Next
~~~~~~~~~~~~~~~~~~~~~
For this section, consider the following patch series, to be applied
in numerical order as shown:
::
0001-F_first-patch.diff
0002-G_second-builds-on-F.diff
0003-H_third-builds-on-G.diff
0004-I_fourth-builds-on-H.diff
0005-J_fifth-builds-on-I.diff
0006-K_sixth-builds-on-J.diff
0007-L_last-patch-needs-K.diff
If these were applied to some commit in a Git repository, say commit "A"
then a history that looks like this would be created:
::
A---F---G---H---I---J---K---L
Where the parent of commit "F" is "A" and so on to where the parent of
commit "L" is commit "K".
If that commit history, from A through L, was then imported into TopGit, one
TopGit branch would be created corresponding to each of the commits F
through L. This way, for example, if the fourth patch in the series
(``0004-I_...diff``) needs work, the TopGit branch corresponding to its patch
can be checked out and changes made and then a new version of its patch
created (using ``tg patch``) without disturbing the other patches in the series
and when ``tg update`` is run, the patches that "follow" the fourth patch
(i.e. 5, 6 and 7) will have their corresponding TopGit branches automatically
updated to take into account the changes made to the fourth patch.
Okay, enough with the review of TopGit systemology
``````````````````````````````````````````````````
Imagine then that you are working on the fourth patch (i.e. you have its
branch checked out into the working tree) and you want to move to the following
patch in the series because you have a nit to pick with it too.
If you can't remember the exact name you might have to fumble around or, you
can display the name of the following or "next" patch's branch with the, you
guessed it, ``tg next`` command. Think of "next" as the "next" logical patch
in the series or the next following patch. If the patches are numbered as in
the list above, "next" corresponds to the "+1" (plus one) patch.
You might have already guessed there's a corresponding ``tg prev`` command
which displays the "-1" (minus one) patch. If these commands (``tg next``
and ``tg prev``) are not given a branch name to start at they start at the
patch corresponding to the current ``HEAD``.
Displaying, however, is not so helpful as actually going there. That's where
the ``tg checkout`` command comes in. ``tg checkout next`` does a
``git checkout`` of the ``tg next`` branch and, not surprisingly,
``tg checkout prev`` does a ``git checkout`` of the ``tg prev`` branch. For
the lazy a single ``n`` or ``p`` can be used with ``tg checkout`` instead of
typing out the entire ``next`` or ``prev``. Or, for the anal, ``previous``
will also be accepted for ``prev``.
Referring to the A...L commit graph shown above, I is the parent of J and,
conversely, J is the child of I. (Git only explicitly records the child to
parent links, in other words a "child" points to zero or more "parents", but
parents are completely clueless about their own children.)
For historical reasons, the ``tg checkout`` command accepts ``child`` as a
synonym for ``next`` and ``parent`` as a synonym for ``prev``. However, this
terminology can be confusing since Git has "parent" links but ``tg checkout``
is referring to the TopGit DAG, not Git's. Best to just avoid using ``child``
or ``parent`` to talk about navigating the TopGit DAG and reserve them
strictly for discussing the Git DAG.
There may be more than one
``````````````````````````
In a simple linear history as shown above there's always only one "next" or
"prev" patch. However, TopGit does not restrict one to only a linear
history (although that can make patch exports just a bushel of fun).
Suffice it to say that there is always a single linearized ordering for any
TopGit patch series since it's always a DAG (Directed Acyclic Graph), but it
may not be immediately obvious to the casual observer what that is.
The ``tg checkout`` command will display a list to choose from if ``next``
or ``prev`` would be ambiguous.
Use the ``tg info/checkout --series`` command
`````````````````````````````````````````````
To see the full, linearized, list of patches with their summary displayed in
order from first to last patch in the series, just run the ``tg info --series``
command. It takes the name of any patch in the series automatically using
``HEAD`` if none is given. It even provides a nice "YOU ARE HERE" mark in
the output list helpful to those who have been absent for a time engaging in
otherwise distracting activities and need to be reminded where they are.
Using ``tg checkout --series`` can take you there (picking from a list) if
you've forgotten the way back to wherever you're supposed to be.
Don't get pushy, there's just one more thing
````````````````````````````````````````````
For historical reasons, ``tg checkout`` with no arguments whatsoever behaves
like ``tg checkout next``. For the same historical reasons, ``tg checkout ..``
behaves like ``tg checkout prev`` (think of ``..`` as the "parent" directory
and since "parent" means "prev" in this context it will then make sense).
Now, for that one more thing. Consider that you have a pristine "upstream"
tarball, repository, source dump or otherwise obtained set of unmodified
source files that need to be patched. View them like so:
::
+-------------------------------+
| Unmodified "upstream" source |
| files represented with "A" |
+-------------------------------+
Now, add the first patch, 0001, to them and view the result like so:
::
+--------------------------+----+
| Patch 0001 represented by "F" |
+-------------------------------+
| Unmodified "upstream" source |
| files represented with "A" |
+-------------------------------+
Not stopping there, "push" patches 2, 3 and 4 onto the stack as well like so:
::
+--------------------------+----+
| Patch 0004 represented by "I" |
+--------------------------+----+
| Patch 0003 represented by "H" |
+--------------------------+----+
| Patch 0002 represented by "G" |
+--------------------------+----+
| Patch 0001 represented by "F" |
+-------------------------------+
| Unmodified "upstream" source |
| files represented with "A" |
+-------------------------------+
In other words, to go to the "next" patch in the series it needs to be "push"ed
onto the stack. ``tg checkout`` accepts ``push`` as an alias for ``next``.
Similarly to go to the "previous" patch in the series the current one needs
to be "pop"ped off the stack. ``tg checkout`` accepts ``pop`` as an alias
for ``prev``.
Unfortunately for these aliases, in Git terminology a "push" has quite a
different meaning and the ``tg push`` command does something quite different
from ``tg checkout push``. Then there's the matter of using a single letter
abbreviation for the lazy -- ``p`` would mean what exactly?
``tg checkout`` continues to accept the ``push`` and ``pop`` aliases for
``next`` and ``prev`` respectively, but it's best to avoid them since
``push`` has an alternate meaning everywhere else in TopGit and Git and that
leaves ``pop`` all alone in the dark.
SEQUESTRATION
-------------
No, this is not a section about budget nonsense. ;)
TopGit keeps its metadata in ``.topdeps`` and ``.topmsg`` files. In an effort
to facilitate cherry-picking and other Git activities on the patch changes
themselves while ignoring the TopGit metadata, TopGit attempts to keep all
changes to ``.topdeps`` and ``.topmsg`` files limited to commits that do NOT
contain changes to any other files.
This is a departure from previous TopGit versions that made no such effort.
Primarily this affects ``tg create`` and ``tg import`` (which makes use of
``tg create``) as ``tg create`` will commit the initial versions of
``.topdeps`` and ``.topmsg`` for a new TopGit-controlled branch in their own
commit instead of mixing them in with changes to other files.
The ``pre-commit`` hook will also attempt to separate out any ``.topdeps`` and
``.topmsg`` changes from commits that include changes to other files.
It is possible to defeat these checks without much effort (``pre-commit`` hooks
can easily be bypassed, ``tg create`` has a ``--no-commit`` option, many Git
commands simply do not run the ``pre-commit`` hook, etc.).
If you really, really, really, really want to change the default back to the
old behavior of previous TopGit versions where no such sequestration took
place, then set the ``topgit.sequester`` config variable explicitly to the
value ``false``. But this is not recommended.
AMENDING AND REBASING AND UPDATE-REF'ING
----------------------------------------
In a word, "don't".
It is okay to manually update a top-bases/... ref when a) it has no depedencies
(i.e. it was created with the ``tg create`` ``--base`` option) and b) the
old top-bases/... ref value can be fast-forwarded to the new top-bases/...
value OR the new value contains ALL of the changes in the old value through
some other mechanism (perhaps they were cherry-picked or otherwise applied to
the new top-bases/... ref). The same rules apply to non-TopGit-controlled
dependencies. Use the ``tg update --base <branch> <new-ref>`` command to
safely make such an update while making it easy to set the merge commit
message at the same time.
Ignoring this rule and proceeding anyway with a non-fast-forward update to a
top-bases/... ref will result in changes present in the new value being merged
into the branch (at ``tg update`` time) as expected (possibly with conflicts),
but any changes that were contained in the old version of the top-bases/... ref
which have been dropped (i.e. are NOT contained in the new version of the
top-bases/... ref) will continue to be present in the branch! To get rid of
the dropped commits, one or more "revert" commits will have to be manually
applied to the tip of the new top-bases/... value (which will then be merged
into the branch at next ``tg update`` time).
The only time it's safe to amend, rebase, filter or otherwise rewrite commits
contained in a TopGit controlled branch or non-TopGit branch is when those
commits are NOT reachable via any other ref!
Furthermore, while it is safe to rewrite merge commits (provided they meet the
same conditions) the merge commits themselves and the branches they are merging
in must be preserved during the rewrite and that can be rather tricky to get
right so it's not recommended.
For example, if, while working on a TopGit-controlled branch ``foo``, a bad
typo is noticed, it's okay to ammend/rebase to fix that provided neither
``tg update`` nor ``tg create`` has already been used to cause some other ref
to be able to reach the commit with the typo.
If an amend or rerwite is done anyway even though the commit with the typo is
reachable from some other ref, the typo won't really be removed. What will
happen instead is that the new version without the typo will ultimately be
merged into the other ref(s) (at ``tg update`` time) likely causing a conflict
that will have to be manually resolved and the commit with the typo will
continue to be reachable from those other refs!
Instead just make a new commit to fix the typo. The end result will end up
being the same but without the merge conflicts.
See also the discussion in the `NO UNDO`_ section.
BARE BRANCHES
-------------
A "TopGit bare branch" (or just "bare branch" for short), refers to a TopGit
branch that has neither a ``.topdeps`` nor a ``.topmsg`` file stored in it.
And it's neither a new, still-empty empty branch nor an annihilated branch.
Such branches are not recommended but are reluctantly accomodated.
There are three situtations in which TopGit may encounter a TopGit branch
that has neither a ``.topdeps`` nor a ``.topmsg`` file.
1. Branch creation with ``--no-commit``
Before the initial commit is made, the branch will still be
pointing to the same commit as its "top-bases" ref. Branches
in this condition (where the branch and top-bases ref point to
the same commit) show up as having "No commits" in listings.
2. Annihilated branches
A branch is annihilated by making a new commit on the branch
that makes its tree identical to the tree of its corresponding
top-bases ref. Although the trees will be the same, the
commits will be different and annihilated branches are
distinguished from "No commits" branches in this way.
Annihilated branches are generally invisible and do not show up
in listings or other status displays. Intentionally so.
3. Bare branches
Any TopGit branch with neither a ``.topdeps`` file nor a
``.topmsg`` file whose branch and top-bases trees differ falls
into this category. TopGit will not create such a branch
itself nor does it provide any commands to do so.
Whenever possible, a TopGit "[BASE]" branch should be preferred to using a
"bare branch" because a) it can never be mistaken for an annihilated branch,
b) it has a nice subject attached (via its ``.topmsg`` file) that shows
up in listings and c) exactly when and which updates are taken can be planned.
Nevertheless, situations may arise where it's useful to have TopGit treat a
branch as a "TopGit branch" so that it fully participates in all update
activities (such as updating local branches based on their remote branches),
but it's not feasible to turn it into a real "TopGit branch" as it comes from
an external source and rather than controlling exactly when and what updates
are picked up from it by TopGit (the precise use case of a "[BASE]" branch),
all updates that appear on it are to be assimilated as soon as they occur.
For this reason, TopGit will accomodate such "bare branches" but it will not
create (nor provide the means to create) them itself.
In order to create a "bare branch" all that's required is to create the
necessary top-bases ref. The choice of commit for the top-bases ref will
affect the output of the "files", "log" and "patch" commands most directly
(but all commands will be affected).
To work properly as a "bare branch", the commit the "bare branch"'s base points
to should be contained within the branch, be a different commit than the branch
tip itself and have a different tree than the branch tip. Simply setting the
base to the parent commit of the "bare branch" will usually work, but should
that commit at the tip of the "bare branch" end up getting reverted as the next
commit, the trees would match and it would appear to be an annihilated branch
rather than a "bare branch". That is one of the reasons these branches are not
recommended in the first place.
Setting the base to the root commit of the branch is more reliable and may
be accomplished like so for a local branch named "mybranch":
::
git update-ref $(tg --top-bases)/mybranch \
$(git rev-list --first-parent --max-parents=0 mybranch) ""
Typically though it's more likely a remote bare branch will be needed. For
a remote named "origin" and a remote branch name of "vendor" this will do it:
::
git update-ref $(tg --top-bases -r origin)/vendor \
$(git rev-list --first-parent --max-parents=0 origin/vendor) ""
Such "bare branches" are not likely ever to receive any more direct support in
TopGit than acknowleging they can be useful in some situations and tolerating
their existence by functioning properly with them even to the point of the
``pre-commit`` hook tacitly allowing continued commits on such branches without
complaints about missing ``.topdeps`` and ``.topmsg`` files.
Note, however, that creating a regular TopGit branch that has no changes of its
own with the "bare branch" as its single dependency provides a means to supply
some kind of documentation if all other uses of the "bare branch" depend on
this "wrapper" branch instead of directly on the "bare branch".
SPEED AND CACHING
-----------------
TopGit needs to check many things to determine whether a TopGit branch is
up-to-date or not. This can involve a LOT of git commands for a complex
dependency tree. In order to speed things up, TopGit keeps a cache of results
in a ``tg-cache`` subdirectory in the ``.git`` directory.
Results are tagged with the original hash values used to get that result so
that items which have not been changed return their results quickly and items
which have been changed compute their new result and cache it for future use.
The ``.git/tg-cache`` directory may be removed at any time and the cache will
simply be recreated in an on-demand fashion as needed, at some speed penalty,
until it's fully rebuilt.
To force the cache to be fully pre-loaded, run the ``tg summary`` command
without any arguments. Otherwise, normal day-to-day TopGit operations should
keep it more-or-less up-to-date.
While each TopGit command is running, it uses a temporary subdirectory also
located in the ``.git`` directory. These directories are named
``tg-tmp.XXXXXX`` where the ``XXXXXX`` part will be random letters and digits.
These temporary directories should always be removed automatically after each
TopGit command finishes running. As long as you are not in a subshell as a
result of a TopGit command stopping and waiting for a manual merge resolution,
it's safe to remove any of these directories that may have somehow accidentally
been left behind as a result of some failure that occurred while running a
TopGit command (provided, of course, it's not actually being used by a TopGit
command currently running in another terminal window or by another user on the
same repository).
USAGE
-----
``tg [global options] <subcommand> [<subcommand option/argument>...]``
Global options:
``[-C <dir>]... [-r <remote> | -u] [-c <name>=<val>]... [--[no-]pager]``
-C <dir> Change directory to <dir> before doing anything more
-r <remote> Pretend ``topgit.remote`` is set to <remote>
-u Pretend ``topgit.remote`` is not set
-c <name=val> Pass config option to git, may be repeated
-w <tgtag> Activate `wayback machine`_ using the `tg tag`_ <tgtag>
--no-pager Disable use of any pager (by both TopGit and Git)
--pager Enable use of a pager (aka ``-p``)
--top-bases Show full ``top-bases`` ref prefix and exit
--exec-path Show path to subcommand scripts location and exit
--help Show brief usage help and exit (aka ``-h``)
The ``tg`` tool has several subcommands:
:`tg annihilate`_: Mark a TopGit-controlled branch as defunct
:`tg base`_: Show base commit for one or more TopGit branches
:`tg checkout`_: Shortcut for git checkout with name matching
:`tg contains`_: Which TopGit-controlled branch contains the commit
:`tg create`_: Create a new TopGit-controlled branch
:`tg delete`_: Delete a TopGit-controlled branch cleanly
:`tg depend`_: Add a new dependency to a TopGit-controlled branch
:`tg export`_: Export TopGit branch patches to files or a branch
:`tg files`_: Show files changed by a TopGit branch
:`tg help`_: Show TopGit help optionally using a browser
:`tg import`_: Import commit(s) to separate TopGit branches
:`tg info`_: Show status information about a TopGit branch
:`tg log`_: Run git log limiting revisions to a TopGit branch
:`tg mail`_: Shortcut for git send-email with ``tg patch`` output
:`tg migrate-bases`_: Transition top-bases to new location
:`tg next`_: Show branches directly depending on a TopGit branch
:`tg patch`_: Generate a patch file for a TopGit branch
:`tg prev`_: Show non-annihilated TopGit dependencies for a branch
:`tg push`_: Run git push on TopGit branch(es) and depedencies
:`tg rebase`_: Auto continue git rebase if rerere resolves conflicts
:`tg remote`_: Set up remote for fetching/pushing TopGit branches
:`tg revert`_: Revert ref(s) to a state stored in a ``tg tag``
:`tg shell`_: Extended `wayback machine`_ mode
:`tg status`_: Show current TopGit status (e.g. in-progress update)
:`tg summary`_: Show various information about TopGit branches
:`tg tag`_: Create tag that records current TopGit branch state
:`tg update`_: Update TopGit branch(es) with respect to dependencies
tg help
~~~~~~~
Our sophisticated integrated help facility. Mostly duplicates
what is below::
# to list commands:
$ tg help
# to get help for a particular command:
$ tg help <command>
# to get help for a particular command in a browser window:
$ tg help -w <command>
# to get help on TopGit itself
$ tg help tg
# to get help on TopGit itself in a browser
$ tg help -w tg
tg status
~~~~~~~~~
Our sophisticated status facility. Similar to Git's status command
but shows any in-progress update that's awaiting a merge resolution
or any other on-going TopGit activity (such as a branch creation).
With a single ``--verbose`` (or ``-v``) option include a short status
display for any dirty (but not untracked) files. This also causes all
non file status lines to be prefixed with "## ".
With two (or more) ``--verbose`` (or ``-v``) options, additionally
show full symbolic ref names and unabbreviated hash values.
With the ``--exit-code`` option the exit code will be non-zero if any
TopGit or Git operation is currently in progress or the working
tree is unclean.
tg create
~~~~~~~~~
Create a new TopGit-controlled topic branch of the given name
(required argument) and switch to it. If no dependencies are
specified (by extra arguments passed after the first one), the
current branch is assumed to be the only dependency.
By default ``tg create`` opens an editor on the new ``.topmsg`` file
and then commits the new ``.topmsg`` and ``.topdeps`` files
automatically with a suitable default commit message.
The commit message can be changed with the ``-m`` (or ``--message``) or
``-F`` (or ``--file``) option. The automatic commit can be suppressed
by using the ``--no-ccmmit`` (or ``-n``) option. Running the editor on
the new ``.topmsg`` file can be suppressed by using ```--no-edit``
(which does *NOT* suppress the automatic commit unless ``--no-commit``
is also given) or by providing an explicit value for the new
``.topmsg`` file using the ``--topmsg`` or ``--topmsg-file`` option.
In any case the ``.topmsg`` content will be automatically reformated to
have a ``Subject:`` header line if needed.
If the ``format.signoff`` config variable (see ``git help config``)
has been set to true then the ``Signed-off-by:`` header line added to
the end of the initial version of the ``.topmsg`` file will be
uncommented by default. Otherwise it will still be there but will be
commented out and will be automatically stripped if no action is taken
to remove the comment character.
If more than one dependency is listed an automatic ``tg update`` runs
after the branch has been created to merge in the additional
dependencies and bring the branch up-to-date. This can be suppressed
with the ``--no-commit`` option (which also suppresses the initial
commit) or the ``--no-update`` option (which allows the initial commit
while suppressing only the update operation portion).
Previous versions of TopGit behaved as though both the ``--no-edit``
and ``--no-commit`` options were always given on the command line.
The default behavior has been changed to promote a separation between
commits that modify ``.topmsg`` and/or ``.topdeps`` and commits that
modify other files. This facilitates cleaner cherry picking and other
patch maintenance activities.
You should edit the patch description (contained in the ``.topmsg``
file) as appropriate. It will already contain some prefilled bits.
You can set the ``topgit.to``, ``topgit.cc`` and ``topgit.bcc``
git configuration variables (see ``man git-config``) in order to
have ``tg create`` add these headers with the given default values
to ``.topmsg`` before invoking the editor. If the configuration
variable ``topgit.subjectPrefix`` is set its value will be inserted
*between* the initial ``[`` and the word ``PATCH`` in the subject
line (with a space added before the word ``PATCH`` of course).
The main task of ``tg create`` is to set up the topic branch base
from the dependencies. This may fail due to merge conflicts if more
than one dependency is given. In that case, after you commit the
conflict resolution, you should call ``tg update --continue`` to
finish merging the dependencies into the new topic branch base.
With the ``--base`` (aka ``--no-deps``) option at most one dependency
may be listed which may be any valid committish (instead of just
refs/heads/...) and the newly created TopGit-controlled branch will
have an empty ``.topdeps`` file. This may be desirable in order to
create a TopGit-controlled branch that has no changes of its own and
serves merely to mark the common dependency that all other
TopGit-controlled branches in some set of TopGit-controlled branches
depend on. A plain, non-TopGit-controlled branch can be used for the
same purpose, but the advantage of a TopGit-controlled branch with no
dependencies is that it will be pushed with ``tg push``, it will show
up in the ``tg summary`` and ``tg info`` output with the subject from
its ``.topmsg`` file thereby documenting what it's for and finally it
can be set up with ``tg create -r`` and/or ``tg remote --populate`` to
facilitate sharing.
For example, ``tg create --base release v2.1`` will create a TopGit-
controlled ``release`` branch based off the ``v2.1`` tag that can then
be used as a base for creation of other TopGit-controlled branches.
Then when the time comes to move the base for an entire set of changes
up to ``v2.2`` the command ``tg update --base release v2.2`` can be
used followed by ``tg update --all``.
Using ``--base`` it's also possible to use ``tg create`` on an
unborn branch (omit the dependency name or specify ``HEAD``). The
unborn branch itself can be made into the new TopGit branch (rather