Git Pull Force - Як замінити локальні зміни за допомогою Git

Коли ви навчитеся кодувати, рано чи пізно ви також дізнаєтеся про Системи контролю версій. І хоча в цьому просторі багато конкуруючих інструментів, одним із них є фактичний стандарт, який використовують майже всі в галузі. Це настільки популярно, що є компанії, які використовують його назву у своєму брендингу. Ми, звичайно, говоримо про Git.

Хоча Git - потужний інструмент, його сила добре прихована. Є кілька важливих концепцій, які ви повинні розуміти, щоб стати справді знаючими Git. Хороша новина полягає в тому, що, дізнавшись їх, ви навряд чи коли-небудь зіткнетеся з проблемами, від яких не втекти.

Типовий робочий процес

У типовому робочому процесі Git ви будете використовувати локальне сховище, віддалене сховище та одну або кілька гілок. У сховищах зберігається вся інформація про проект, включаючи всю його історію та всі гілки. Гілка - це, в основному, сукупність змін, що ведуть від порожнього проекту до поточного стану.

Після клонування сховища ви працюєте над локальною копією та вносите нові зміни. Поки ви не натискаєте локальні зміни у віддаленому сховищі, вся ваша робота доступна лише на вашому комп'ютері.

Після завершення завдання настав час синхронізуватися з віддаленим сховищем. Ви хочете здійснити віддалені зміни, щоб не відставати від прогресу проекту, і ви хочете просувати локальні зміни, щоб поділитися своєю роботою з іншими.

Місцеві зміни

Все добре, коли ви та решта вашої команди працюєте над абсолютно окремими файлами. Що б не сталося, ви не будете наступати один одному на ноги.

Однак бувають випадки, коли ви та ваші товариші по команді одночасно вносите зміни в одне і те ж місце. І тут зазвичай починаються проблеми.

Ви коли-небудь страчували git pullлише для того, щоб побачити страшних error: Your local changes to the following files would be overwritten by merge:? Рано чи пізно всі стикаються з цією проблемою.

Що ще більше бентежить, це те, що ви не хочете нічого об’єднувати, просто тягніть, так? Насправді тягнути трохи складніше, ніж ви могли подумати.

Наскільки точно працює Git Pull?

Витягування - це не одна операція. Він складається з отримання даних з віддаленого сервера, а потім об’єднання змін з локальним сховищем. Ці дві операції можна виконати вручну, якщо потрібно:

git fetch git merge origin/$CURRENT_BRANCH

У origin/$CURRENT_BRANCHчастині означає , що:

  • Git об'єднає зміни з віддаленого сховища з іменем origin(того, з якого ви клонували)
  • які були додані до $CURRENT_BRANCH
  • яких ще немає у вашому місцевому відділенні, де зареєстровано

Оскільки Git виконує злиття лише тоді, коли немає незафіксованих змін, кожен раз, коли ви запускаєте git pullз незафіксованими змінами, ви можете отримати проблеми. На щастя, є способи вирватися з неприємностей цілиною!

Ми - сім'я

Різні підходи

Якщо у вас є незафіксовані локальні зміни, і ви все ще хочете отримати нову версію з віддаленого сервера, випадок використання зазвичай потрапляє в один із наступних сценаріїв. Або:

  • вас не хвилюють місцеві зміни і ви хочете їх замінити,
  • ви дуже дбаєте про зміни і хотіли б застосувати їх після віддалених змін,
  • ви хочете завантажити віддалені модифікації, але поки не застосовувати їх

Кожен із підходів вимагає різного рішення.

Вас не турбують місцеві зміни

У цьому випадку ви просто хочете скинути всі незафіксовані локальні зміни. Можливо, ви модифікували файл для експерименту, але вам більше не потрібні зміни. Все, що вам цікаво, - це бути в курсі попереднього течії.

Це означає, що ви додаєте ще один крок між завантаженням віддалених змін та їх об’єднанням. Цей крок призведе до відновлення гілки до її немодифікованого стану, що дозволить git mergeпрацювати.

git fetch git reset --hard HEAD git merge origin/$CURRENT_BRANCH

