Чому я хочу етапу перед виконанням у Git?


102

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

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

Редагувати: Я думаю, що я, можливо, плутаю термінологію. "Поетапний" файл - це те саме, що "відстежуваний" файл?


6
Ні. Відстежуваний файл - це файл, який відомий сховищу (як правило, з попереднього коміту). Поетапний файл - це файл, доданий до індексу, який згодом буде використаний для фіксації.
Mark Peters 02

Відповіді:


82

Коли ви фіксуєте, це буде лише фіксувати зміни в індексі ("поетапні" файли). Для цього існує багато способів використання, але найбільш очевидним є розбиття робочих змін на менші, самостійні частини. Можливо, ви виправили помилку під час реалізації функції. Ви можете git addпросто цей файл (або git add -pдодати лише частину файлу!), А потім зафіксувати це виправлення, перш ніж фіксувати все інше. Якщо ви використовуєте, git commit -aто ви просто змушуєте до addвсього перед комітом. Не використовуйте, -aякщо хочете скористатися інсценізацією файлів.

Ви також можете розглядати інсценовані файли як проміжну робочу копію за допомогою --cachedбагатьох команд. Наприклад, git diff --cachedпокаже, чим відрізняється сцена, HEADщоб ви могли бачити, що збираєтеся зробити, не змішуючи інші робочі зміни.


25
Інший справді загальновживаний спосіб - це те, коли деякі ваші зміни ніколи не повинні виконуватися; наприклад, ви можете інсценувати хороший матеріал, здійснити його, а потім продути поганий матеріал git reset --hard.
Cascabel 02

3
@BenJackson у вашому прикладі, у чому різниця між етапом + коміт та селективним комітом? Я не бачу різниці.
Eugenio

9
Я особисто не зміг отримати задовільної відповіді на запитання: "Який сенс постановки?" питання. Чесно кажучи, це просто непотрібно. Я вже використовую локальну гілку, тому немає ризику зламати збірку. Я не збираюся публікувати та робити запит на витяг, поки не буду повністю задоволений своїми змінами. Я вже можу розділити свої коміти логічно. Просто не потрібно проміжного кроку. Таким чином, я ніколи не використовую його.
mrplainswalker

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

1
@ kiwicomb123 Зазвичай тому, що ви виявили цю помилку під час роботи над чимось іншим, і ви хочете мати це виправлення у власному коміті з власним повідомленням журналу та гнучкістю для об'єднання / вишневого вибору / перебазування, що виправляють десь ще.
Бен Джексон,

26
  • Область проходження дає контроль, щоб зробити коміт меншим. Просто внесіть одну логічну зміну в код, додайте змінені файли в інтерактивну область і, нарешті, якщо зміни погані, то оформлення замовлення до попереднього коміту або іншим чином фіксуйте зміни. Це дає можливість розділити завдання на менші завдання та зробити менші зміни. З областю постановки легше зосередитись на невеликих завданнях.
  • Він також пропонує вам зробити перерву і забути про те, скільки роботи ви зробили до перерви. Припустимо, вам потрібно змінити три файли, щоб внести одну логічну зміну, і ви змінили перший файл і потребуєте тривалої перерви, поки не почнете вносити інші зміни. На даний момент ви не можете здійснити комісію, і ви хочете відстежити, з якими файлами ви закінчили, щоб після повернення вам не потрібно було намагатися згадати, скільки роботи було зроблено. Тож додайте файл до індексу, і це збереже вашу роботу. Повернувшись, просто git diff --stagedперевірте, які файли ви змінили і де, і почніть вносити інші зміни.

13

Однією з практичних цілей індексування є логічне відокремлення файлових комітів.

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

Припустимо , у вас є 4 файлу fileA.html, fileB.html, fileC.htmlі fileD.html. Ви вносите зміни до всіх 4 файлів і готові до фіксації, але зміни в них fileA.htmlі fileB.htmlлогічно пов’язані (наприклад, однакова реалізація нової функції в обох файлах), тоді як зміни у файлі fileC.htmlта fileD.htmlокремі логічно не пов’язані з попередніми файлами. Ви можете спочатку сформувати файли fileA.htmlта fileB.htmlі скопіювати їх.

