Підсумок
За замовчуванням git pull
створює комісії злиття, які додають шуму та складності історії коду. Крім того, pull
це легко не замислюватися про те, як на ваші зміни можуть вплинути вхідні зміни.
git pull
Команда безпечна так довго , як він виконує тільки швидко вперед зливається. Якщо git pull
налаштовано робити тільки злиття вперед, і коли злиття вперед не можливе, Git вийде з помилкою. Це дасть вам можливість вивчити вхідні зобов’язання, подумати про те, як вони можуть вплинути на ваші місцеві комісії, і визначити кращий спосіб дії (злиття, перезавантаження, скидання тощо).
За допомогою Git 2.0 та новіших версій ви можете запускати:
git config --global pull.ff only
щоб змінити поведінку за замовчуванням лише на швидку перемотку вперед. З версіями Git між 1.6.6 та 1.9.x вам доведеться вводити звичку вводити:
git pull --ff-only
Однак для всіх версій Git я рекомендую налаштувати git up
псевдонім на зразок цього:
git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'
і використання git up
замість git pull
. Я віддаю перевагу цьому псевдоніму, git pull --ff-only
тому що:
- він працює з усіма (недавніми) версіями Git,
- він отримує всі гілки вище за течією (не тільки галузь, над якою ви зараз працюєте), і
- він очищає старі
origin/*
гілки, які вже не існують вище за течією.
Проблеми з git pull
git pull
непогано, якщо він використовується правильно. Декілька останніх змін у Git спростили git pull
правильне використання , але, на жаль, поведінка звичайної програми за замовчуванням git pull
має кілька проблем:
- це вносить зайві нелінійності в історію
- це полегшує випадкове повторне введення комітетів, які були навмисно відкинуті назад за течією
- він змінює ваш робочий каталог непередбачуваними способами
- призупинення того, що ви робите, щоб переглянути чужу роботу, дратує
git pull
- це ускладнює правильне перестановлення на віддалену гілку
- він не очищає гілки, видалені в віддаленому репо
Ці проблеми більш докладно описані нижче.
Нелінійна історія
За замовчуванням git pull
команда еквівалентна запуску, git fetch
за якою слідує git merge @{u}
. Якщо в локальному сховищі є незапущені коміти, частина об'єднання git pull
створює комісію злиття.
Немає нічого поганого в об'єднанні, але вони можуть бути небезпечними і до них слід ставитися з повагою:
- Об'єднання об'єднань по суті важко вивчити. Щоб зрозуміти, що таке злиття, потрібно зрозуміти відмінності для всіх батьків. Звичайна різниця не передає цю багатовимірну інформацію добре. На відміну від цього, ряд нормальних комісій легко переглядати.
- Вирішення конфлікту об'єднань є складним, і помилки часто залишаються невизначеними протягом тривалого часу, оскільки об'єднання об'єктів важко переглядати.
- Злиття можуть спокійно витіснити ефекти регулярних комітетів. Код більше не є сумою поступових скоєнь, що призводить до непорозумінь щодо того, що насправді змінилося.
- Об'єднання об'єднань може порушити деякі схеми безперервної інтеграції (наприклад, автоматично будувати лише перший вихідний шлях відповідно до прийнятої конвенції, згідно з якою другі батьки вказують на незавершене виконання роботи).
Звичайно, є час і місце для злиття, але розуміння того, коли злиття слід і не слід використовувати, може покращити корисність вашого сховища.
Зауважте, що мета Git - полегшити обмін та споживання еволюції бази коду, а не точно записувати історію саме так, як вона розгорнулася. (Якщо ви не погоджуєтесь, розгляньте rebase
команду і чому вона була створена.) З'єднання, створені компанією git pull
, не передають корисну семантику іншим - вони просто кажуть, що хтось інший трапився перейти до сховища до того, як ви зробили свої зміни. Чому ці об’єднання здійснюються, якщо вони не мають значення для інших і можуть бути небезпечними?
Можна налаштувати git pull
повторне базування даних замість злиття, але це також має проблеми (обговорено пізніше). Натомість git pull
має бути налаштовано лише для швидкого злиття вперед.
Повторне введення комісій, які викидають заново
Припустимо, хтось відкидає гілку і сила її штовхає. Це, як правило, не повинно відбуватися, але іноді це необхідно (наприклад, для видалення файлу журналу 50GiB, який був випадково обраний та натиснутий). Злиття, здійснене компанією git pull
, об'єднає нову версію гілки вище за течією у стару версію, яка все ще існує у вашому локальному сховищі. Якщо натиснути на результат, торочні вилки та смолоскипи почнуть наступати на ваш шлях.
Деякі можуть стверджувати, що справжньою проблемою є примусові оновлення. Так, зазвичай доцільно уникати силових натискань, коли це можливо, але вони іноді неминучі. Розробники повинні бути готові розібратися з оновленнями, оскільки вони трапляться іноді. Це означає не сліпо зливатися у старих комісіях за допомогою звичайного git pull
.
Здивуйте зміни робочого каталогу
Немає способу передбачити, як буде виглядати робочий каталог або індекс, поки git pull
це не буде зроблено. Можуть виникнути конфлікти злиття, які вам доведеться вирішити, перш ніж робити щось інше, це може ввести файл журналу 50GiB у вашу робочу директорію, оскільки хтось випадково натиснув його, він може перейменувати каталог, у якому ви працюєте тощо.
git remote update -p
(або git fetch --all -p
) дозволяє переглядати зобов’язання інших людей, перш ніж ви вирішите об'єднатись або перезавантажити, що дозволяє скласти план перед тим, як вжити заходів.
Складність перегляду комітетів інших людей
Припустимо, ви знаходитесь в середині деяких змін і хтось хоче, щоб ви переглянули деякі зобов'язання, які вони просто натиснули. git pull
Операція злиття (або відновлення бази даних) змінює робочий каталог та індекс, а це означає, що ваш робочий каталог та індекс повинні бути чистими.
Ви могли б використовувати git stash
і потім git pull
, але що робити, коли закінчуєте перевірку? Щоб повернутися туди, де ви були, вам потрібно скасувати злиття, створене компанією, git pull
та застосувати копію.
git remote update -p
(або git fetch --all -p
) не змінює робочий каталог чи індекс, тому його можна безпечно запустити в будь-який час - навіть якщо ви здійснили поетапні та / або незмінені зміни. Ви можете призупинити те, що ви робите, і переглядати чужі вчинки, не турбуючись про приховування чи закінчення зобов'язань, над якими ви працюєте. git pull
не дає вам такої гнучкості.
Перехід на віддалену гілку
Загальна схема використання Git полягає в тому, git pull
щоб внести останні зміни, за якими git rebase @{u}
слід усунути git pull
введений комітет злиття . Це загальноприйнята досить того, що Git має деякі параметри конфігурації , щоб зменшити ці два кроки за один крок, розповівши git pull
виконати перебазування замість злиття (див branch.<branch>.rebase
, branch.autosetuprebase
і pull.rebase
варіанти).
На жаль, якщо у вас є незапущена команда злиття, яку ви хочете зберегти (наприклад, фіксація, що об'єднує відгалужену гілку функції master
), ні перетягування бази даних ( git pull
з branch.<branch>.rebase
встановленим на true
), ні витягнення злиття ( git pull
поведінка за замовчуванням ), за яким слідує a Rebase буде працювати. Це тому, що git rebase
усуває злиття (це лінеаризує DAG) без --preserve-merges
опції. Операція витягування бази даних не може бути налаштована для збереження злиття, і злиття, яке слідує за нею, git rebase -p @{u}
не усуне злиття, викликане злиттям. Оновлення: Git v1.8.5 додано git pull --rebase=preserve
та git config pull.rebase preserve
. Ці причини , git pull
щоб зробити git rebase --preserve-merges
після завантаження вгору по течії фіксацій. (Завдяки функціоналу за хед -ап!)
Очищення видалених гілок
git pull
не обрізає гілки віддаленого відстеження, відповідні гілкам, які були видалені з віддаленого сховища. Наприклад, якщо хтось видаляє гілку foo
з віддаленого репо, ви все одно побачите origin/foo
.
Це призводить до того, що користувачі випадково відроджують вбиті гілки, оскільки вони думають, що вони все ще активні.
Краща альтернатива: використовувати git up
замістьgit pull
Замість цього git pull
я рекомендую створити та використовувати наступний git up
псевдонім:
git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'
Цей псевдонім завантажує всі останні комісії з усіх гілок вище за течією (обрізання мертвих гілок) і намагається переадресувати локальну гілку до останнього комітету на гілці вище за течією. Якщо це було успішним, то місцевих комітетів не було, тому ризик злиття конфлікту не було. Перемотка вперед не вдасться, якщо є місцеві (невдалені) зобов’язання, що дає вам можливість переглядати зобов’язання вище за течією, перш ніж вживати заходів.
Це все ще модифікує ваш робочий каталог непередбачуваними способами, але лише якщо у вас немає місцевих змін. На відміну від цього git pull
, git up
ніколи не підведе вас до швидкого очікування, що ви вирішите конфлікт злиття.
Ще один варіант: git pull --ff-only --all -p
Нижче наведена альтернатива вищезазначеному git up
псевдоніму:
git config --global alias.up 'pull --ff-only --all -p'
Ця версія git up
має таку саму поведінку, що і попередня git up
псевдонім, за винятком:
- повідомлення про помилку є дещо більш виразним, якщо ваша локальна гілка не налаштована з гілкою вище
- вона покладається на недокументовану функцію (
-p
аргумент, який передається fetch
), яка може змінюватися в майбутніх версіях Git
Якщо ви використовуєте Git 2.0 або новішу версію
За допомогою Git 2.0 та новіших версій ви можете налаштувати так, git pull
щоб вони виконували лише швидкі злиття вперед за замовчуванням:
git config --global pull.ff only
Це змушує git pull
діяти так git pull --ff-only
, але воно все ще не отримує всіх верховинних комісій чи очищення старих origin/*
гілок, тому я все одно вважаю за краще git up
.