Якщо ви не хочете вводити ім'я гілки кожен раз при запуску цієї команди Git має хороший ярлик , який вказує на вхідну гілку: @{u}. Вихідна гілка - це гілка у віддаленому сховищі, до якої ви натискаєте та отримуєте.

Ось як виглядали б вищезазначені команди з ярликом:

git fetch git reset --hard HEAD git merge '@{u}'

Ми цитуємо ярлик у прикладі, щоб не дати оболонці інтерпретувати його.

Ви дуже дбаєте про місцеві зміни

Коли ваші незмінені зміни є для вас значущими, існує два варіанти. Ви можете їх зафіксувати, а потім виконати git pull, а можна і сховати.

Приховування означає прибирання змін на мить, щоб повернути їх пізніше. Якщо бути точнішим, git stashстворює коміт, який не видно у вашій поточній гілці, але все ще доступний Git.

Щоб повернути зміни, збережені в останньому схованці, ви використовуєте git stash popкоманду. Після успішного застосування прихованих змін ця команда також видаляє зафіксовану комісію, оскільки вона більше не потрібна.

Тоді робочий процес може виглядати так:

git fetch git stash git merge '@{u}' git stash pop

By default, the changes from the stash will become staged. If you want to unstage them, use the command git restore --staged (if using Git newer than 2.25.0).

You Just Want to Download the Remote Changes

The last scenario is a little different from the previous ones. Let's say that you are in the middle of a very messy refactoring. Neither losing the changes nor stashing them is an option. Yet, you still want to have the remote changes available to run git diff against them.

As you have probably figured out, downloading the remote changes does not require git pull at all! git fetch is just enough.

One thing to note is that by default, git fetch will only bring you changes from the current branch. To get all the changes from all the branches, use git fetch --all. And if you'd like to clean up some of the branches that no longer exist in the remote repository, git fetch --all --prune will do the cleaning up!

Some Automation

Have you heard of Git Config? It's a file where Git stores all of the user-configured settings. It resides in your home directory: either as ~/.gitconfig or ~/.config/git/config. You can edit it to add some custom aliases that will be understood as Git commands.

For example, to have a shortcut equivalent to git diff --cached (that shows the difference between the current branch and the staged files), you'd add the following section:

[alias] dc = diff --cached

After that, you can run git dc whenever you wish to review the changes. Going this way, we can set up a few aliases related to the previous use cases.

[alias] pull_force = !"git fetch --all; git reset --hard HEAD; git merge @{u}" pf = pull_force pull_stash = !"git fetch --all; git stash; git merge @{u}; git stash pop"

This way, running git pull_force will overwrite the local changes, while git pull_stash will preserve them.

The Other Git Pull Force

Curious minds may have already discovered that there is such a thing as git pull --force. However, this is a very different beast to what's presented in this article.

It may sound like something that would help us overwrite local changes. Instead, it lets us fetch the changes from one remote branch to a different local branch. git pull --force only modifies the behavior of the fetching part. It is therefore equivalent to git fetch --force.

Like git push, git fetch allows us to specify which local and remote branch do we want to operate on. git fetch origin/feature-1:my-feature will mean that the changes in the feature-1 branch from the remote repository will end up visible on the local branch my-feature. When such an operation modifies the existing history, it is not permitted by Git without an explicit --force parameter.

Just like git push --force allows overwriting remote branches, git fetch --force (or git pull --force) allows overwriting local branches. It is always used with source and destination branches mentioned as parameters. An alternative approach to overwriting local changes using git --pull force could be git pull --force "@{u}:HEAD".

Conclusion

Світ Git величезний. Ця стаття висвітлювала лише один із аспектів обслуговування сховища: включення віддалених змін до локального сховища. Навіть цей повсякденний сценарій вимагав від нас трохи глибшого вивчення внутрішніх механізмів цього інструменту контролю версій.

Вивчення справжніх випадків використання допомагає краще зрозуміти, як працює Git під капотом. Це, в свою чергу, змусить вас почувати себе повноваженнями кожного разу, коли ви потрапляєте в халепу. Ми всі робимо це час від часу.