git add fileA.html
git add fileB.html
git commit -m "Implemented new feature XYZ"

Потім на наступному кроці ви виконуєте поетапне внесення змін у інші два файли.

git add fileC.html
git add fileD.html
git commit -m "Implemented another feature EFG"

6
У цьому прикладі я не впевнений, чи дійсно потрібна постановка. Після редагування всіх 4 файлів, якщо я просто хочу зафіксувати fileA.html і fileB.html, я все одно можу здійснити фіксацію, не виконуючи це. Команда: git commit -m "Implemented new feature XYZ" fileA.html fileB.html добре працювала б, не потребуючи команд git add. Я походжу зі світу диверсій, де інсценізація не є поняттям, тому я не впевнена в корисності інсценізації git
Паван

5

Простіше зрозуміти використання команд git, addі commitякщо ви уявляєте, що файл журналу зберігається у вашому сховищі на Github. Типовий файл журналу проекту для мене може виглядати так:

---------------- Day 1 --------------------
Message: Complete Task A
Index of files changed: File1, File2

Message: Complete Task B
Index of files changed: File2, File3
-------------------------------------------

---------------- Day 2 --------------------
Message: Correct typos
Index of files changed: File3, File1
-------------------------------------------
...
...
...and so on

Зазвичай я починаю свій день із git pullпрохання і закінчую його git pushпроханням. Отже, все, що є в записі дня, відповідає тому, що відбувається між ними. Протягом кожного дня є одне або кілька логічних завдань, які я виконую, і які вимагають зміни кількох файлів. Файли, відредаговані під час цього завдання, перераховані в індексі.

Кожне з цих підзавдань (Завдання A та Завдання B тут) є окремими комітами. git addКоманда додає файли в список «Список змінених файлів». Цей процес також називають інсценуванням. У git commitкомандному записи / допрацьовує зміни і відповідний список індексів поряд з налаштованим повідомленням.

Пам'ятайте, що ви все ще змінюєте лише локальну копію вашого сховища, а не копію на Github. Після цього, лише коли ви робите «git push», всі ці записані зміни разом із вашими індексними файлами для кожного коміту потрапляють до головного сховища (на Github).

Як приклад, щоб отримати другий запис у цьому уявному файлі журналу, я б зробив:

git pull
# Make changes to these files
git add File3 File4
# Verify changes, run tests etc..
git commit -m 'Correct typos'
git push

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


2

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

Ви можете працювати над кількома функціями / помилками в одному робочому каталозі і все одно створювати значущі коміти. Наявність єдиного робочого каталогу, який містить всю нашу активну роботу, також дуже зручно. (Це можна зробити без проміжної області, лише якщо зміни ніколи не перекривають файл. І ви також маєте додаткову відповідальність за відстеження вручну, чи вони перекриваються)

Інші приклади можна знайти тут: Використання індексу

І найкраще, переваги не зупиняються на цьому списку робочих процесів. Якщо унікальний робочий процес все-таки з’явиться, ви можете бути майже впевнені, що простір допоможе вам допомогти.


2

Щоб розширити відповідь Бена Джексона , що добре, давайте уважно розглянемо вихідне питання. (Див. Його відповідь щодо того, чому турбувати питання типу; це більше про те, що відбувається .)

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

Це не зовсім правильно. Резервні копії та контроль версій, безумовно, пов’язані між собою - наскільки сильно залежить від деяких речей, які певною мірою стосуються думки, - але, безумовно, є певні відмінності, хоча б лише за намірами: Резервні копії, як правило, призначені для аварійного відновлення (машина виходить з ладу, вогонь знищує ціла будівля, включаючи всі носії інформації тощо). Контроль версій, як правило, розроблений для детальнішої взаємодії та пропонує функції, яких резервне копіювання немає. Резервні копії зазвичай зберігаються деякий час, а потім видаляються як "занадто старі": більш важливим є більш свіже резервне копіювання. Зазвичай контроль версій назавжди зберігає кожну встановлену версію.

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

