forked from blynn/gitmagic
-
Notifications
You must be signed in to change notification settings - Fork 0
/
grandmaster.txt
182 lines (96 loc) · 17 KB
/
grandmaster.txt
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
== Гросмейстерство Git ==
Тепер ви вже повинні вміти орієнтуватися в сторінках *git help* і розуміти майже все. Однак точний вибір команди, необхідної для вирішення конкретної проблеми, може бути виснажливим. Можливо, я збережу вам трохи часу: нижче наведені рецепти, які знадобилися мені в минулому.
=== Релізи вихідних кодів ===
У моїх проектах Git управляє в точності тими файлами, які я збираюся архівувати і пускати в реліз. Щоб створити тарбол з вихідними кодами, я виконую:
$ git archive --format=tar --prefix=proj-1.2.3/ HEAD
=== Комміт змін ===
У деяких проектах може бути трудомістким повідомляти Git про кожне додавання, видаленні та перейменування файлу. Замість цього ви можете виконати команди
$ git add .
$ git add -u
Git прогляне файли в поточному каталозі і сам подбає про деталі. Замість другої команди add, виконайте `git commit -a`, якщо ви збираєтеся відразу зробити комміт. Дивіться * git help ignore *, щоб дізнатися як вказати файли, які повинні ігноруватися.
Ви можете виконати все це одним махом:
$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove
Опції *-z* і *-0* запобігають невірну обробку файлових імен, що містять спеціальні символи. Оскільки ця команда додає ігноровані файли, ви можливо захочете використовувати опції `-x` або `-X`.
=== Мій комміт занадто великий ===
Ви нехтували коммітамі занадто довго? Затято писали код і згадали про управління вихідними кодами тільки зараз? Внесли ряд незв'язаних змін, тому що це ваш стиль?
Немає причин для занепокоєння. Виконайте
$ git add -p
Для кожної зробленої вами правки Git покаже змінену ділянку коду і запитає, чи повинна ця зміна потрапити в наступний комміт. Відповідайте "y" (так) або "n" (ні). У вас є й інші варіанти, наприклад відкласти вибір; введіть "?" Щоб дізнатися більше.
Коли закінчите, виконайте
$ git commit
для внесення саме тих правок, що ви вибрали ('буферизованих' змін). Переконайтеся, що ви не вказали опцію *-a*, інакше Git закоммітить всі правки.
Що робити, якщо ви змінили безліч файлів в багатьох місцях? Перевірка кожної окремої зміни стає обтяжливою рутиною. У цьому випадку використовуйте *git add -i*. Її інтерфейс не такий простий, але більш гнучкий. У декілька натискань можна додати або прибрати з буфера кілька файлів одночасно, або переглянути і вибрати зміни лише в окремих файлах. Як варіант, запустіть *git commit \--interactive*, яка автоматично зробить комміт коли ви закінчите.
=== Індекс — буферна зона Git ===
До цих пір ми уникали знаменитого 'індексу' Git, але тепер ми повинні розглянути його, для пояснення вищесказаного. Індекс це тимчасовий буфер. Git рідко переміщує дані безпосередньо між вашим проектом і його історією. Замість цього Git спочатку записує дані в індекс, а вже потім копіює їх з індексу за місцем призначення.
Наприклад, *commit -a* насправді двоетапний процес. Спочатку зліпок поточного стану кожного з відстежуваних файлів поміщається в індекс. Потім зліпок, що знаходиться в індексі, записується в історію. Комміт без опції *-a* виконує тільки другий крок, і має сенс тільки після виконання команд, що змінюють індекс, таких як *git add*.
Зазвичай ми можемо не звертати уваги на індекс і робити вигляд, що взаємодіємо безпосередньо з історією. Але в даному випадку ми хочемо більш тонкого контролю, тому управляємо індексом. Ми поміщаємо зліпок деяких (але не всіх) наших змін в індекс, після чого остаточно записуємо цей акуратно сформований зліпок.
=== Не втрачай "голови" ===
Тег HEAD подібний курсору, який зазвичай вказує на останній комміт, просуваючись з кожним новим коммітом. Деякі команди Git дозволяють переміщати цей курсор. Наприклад,
$ git reset HEAD~3
перемістить HEAD на три комміти назад. Тепер всі команди Git будуть працювати так, ніби ви не робили останніх трьох коммітів, хоча файли залишаться в поточному стані. У довідці описано кілька способів використання цього прийому.
Але як повернутися назад у майбутнє? Адже попередні комміти про нього нічого не знають.
Якщо у вас є SHA1 вихідної "голови", то:
$ git reset 1b6d
Але припустимо, ви його не записували. Не турбуйтеся: для комнад такого роду Git зберігає оригінальну "голову" як тег під назвою ORIG_HEAD, і ви можете повернутися надійно і безпечно:
$ git reset ORIG_HEAD
=== Полювання за "головами" ===
Припустимо ORIG_HEAD недостатньо. Приміром, ви тільки що усвідомили, що допустили величезну помилку, і вам потрібно повернутися до давнього комміту в давно забутій гілці.
За замовчуванням Git зберігає комміти не менше двох тижнів, навіть якщо ви наказали знищити гілку, що їх містить. Проблема в знаходженні відповідного хешу. Ви можете проглянути всі значення хешів в `.git/objects` і методом проб та помилок знайти потрібний. Але є шлях значно легший.
Git записує кожен підрахований ним хеш комміта в `.git/logs`. У підкаталозі `refs` міститься повна історія активності на всіх гілках, а файл `HEAD` містить кожне значення хешу, яке коли-небудь приймав HEAD. Останній можна використовувати щоб знайти хеши коммітів на випадково обрубаних гілках.
Команда reflog надає зручний інтерфейс роботи з цими журналами. Використовуйте
$ git reflog
Замість копіювання хешів з reflog, спробуйте
$ git checkout "@{10 minutes ago}"
Чи зробіть чекаут п'ятого з кінця з відвіданих коммітів за допомогою
$ git checkout "@{5}"
Дивіться розділ ``Specifying Revisions'' в *git help rev-parse* для додаткової інформації.
Ви можете захотіти подовжити відстрочку для коммітів, приречених на видалення. Наприклад,
$ git config gc.pruneexpire "30 days"
означає, що комміти, які видаляються, будуть остаточно зникати тільки після 30 днів і після запуску *git gc*.
Також ви можете захотіти відключити автоматичний виклик *git gc*:
$ git config gc.auto 0
У цьому випадку комміти будуть видалятися тільки коли ви будете запускати *git gc* вручну.
=== Git як основа ===
Дизайн Git, в істинному дусі UNIX, дозволяє легко використовувати його як низькорівневий компонент інших програм: графічних та веб-інтерфейсів; альтернативних інтерфейсів командного рядка; інструментів управління патчами; засобів імпорту або конвертації, і так далі. Багато команд Git насправді - скрипти, які стоять на плечах гігантів. Невеликим доопрацюванням ви можете переробити Git на свій смак.
Найпростіший трюк — використання аліасів Git для скорочення часто використовуваних команд:
$ git config --global alias.co checkout
$ git config --global --get-regexp alias # відображає поточні аліаси
alias.co checkout
$ git co foo # те ж саме, що і 'git checkout foo'
Інший приклад: можна виводити поточну гілку в запрошенні командного рядка або заголовку вікна терміналу. Запуск
$ git symbolic-ref HEAD
виводить назву поточної гілки. На практиці ви швидше за все захочете прибрати "refs/heads/" і повідомлення про помилки:
$ git symbolic-ref HEAD 2> /dev/null | cut -b 12-
Підкаталог +contrib+ — це ціла скарбниця інструментів, побудованих на Git. З часом деякі з них можуть ставати офіційними командами. В Debian та Ubuntu цей каталог знаходиться у +/usr/share/doc/git-core/contrib+.
Один популярний інструмент з цього каталогу — +workdir/git-new-workdir+. Цей скрипт створює за допомогою символічних посилань новий робочий каталог, який має спільну історію з оригінальним сховищем:
$ git-new-workdir існуюче/сховище новий/каталог
Новий каталог і файли в ньому можна сприймати як клон, з тією різницею, що два дерева автоматично залишаються синхронізованими зважаючи на спільну історію. Немає необхідності в merge, push і pull.
=== Ризиковані трюки ===
Нинішній Git робить випадкове знищення даних дуже складним.
Але якщо ви знаєте, що робите, ви можете обійти захист для розповсюджених команд.
*Checkout*: Наявність незакомміченних змін перериває виконання checkout. Щоб перейти до потрібного комміту, навіть знищивши свої зміни, використовуйте прапор змушування (force) *-f*:
$ git checkout -f HEAD^
З іншої сторони, якщо ви вкажете checkout конкретні шляхи, перевірки на безпеку не буде: вказані файли мовчки перезапишуть. Будьте обережні при такому використанні checkout.
*Reset*: скидання також переривається при наявності незакомміченних змін. Щоб змусити його спрацювати, запустіть
$ git reset --hard 1b6d
*Branch*: Видалення гілки припиниться, якщо воно призвело б до втрати змін. Для примусового видалення введіть
$ git branch -D мертва_гілка # замість -d
Аналогічно, спроба перезапису гілки шляхом переміщення буде перервана, якщо може призвести до втрати даних. Для примусового переміщення гілки введіть
$ git branch -M джерело ціль # замість -m
У відмінності від checkout і reset, ці дві команди дають відстрочку у видаленні даних. Зміни залишаються в каталозі.git і можуть бути повернуті відновленням потрібного хешу з `.git/logs` (дивіться вище розділ "Полювання за головами"). За замовчуванням вони будуть зберігатися принаймні два тижні.
*Clean*: Деякі команди можуть не спрацювати через побоювання пошкодити невідслідковувані файли. Якщо ви впевнені, що все невідслідковувані файли і каталоги не потрібні, то безжально видаляйте їх командою
$ git clean -f -d
Наступного разу ця прикра команда спрацює!
=== Запобігаємо поганим коммітам ===
Дурні помилки забруднюють мої сховища. Найжахливіше це проблема відсутніх файлів, викликана забутим *git add*.
Приклади менш серйозних проступків: завершальні пропуски і невирішені конфлікти злиття. Незважаючи на нешкідливість, я не хотів би, щоб це з'являлося в публічних записах.
Якби я тільки поставив захист від дурня, використовуючи _хук_, який би попереджав мене про ці проблеми:
$ cd .git/hooks
$ cp pre-commit.sample pre-commit # В старих версіях Git: chmod +x pre-commit
Тепер Git скасує комміт, якщо виявить зайві пробіли або невирішені конфлікти.
Для цього керівництва я в кінці кінців додав наступне в початок хука *pre-commit*, щоб захиститися від своєї неуважності:
if git ls-files -o | grep '\.txt$'; then
echo ПЕРЕРВАНО! Невідслідковувані .txt файли.
exit 1
fi
Хукі підтримуються кількома різними операціями Git, дивіться *git help hooks*. Ми використовували приклад хука *post-update* раніше, при обговоренні використання Git через http. Він запускався при кожному переміщенні голови. Простий скрипт post-update оновлює файли, які потрібні Git для зв'язку через засоби повідомлення такі як HTTP.