Чому в Git є два способи зняти файл?


1166

Іноді git пропонує git rm --cachedзняти файл, іноді git reset HEAD file. Коли я повинен використовувати який?

Редагувати:

D:\code\gt2>git init
Initialized empty Git repository in D:/code/gt2/.git/
D:\code\gt2>touch a

D:\code\gt2>git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       a
nothing added to commit but untracked files present (use "git add" to track)

D:\code\gt2>git add a

D:\code\gt2>git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#       new file:   a
#
D:\code\gt2>git commit -m a
[master (root-commit) c271e05] a
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 a

D:\code\gt2>touch b

D:\code\gt2>git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       b
nothing added to commit but untracked files present (use "git add" to track)

D:\code\gt2>git add b

D:\code\gt2>git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       new file:   b
#

20
Чому? Я б сказав, що інтерфейс командної лінії git органічно розвивався і ніколи не піддавався капітальній перебудові, щоб зробити це послідовними. (Якщо ви НЕ згодні, зверніть увагу , як git rmможе як етап видалення , а також прибрати з буфера в додаток )
Roman Старков

3
@romkyns: Я погоджуюся, що інтерфейс Git має декілька дивацтв, оскільки він розвивався органічно, але видалення, безумовно, є зворотною функцією додатку, тож чи не логічно rmце скасовувати add? Як ви думаєте, як rmслід поводитися?
Заз

6
Єдиною фактичною відповіддю на ваше запитання є те, що одразу після git initзапиту не HEADпотрібно скидати.
Майлз Рут

Найкращі документи для цього: help.github.com/articles/changing-a-remote-s-url
ScottyBlades

4
@Zaz, я дам свою думку. rmпередбачає видалення в контексті unix. Це не протилежне додавання до індексу. Функція для видалення файлів не повинна перевантажуватися функціями для зміни стану інсценізації. Якщо є деталі реалізації, які дозволяють зручно поєднувати, це просто вказує на відсутність продуманого шару абстрагування в git, який би зрозумів зручність використання.
Джошуа Голдберг

Відповіді:


1891

git rm --cached <filePath> не видаляє файл, він фактично поетапно видаляє файли (файли) з репо (припускаючи, що це вже було скоєно раніше), але залишає файл у вашому робочому дереві (залишаючи з вами неперевірений файл).

git reset -- <filePath>буде нестабільним будь-які поетапні зміни для даного файлу.

Це git rm --cachedозначає , що якщо ви використовували новий інсценований файл, він би виглядав так, ніби ви його лише зняли, оскільки він раніше не робився.

Оновити git 2.24
У цій новій версії git ви можете використовувати git restore --stagedзамість git reset. Дивіться документи git .


70
Я б сказав git rm --cachedнестабільність файлу, але не видаляє його з робочого каталогу.
П’єр де ЛЕСПІНАЙ

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

4
Тому, як правило, можна було б git rm --cached <filePath>видалити деякі файли (файли) з репо після того, як він зрозумів, що він ніколи не був у репо: так, швидше за все, запустіть цю команду і потім додайте до неї відповідні файли gitignore. Я прав?
Адріан Бе

13
Маючи багато голосів і на питання, і на відповіді, я б сказав, що, мабуть, ми хочемо мати unstageкоманду git.
milosmns

4
"git status" радить зараз: використовувати "git recovery --staged <file> ..." to untage
yucer

334

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

git reset HEAD file(який за замовчуванням використовує --mixedпрапор) відрізняється тим, що у випадку, коли файл уже знаходиться в репо, він замінює індексну версію файлу версією з репо (HEAD), фактично знімаючи зміни до нього.

У випадку неперевершеного файлу він видалить увесь файл, оскільки цього файла не було в HEAD. В цьому аспекті git reset HEAD fileі git rm --cachedтакі ж, але вони не такі ж (як пояснено в разі файлів вже в репо)

На питання Why are there 2 ways to unstage a file in git?- ніколи насправді не існує лише одного способу зробити що-небудь в git. в чому краса цього :)


7
І прийнята відповідь, і ця одна чудова, і поясніть, чому б ви використовували один проти іншого. Але вони не відповідають безпосередньо на неявне запитання, чому git пропонує два різні методи. У першому випадку на прикладі ОП щойно було зроблено git init. У цьому випадку git пропонує "git rm --cached", оскільки в цьому місці в сховищі немає ніяких комісій, тому HEAD недійсний. "git reset HEAD - a" виробляє: "fatal: Не вдалося вирішити" HEAD "як дійсний номер."
sootsnoot

5
з "git checkout", чи не втратили б ви всі зміни, внесені до файлу? Це не те саме, що видалити файл, якщо я не розумію.
Джон Дейгань