Так і ні. Дизайн Git тут дещо своєрідний. Існують системи контролю версій, які не вимагають окремого етапу переходу. Наприклад, Mercurial, який інакше дуже схожий на Git з точки зору використання, не вимагає окремого hg addкроку, крім самого першого, який представляє абсолютно новий файл. З Mercurial ви використовуєте hgкоманду, яка вибирає певний коміт, потім ви робите свою роботу, потім запускаєте hg commit, і все готово. З Git ви використовуєте git checkout, 1 тоді ви робите свою роботу, потім запускаєте git add, а потім git commit. Чому зайвий git addкрок?

Секрет тут полягає в тому, що Git називає, по-різному, індекс або область проходження , або іноді - рідко в наші дні - кеш . Це все назви для одного і того ж.

Редагувати: Я думаю, що я, можливо, плутаю термінологію. "Поетапний" файл - це те саме, що "відстежуваний" файл?

Ні, але це пов’язано. Відслідковуються файл один , який існує в індексі Git і . Щоб правильно зрозуміти індекс, добре почати з розуміння комітів.


Починаючи з версії Git 2.23, ви можете використовувати git switchзамість git checkout. У цьому конкретному випадку ці дві команди роблять абсолютно те саме. Нова команда існує, тому що git checkoutперенасичена забагато речей; вони були розділені на дві окремі команди, git switchі git restore, щоб полегшити та безпечніше використовувати Git.


Коміти

У Git коміт зберігає повний знімок кожного файлу, про який знає Git. (Про які файли знає Git? Ми побачимо це в наступному розділі.) Ці знімки зберігаються у спеціальній, лише для читання, лише для Git, стиснутій та дедупльованій формі, яку загалом може читати лише сам Git . (У кожному коміті є більше речей, ніж просто цей знімок, але це все, що ми розглянемо тут.)

Видалення дублікатів допомагає використовувати простір: ми, як правило, міняємо лише кілька файлів, а потім робимо новий коміт. Отже, більшість файлів у коміті здебільшого збігаються з файлами у попередньому коміті. Просто повторно використовуючи ці файли безпосередньо, Git економить багато місця: якщо ми торкнулися лише одного файлу, новий коміт займає місце лише для однієї нової копії. Навіть тоді він стискається - іноді дуже стискається, хоча це насправді трапляється пізніше - так що .gitкаталог може бути насправді меншим, ніж містяться в ньому файли, як тільки вони будуть розширені до звичайних повсякденних файлів. Видалення дублікатів безпечно, оскільки створені файли заморожені на весь час. Ніхто не може змінити одну, тому коміти можуть залежати від копій один одного.

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

Це означає, що коли ви перевіряєте певний коміт, автоматично створюється дві копії кожного файлу:

  • У поточному коміті Git має заморожену на весь час копію Git-ified . Ви не можете змінити цю копію (хоча, звичайно, ви можете вибрати інший коміт або зробити новий коміт).

  • У вашому робочому дереві є копія нормального формату. Ви можете робити все, що завгодно, використовуючи будь-яку з команд на комп’ютері.

На цьому зупиняються інші системи контролю версій (включаючи Mercurial, як уже згадувалося вище), на цих двох копіях. Ви просто модифікуєте свою копію робочого дерева, а потім фіксуєте. Git ... ні.

Індекс

Поміж цими двома копіями Git зберігає третю копію 2 кожного файлу. Ця третя копія має заморожений формат , але на відміну від замороженої копії у коміті, ви можете її змінити. Щоб змінити його, ви використовуєте git add.

У git addзасобі командного зробити індекс копія файлу збігається з роботою дерево копії . Тобто, ви говорите Git: Замініть копію замороженого формату, що не дублюється, яка зараз знаходиться в індексі, стискаючи мою оновлену копію робочого дерева, видаляючи її з копії та готуючи її до заморожування, на новий коміт. Якщо ви не використовуєте git add, індекс все ще зберігає копію замороженого формату з поточного коміту.

Коли ви запускаєте git commit, Git пакує все, що є в індексі, а потім використовувати як новий знімок. Оскільки він уже в замороженому форматі та попередньо розмножений, Git не повинен робити багато зайвої роботи.

