Підсумок
За замовчуванням 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.