there is never really only one way to do anything in git. that is the beauty of it- Хм ... чому? це завжди чудово, коли існує лише один очевидний шлях. це економить багато нашого часу та пам’яті на мозку))
Ото Шавадзе

128

Все просто:

  • git rm --cached <file> змушує git зупиняти відстеження файлу повністю (залишаючи його у файловій системі, на відміну від простого git rm*)
  • git reset HEAD <file> нестабільність будь-яких модифікацій, внесених у файл з моменту останнього фіксації (але не повертає їх у файловій системі, всупереч тому, що може запропонувати ім'я команди **). Файл залишається під контролем редагування.

Якщо файл раніше не знаходився під контролем редагування (тобто ви видаляєте файл, який ви тільки що git addредагували вперше), то дві команди мають однаковий ефект, отже, поява цих "двох способів зробити щось ".

* Майте на увазі, у своїй відповіді застереження @DrewT згадує про git rm --cachedфайл, який раніше був зафіксований у сховище. У контексті цього питання про файл, щойно доданий і ще не введений, не варто турбуватися.

** Мені було страшно тривалий час використовувати команду скидання git через його назву - і досі я часто шукаю синтаксис, щоб переконатися, що я не викручуюся. ( Оновлення : я , нарешті , знайшов час , щоб підвести підсумки використання git resetв сторінці tldr , так що тепер у мене є краще ментальна модель , як вона працює, і швидкі посилання для того, коли я забуваю деякі подробиці.)


Цеgit rm <file> --cached
неоновий

8
Я дійсно не думаю, що редакція цієї відповіді 4 серпня 2015 року було загальним покращенням. Можливо, вона має фіксовану технічну коректність (я не вважаю кваліфікованою, щоб оцінити це), але я боюся, що вона зробила тон відповіді набагато менш доступним, ввівши мову на зразок "знімає обов'язкове значення для початку відстеження поточно не відстежуваного файлу ", і використовуючи жаргони, такі як" індекс "і" голова ", саме такі речі, які відлякують початківців. Якщо хтось може, будь ласка, відредагуйте, щоб відновити більш зручну для новачків мову.
waldyrious

5
Погодьтеся з @waldyrious. Оригінальна відповідь, можливо, не була прямо з підручника з git, але вона відповіла на питання на достатньому технічному рівні. Технічні деталі повинні бути роз'яснені в коментарях, а не як редакція, яка затіняла початковий намір.
Саймон Робб

Я повернув правки. Я вважаю, що громадою було достатньо підтверджено (у попередніх коментарях та голосуваннях за них), що редагування шкодило ясності відповіді.
waldyrious

Примітка @DrewT попереджає, що при використанні rm --cachedта натисканні кожен, хто тягне за собою ту саму гілку, буде фактично видалено файли (файли) зі свого робочого дерева.
Том Хейл

53

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

me$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   to-be-added
#   modified:   to-be-modified
#   deleted:    to-be-removed
#

me$ git reset -q HEAD to-be-added

    # ok

me$ git reset -q HEAD to-be-modified

    # ok

me$ git reset -q HEAD to-be-removed

    # ok

# or alternatively:

me$ git reset -q HEAD to-be-added to-be-removed to-be-modified

    # ok

me$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   to-be-modified
#   deleted:    to-be-removed
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   to-be-added
no changes added to commit (use "git add" and/or "git commit -a")

git reset HEAD(без -q) видає попередження про модифікований файл, і його вихідний код - 1, який буде розглядатися як помилка в сценарії.

Редагувати: git checkout HEAD to-be-modified to-be-removedтакож працює для видалення, але видаляє зміни повністю з робочої області

Оновлення git 2.23.0: час від часу команди змінюються. Тепер, git statusкаже:

  (use "git restore --staged <file>..." to unstage)

... що працює для всіх трьох типів змін


Дякую, з перших двох відповідей (напевно, лише моє незнання термінології) було не зовсім зрозуміло, що скидання git залишило зміни у файлі локально (на відміну від git checkout, яке поверне їх).
супдог

На початку слід попередити про версію, оскільки стара версія видаляє файли в нових версіях
Луїс Маурісіо

@LuisMauricio, яка команда видаляє файли?
Даніель Олдер

36

якщо ви випадково влаштували файли, які не хотіли б робити, і хочете бути впевненими, що ви зберігаєте зміни, ви також можете використовувати:

git stash
git stash pop

це виконує скидання на HEAD і повторно застосовує ваші зміни, дозволяючи повторно поставити окремі файли для фіксації. це також корисно, якщо ви забули створити гілку функцій для запитів на тягнення ( git stash ; git checkout -b <feature> ; git stash pop).


3
Це чисте рішення і набагато менш занепокоєння, ніж набір "git rm"
Subimage

1
git stashмає й інші супутні переваги, оскільки це створює записи в рефлогу, які згодом будуть доступні в майбутньому. коли ви сумніваєтесь, ідіть вперед і зробіть git stash(наприклад, git stash save -u "WIP notes to self"'-u' - це включити будь-які нові / неповернені файли до скрипту для зберігання) ... тоді спробуйте git reflog show stashпереглянути список прихованих комісій та їх ша. Я рекомендую оболонку псевдонім на зразокalias grs="git reflog show stash"
cweekly

15

Ці 2 команди мають кілька тонких відмінностей, якщо файл, про який йде мова, вже знаходиться в репо-репортажі та знаходиться під контролем версій (раніше зроблено тощо):

  • git reset HEAD <file> нестабільність файлу в поточній комісії.
  • git rm --cached <file>нестабільний файл також для майбутніх комісій. Це нестандартно, поки воно знову не додається git add <file>.

І є ще одна важлива різниця:

  • Після запуску git rm --cached <file>та натискання вашої гілки на віддалений, кожен, хто витягне вашу гілку з віддаленого, отримає файл АКТУАЛЬНО видалений зі своєї папки, навіть незважаючи на те, що у вашому локальному робочому наборі файл просто не відслідковується (тобто фізично не видаляється з папки).

Остання відмінність важлива для проектів, які включають конфігураційний файл, де кожен розробник у команді має різні конфігурації (тобто різні базові URL-адреси, ip чи порти), тому якщо ви використовуєте git rm --cached <file>когось, хто витягує вашу гілку, доведеться вручну повторно створіть конфігурацію, або ви можете надіслати їх своїми, і вони зможуть повторно відредагувати його назад до своїх ip-налаштувань (тощо), оскільки видалення впливає лише на людей, які тягнуть вашу гілку з пульта.


10

Скажімо, вам stageцілий каталог через git add <folder>, але ви хочете виключити файл із списку поетапних (тобто зі списку, який генерується під час запуску git status) і зберегти модифікації у виключеному файлі (ви працювали над чимось, і він не готовий до фіксації, але ви не хочете втрачати свою роботу ...). Ви можете просто використовувати:

git reset <file>

Запустивши git status, ви побачите, що ви не resetє unstagedфайлами , а решта файлів ви addedвсе ще в stagedсписку.


10

1.

D:\code\gt2>git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#       new file:   a

(використовувати "git rm --cached ..." для нестабільності)

  • git - це система покажчиків

  • у вас ще немає зобов'язання змінити вказівник на

  • єдиний спосіб "вийняти файли з відра, на який вказують", - це видалити файли, про які ви сказали git, щоб спостерігати за змінами

2.

D:\code\gt2>git commit -m a
[master (root-commit) c271e05] a
0 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 a

git počin -ма

  • ви погодилися, " збережено "

3.

D:\code\gt2>git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       new file:   b
#

(використовуйте "git reset HEAD ..." для нестабільності)

  • Ви взяли на себе зобов’язання у своєму коді в цей час
  • тепер ви можете скинути вказівник на ваш комітет " повернути назад до останнього збереження "

1
Це насправді єдина відповідь, яка правильно відповідає на питання, ІМО. Насправді він відповідає на питання, яке полягає не в тому, "які відмінності між" git rm - cached "і" git reset HEAD ", але" чому git непослідовно дає обидва варіанти як варіанти? " до того, коли ви git initвперше.
Міль Рут

5

Я здивований, що ніхто не згадав про git reflog ( http://git-scm.com/docs/git-reflog ):

# git reflog
<find the place before your staged anything>
# git reset HEAD@{1}

Reflog - це історія git, яка не лише відслідковує зміни до репо, але й відстежує дії користувача (наприклад, тягнути, перевірити в іншу гілку тощо) та дозволяє скасувати ці дії. Тож замість видалення файлу, який був помилково інсценований, де ви можете повернутися до того пункту, коли ви не ставили файли.

Це аналогічно, git reset HEAD <file>але в деяких випадках може бути більш детальним.

Вибачте - не дуже відповідаю на ваше запитання, але просто вказую на ще один спосіб нестабільних файлів, які я використовую досить часто (мені дуже подобаються відповіді Райана Стюарта і дуже хороший.);) Я сподіваюся, що це допоможе.


5

Просто використовуйте:

git reset HEAD <filename>

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


3

Мені здається, що git rm --cached <file>вилучає файл з індексу, не видаляючи його з каталогу, де звичайна робота git rm <file>буде виконувати і те, і інше, як ОС rm <file>видалить файл із каталогу, не видаляючи його версію.


1

Лише для версій 2.23 і вище

Замість цих пропозицій ви можете використати git restore --staged <file>для того, щоб unstageфайл (и).


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