Це також пояснює, що таке відстежувані файли . Неотслежіваемих файл являє собою файл , який знаходиться в робочому дереві , але НЕ в індексі Git і зараз . Немає значення, як це файл завершився в такому стані. Можливо, ви скопіювали його з іншого місця на комп’ютері у своє робоче дерево. Можливо, ви створили його тут свіжим. Можливо, в індексі Git була копія, але ви видалили цю копію за допомогою git rm --cached. Так чи інакше, у вашому робочому дереві є копія, але в індексі Git її немає. Якщо ви зробите новий коміт зараз, цей файл не буде в новому коміті.

Зверніть увагу, що git checkoutспочатку заповнює індекс Git з коміту, який ви перевіряєте. Отже, індекс починає відповідати коміту. Git також заповнює ваше робоче дерево з цього самого джерела. Отже, спочатку всі троє збігаються. Коли ви змінюєте файли у вашому робочому дереві, і git addвони добре, тепер індекс та ваше робоче дерево збігаються. Потім ви запускаєте, git commitі Git робить новий коміт з індексу, і тепер усі три знову збігаються.

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

Це все, але це все одно досить складно! Це особливо складно, оскільки немає простого способу точно побачити, що є в індексі Git. 3 Але є команда Git, яка повідомляє вам, що відбувається, таким чином, досить корисно, і ця команда є git status.


2 Технічно це насправді взагалі не є копією . Натомість це посилання на файл Git-ified, попередньо дедупльований та все інше. Тут також є багато іншого, наприклад режим, назва файлу, номер проміжного етапу та деякі дані кешу, щоб Git швидко працював. Але якщо ви не ввійдете в роботу з деякими командами низького рівня Git - git ls-files --stageі git update-indexзокрема - ви можете просто сприймати це як копію.

3git ls-files --stage команда покаже вам імена і номер поетапності кожного файлу індекс Git, але зазвичай це не дуже корисно в будь-якому випадку.


git status

git statusКоманда на насправді працює, запустивши дві окремі git diffкоманди для вас (а також робити деякі інші корисні речі, такі , як кажу вам , яку гілку ви перебуваєте).

Перший git diffпорівнює поточний коміт, який, пам’ятайте, заморожений на всі часи, з тим, що є в індексі Git. Для однакових файлів Git взагалі нічого не скаже. Для файлів, що відрізняються , Git скаже вам, що цей файл організовано для коміту . Це включає в себе все нові файли, якщо зобов'язання не sub.pyв ньому, але індекс дійсно є sub.pyв ньому, то додається, і цей файл будь-які видалені файли, які були (і є) в фіксації , але не в індекс вже ( git rmможливо,).

Другий git diffпорівнює всі файли в індексі Git з файлами у вашому робочому дереві. Для однакових файлів Git взагалі нічого не говорить. Для файлів, які відрізняються , Git буде сказати вам , що цей файл не поставив для фіксації . На відміну від першої різниці, цей конкретний список не містить абсолютно нових файлів: якщо файл untrackedіснує у вашому робочому дереві, але не в індексі Git, Git просто додає його до списку невідстежуваних файлів . 4

Врешті-решт, накопичивши ці файли, що не відстежуються, у списку, git statusбуде також оголошено імена цих файлів, але є особливий виняток: якщо ім'я файлу вказане у .gitignoreфайлі, це придушує цей останній список. Зверніть увагу, що перелік відстежуваного файлу - того, що входить до індексу Git - в a .gitignoreтут не впливає : файл знаходиться в індексі, тому його порівнюють і фіксують, навіть якщо він вказаний у .gitignore. Файл ігнорування пригнічує лише скарги щодо "файлу без відстеження". 5


4 При використанні короткої версії git status- git status -sфайли, що не відстежуються, не так відокремлені, але принцип той же. Накопичуючи подібні файли, ви також можете git statusузагальнити купу імен файлів, що не відстежуються, просто надрукувавши ім'я каталогу, іноді. Щоб отримати повний список, використовуйте git status -uallабо git status -u.

5 Перерахування файлу також змушує масово додавати багато файлових операцій, таких як git add .або git add *пропускати невідстежений файл. Ця частина стає дещо складнішою, оскільки ви можете використовувати git add --forceдля додавання файлу, який зазвичай пропускається. Є деякі інші, як правило, другорядні особливі випадки, які все додають до цього: файл .gitignoreможе бути більш правильно викликаний .git-do-not-complain-about-these-untracked-files-and-do-not-auto-add-themабо щось настільки ж громіздке. Але це занадто смішно, тож .gitignoreце так .


git add -u, git commit -aІ т.д.

Тут є кілька зручних ярликів:

  • git add .додасть усі оновлені файли до поточного каталогу та будь-якого підкаталогу. Це поважає .gitignore, тому, якщо на файл, який наразі не відстежується, не скаржиться git status, він не буде автоматично доданий.

  • git add -uавтоматично додасть усі оновлені файли в будь-яке місце у вашому робочому дереві . 6 Це стосується лише відстежуваних файлів. Зверніть увагу, що якщо ви видалили копію робочого дерева, це також призведе до видалення копії індексу ( git addробить це як частину того, щоб індекс збігався з робочим деревом ).

  • git add -Aце як біг git add .із верхнього рівня вашого робочого дерева (але див. виноску 6).

Крім них, ви можете бігати git commit -a, що приблизно еквівалентно 7 бігу, git add -uа потім git commit. Тобто це дає вам таку саму поведінку, яка зручна в Mercurial.

Я взагалі не раджу git commit -aшаблон: я вважаю, що його краще використовувати git statusчасто, уважно подивіться на результати , і якщо статус не такий, як ви очікували, з’ясуйте, чому це так. Використовуючи git commit -a, занадто просто випадково змінити файл і внести зміни, які ви не мали намір здійснити. Але це здебільшого питання смаку / думки.


6 Якщо ваша версія Git передує Git 2.0, будьте тут обережні: git add -uпрацює лише у поточному каталозі та підкаталогах, тому спочатку потрібно піднятися на верхній рівень вашого робочого дерева. git add -AВаріант має подібне питання.

7 Я кажу приблизно еквівалентно, оскільки git commit -aнасправді працює шляхом створення додаткового індексу та використання цього іншого індексу для фіксації. Якщо коміт працює , ви отримуєте той самий ефект, що і виконання git add -u && git commit. Якщо фіксація не працює - якщо ви змусите Git пропустити фіксацію будь-яким із багатьох способів, якими ви можете це зробити, - після цього файли не будуть git add-ed, оскільки Git викидає тимчасовий додатковий індекс і повертається до використання основного індексу .

Якщо ви використовуєте git commit --onlyтут, виникають додаткові ускладнення . У цьому випадку Git створює третій індекс, і все стає дуже складним, особливо якщо ви використовуєте хуки перед фіксацією. Це ще одна причина використовувати окремі git addоперації.


1

Я бачу сенс використовувати етап для зменшення комітів, як згадували @Ben Jackson і @Tapashee Tabassum Urmi, і іноді я використовую його для цієї мети, але в основному я використовую його, щоб зробити свої коміти більшими! ось моя думка:

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

Я просто інсценізую менші кроки один на одного, і коли я відчуваю, що це гідно вчинення, я роблю це. Таким чином, я видаляю непотрібні коміти з часової шкали, але в змозі скасувати (замовити) останній крок.

Я бачу інші способи зробити це (спрощення історії git), які ви можете використовувати залежно від ваших уподобань:

  1. git edit (що змінює ваш останній коміт), що не є тим, що ви хочете для цієї конкретної мети (я бачу це переважно як поганий коміт, а потім виправлення)
  2. git rebase, що є задумом і може спричинити серйозні проблеми для вас та інших, хто використовує ваше сховище.
  3. створити тимчасову гілку, об'єднати, а потім видалити її (що також є хорошим варіантом, вимагає більше кроків, але дає більше контролю)

0

Це як прапорець, що надає можливість вибору файлів, які слід фіксувати.

наприклад, якщо я відредагував fileA.txtта. fileB.txtАле я хочу внести зміни fileA.txtлише. тому що я ще не закінчив fileB.txt.

Я можу просто використовувати git add fileA.txtта фіксувати, використовуючи, git commit -m "changed fileA.txt"і продовжувати працювати, fileB.txtа після закінчення я можу fileB.txtлегко фіксувати

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.