Спрятать в git только поэтапные изменения - возможно ли?

Есть ли способ спрятать только мои поэтапные изменения? Сценарий, с которым у меня возникают проблемы, - это когда я работал над несколькими ошибками одновременно и имел несколько неустановленных изменений. Я хотел бы иметь возможность обрабатывать эти файлы по отдельности, создавать свои файлы .patch и хранить их до тех пор, пока код не будет одобрен. Таким образом, когда он будет одобрен, я могу спрятать всю мою (текущую) сессию, выявить эту ошибку и отправить код.

Я ошибаюсь? Я неправильно понимаю, как git может работать другими способами, чтобы упростить мой процесс?


person MrDuk    schedule 07.02.2013    source источник
comment
Да, вы, вероятно, делаете что-то не так, чтобы попасть в такую ​​ситуацию. Еще полезный вопрос. Вы действительно должны спрятать или ветвиться, прежде чем приступить к следующему исправлению. Тангенциальный ответ stackoverflow.com/a/50692885, вероятно, лучший способ справиться с этим в git. Игра с тайником часто приводит к странным вещам в моей рабочей области, если я вытаскивал коммиты из апстрима.   -  person Samuel Åslund    schedule 11.10.2019


Ответы (15)


Да, это возможно с DOUBLE STASH

  1. Подготовьте все свои файлы, которые вам нужно спрятать.
  2. Запустите git stash --keep-index. Эта команда создаст тайник с ВСЕМИ вашими изменениями (поэтапными и неустановленными), но оставит поэтапные изменения в вашем рабочем каталоге (все еще в состоянии постановки).
  3. Запустите git stash push -m "good stash"
  4. Теперь ваш "good stash" содержит ТОЛЬКО промежуточные файлы.

Теперь, если вам нужны неустановленные файлы перед хранением, просто примените первый тайник (созданный с помощью --keep-index), и теперь вы можете удалить файлы, которые вы храните в "good stash".

Наслаждаться

person Bartłomiej Semańczyk    schedule 05.10.2015
comment
Он хранит изменения в подмодулях, даже если они не являются постановочными. Это можно обойти? - person rluks; 15.08.2016
comment
это каким-то образом оставило все новые файлы (даже подготовленные). - person Aurimas; 05.03.2017
comment
@Aurimas, чтобы спрятать новые файлы, вам нужно использовать переключатель -u. - person Gyromite; 22.09.2017
comment
когда вы повторно применяете первый тайник и получаете все изменения обратно, в то время как вас могут интересовать только неэтапные изменения, используйте параметр git stash apply --index. Это попытается сохранить ваше неустановленное состояние. Теперь удалить ненужные изменения из рабочего дерева стало проще. - person otomo; 27.09.2018
comment
Хотя мне не нужно было делать именно то, что сказано в этом ответе, знание флага --keep-index было очень полезным. - person Aaron Krauss; 07.11.2018
comment
я думал, что этот ответ был очень запутанным, вместо этого я пойду с git stash push --patch - person Doug; 01.07.2019
comment
@ Bartłomiej Semańczyk, ваш ответ был мне очень полезен, просто был случай, когда мне пришлось отменить случайное удаление файла, вызванное каким-то ошибочным кодом, который я написал, испортил больше, чем мое рабочее дерево git, использовал ваш ответ чтобы исправить мою проблему, престиж. Разместите его ниже, если кто-то столкнется с той же проблемой, что и я. - person wmax; 09.08.2019
comment
Версия 2.17.1 из git stash -m "good stash" дает error: pathspec '[...]/good stash' did not match any file(s) known to git. Did you forget to 'git add'?. Я обновлю ответ с новым синтаксисом (замените -m на save). - person Iain Samuel McLean Elder; 21.11.2019
comment
Снова обновлен с push -m. Я только что узнал, что save устарел. - person Iain Samuel McLean Elder; 21.11.2019
comment
Я бегу git stash drop stash@{n} после этого. - person Marc.2377; 24.01.2020
comment
Вы можете включить неотслеживаемые файлы на шаге 2 выполнения git stash --keep-index --include-untracked. - person Wesley Gonçalves; 06.07.2020
comment
Это работало хорошо, но не убирало неустановленные элементы. Я запустил git stash pop --index 1, чтобы восстановить неустановленные изменения и удалить неустановленное хранилище. После этого в список тайников попадает только хороший тайник. - person Luke; 25.08.2020
comment
Ой, куда делись мои неустановленные изменения? - person raphisama; 07.07.2021

В последней версии git вы можете использовать параметр --patch

git stash push --patch   # since 2.14.6

git stash save --patch   # for older git versions

И git будет запрашивать каждое изменение в ваших файлах, добавлять или нет в тайник.
Вы просто отвечаете y или n

UPD
Псевдоним для DOUBLE STASH:

git config --global alias.stash-staged '!bash -c "git stash --keep-index; git stash push -m "staged" --keep-index; git stash pop stash@{1}"'

Теперь вы можете подготовить свои файлы, а затем запустить git stash-staged.
В результате ваши подготовленные файлы будут сохранены в тайнике.

Если вы не хотите хранить промежуточные файлы и хотите переместить их в тайник. Затем вы можете добавить еще один псевдоним и запустить git move-staged:

git config --global alias.move-staged '!bash -c "git stash-staged;git commit -m "temp"; git stash; git reset --hard HEAD^; git stash pop"'
person Eugen Konkov    schedule 29.06.2017
comment
Технически не отвечает на вопрос - но действительно хорошая техника, позволяющая избирательно спрятать. - person alexreardon; 12.07.2017
comment
Согласитесь, это нормально, но идея здесь с вопросом заключается в том, что я УЖЕ выполнил всю эту работу по постановке изменений, с которыми я хочу что-то сделать (якобы изначально для фиксации, но теперь хочу спрятать), а не просто делать все это снова. - person Steven Lu; 04.06.2018
comment
не работает для вновь созданных файлов (работает только с измененными файлами) - person Derek Liang; 20.09.2018
comment
@DerekLiang: Новые файлы вообще не отслеживаются. Вероятно, вам следует проверить -u|--include-untracked параметр git-stash - person Eugen Konkov; 20.09.2018
comment
Из документации: сохранить: этот параметр устарел в пользу git stash push. Он отличается от 'stash push' тем, что не может принимать пути, а любые аргументы, не являющиеся опциями, формируют сообщение. - person Borjovsky; 10.04.2019
comment
Я использую git версии 2.7.1.windows.2, и в ней нет git stash push, но есть git stash save --patch - person user829755; 12.07.2019
comment
@DerekLiang: Новый файл - это один патч. Вы не можете его разделить. Но вы можете нажать e команду, а затем удалить + строки, которые вы не хотите прятать. - person Eugen Konkov; 22.02.2020
comment
Осторожно: создание и запуск псевдонима 2ns git move-staged без первого испортили мое репо. - person Shankar Thyagarajan; 07.10.2020
comment
ПРЕДУПРЕЖДЕНИЕ. Команда git move-staged сбросила мою последнюю фиксацию, когда у меня был частично поставленный файл. Пришлось восстанавливать с оригинала. - person Shankar Thyagarajan; 07.10.2020

TL; DR Просто добавьте -- $(git diff --staged --name-only) в качестве параметра git <pathspec>

Вот простой однострочник:

git stash -- $(git diff --staged --name-only)

А чтобы просто добавить сообщение:

git stash push -m "My work in progress" -- $(git diff --staged --name-only)

Проверено на v2.17.1 и v2.21.0.windows.1

Ограничения:

  • Имейте в виду, что это будет хранить все, если у вас нет файлов.
  • Кроме того, если у вас есть файл, который является только частично подготовленным (то есть только некоторые измененные строки вставлены, а некоторые другие измененные строки нет), тогда весь файл будет сохранен (включая неустановленные строки).
person Somo S.    schedule 23.01.2020
comment
Я думаю, что это лучший вариант в описанной ситуации: простой для понимания и без черной магии! - person Luis; 30.01.2020
comment
Это довольно аккуратно. В итоге я создал из него псевдоним! - person Kalpesh Panchal; 21.02.2020
comment
@KalpeshPanchal, можешь поделиться своим псевдонимом? Я не уверен, как этого избежать, поэтому он неправильно интерпретирует это. - person Igor Nadj; 02.03.2020
comment
@IgorNadj Конечно! Вот он: github.com/panchalkalpesh/commit- - person Kalpesh Panchal; 04.03.2020
comment
пожалуйста, обратите внимание, что (по крайней мере, на моей машине, 2.27.0.windows.1) это работает, только если вы находитесь в каталоге верхнего уровня своего репозитория. - person marco6; 22.06.2020
comment
Тем, кто часто вносит поэтапные + неустановленные изменения для одного файла, не пропустите этот ответ - кажется, много лучше. - person quetzalcoatl; 23.06.2020
comment
@ marco6, используйте флаг --relative, чтобы исправить это - person Miraclx; 02.11.2020
comment
Это не работает, если удаленный файл находится в постановке. - person Dennis; 28.04.2021
comment
Да, к сожалению, это не работает для удаленных и добавленных файлов. - person kjbartel; 22.06.2021

Я сделал сценарий, который прячет только то, что поставлено в данный момент, и оставляет все остальное. Это здорово, когда я начинаю вносить слишком много несвязанных изменений. Просто подготовьте то, что не связано с желаемой фиксацией, и спрячьте только это.

(Спасибо Бартломею за отправную точку)

#!/bin/bash

#Stash everything temporarily.  Keep staged files, discard everything else after stashing.
git stash --keep-index

#Stash everything that remains (only the staged files should remain)  This is the stash we want to keep, so give it a name.
git stash save "$1"

#Apply the original stash to get us back to where we started.
git stash apply stash@{1}

#Create a temporary patch to reverse the originally staged changes and apply it
git stash show -p | git apply -R

#Delete the temporary stash
git stash drop stash@{1}
person Joe    schedule 22.09.2016
comment
Я бы добавил, что вы можете превратить скрипт в команду git, выполнив thediscoblog.com/blog/2014/03/29/custom-git-commands-in-3-steps - person Petr Bela; 22.11.2016
comment
Отлично! Я настроил его, чтобы запрашивать у пользователя описание тайника, если он не вводит его в командной строке: gist.github.com/brookinc/e2589a8c5ca33f804e4868f6bfc18282 - person brookinc; 09.09.2017
comment
Спасибо, я проголосовал за и превратил его в псевдоним здесь: stackoverflow.com/a/60875067/430128. - person Raman; 26.03.2020
comment
Прохладный! Это сделало свою работу. Другие решения были не тем, что я искал. Спасибо - person Artemious; 19.10.2020

Чтобы сделать то же самое ...

  1. Подготовьте только те файлы, над которыми хотите работать.
  2. git commit -m 'temp'
  3. git add .
  4. git stash
  5. git reset HEAD~1

Бум. Ненужные файлы спрятаны. Все нужные вам файлы готовы для вас.

person Michael    schedule 05.10.2018
comment
Это лучший ответ, и его легче всего запомнить - person Kevin; 21.01.2020
comment
Проголосовали за полезность, но это не отвечает на вопрос - в тайнике попадают неустановленные изменения на шаге № 1, тогда как вопрос задает вопрос о хранении только поэтапных изменений. Вы отвечаете противоположно этому вопросу: stackoverflow.com/q/7650797/430128. Я создал псевдоним, который, по сути, делает это, с некоторыми улучшениями здесь: stackoverflow.com/a/60875082/430128. - person Raman; 23.01.2021
comment
@Raman Просто добавьте еще один git stash, и последний stash будет содержать поэтапные изменения. - person Helv; 23.07.2021

Спрятать только индекс (поэтапные изменения) в Git сложнее, чем должно быть. Я нашел, что ответ @Jo работает хорошо, и превратил его небольшую вариацию в этот псевдоним:

stash-index = "!f() { \
  ! git diff --cached --exit-code --quiet && \
  git stash push --quiet --keep-index -m \"temp for stash-index\" && \
  git stash push \"$@\" && \
  git stash pop --quiet stash@{1} && \
  git stash show -p | git apply -R; }; f"

It:

  1. Проверяет, действительно ли есть поэтапные изменения (git diff --cached --exit-code возвращает ненулевой статус, если они есть). HT: @nandilugio

  2. Он помещает как поэтапные, так и неэтапные изменения во временное хранилище, оставляя только поэтапные изменения.

  3. Затем он помещает поэтапные изменения в тайник, который мы хотим сохранить. Аргументы, переданные псевдониму, такие как --message "whatever", будут добавлены к этой команде stash.

  4. Он открывает временный тайник, чтобы восстановить исходное состояние и удалить временный тайник, а затем

  5. Наконец, удаляет сохраненные изменения из рабочего каталога с помощью приложения обратного исправления.

По поводу противоположной проблемы, связанной с хранением только неустановленных изменений (псевдоним stash-working), см. этот ответ.

person Raman    schedule 26.03.2020
comment
Как бы вы поступили наоборот? Мне нужно спрятать только неустановленные изменения - person scaly; 20.01.2021
comment
@scaly См. ссылку в последнем предложении. - person Raman; 20.01.2021
comment
Отличный ответ! Я немного обновил его, чтобы не делать неправильных вещей, когда ничего не поставлено, добавив ! git diff --cached --exit-code --quiet && \ в качестве первой строки, поэтому в этом случае мы прерываем (ненулевой выход первым в цепочке &&s). Также обратите внимание, что это не работает при установке diff.noprefix = true (git версия 2.29.2), но для меня это не было проблемой, так как у меня также есть псевдонимы для diff, поэтому я только что добавил к ним --no-prefix. - person nandilugio; 28.04.2021

В этом сценарии я предпочитаю создавать новые ветки для каждой проблемы. Я использую префикс temp /, поэтому знаю, что могу удалить эти ветки позже.

git checkout -b temp/bug1

Подготовьте файлы, исправляющие ошибку 1, и зафиксируйте их.

git checkout -b temp/bug2

Затем вы можете выбрать коммиты из соответствующих веток по мере необходимости и отправить запрос на перенос.

person Shamps    schedule 05.06.2018
comment
Хотя неплохо знать о причудливых звуках, на практике это кажется подходом, с которым я вряд ли откажусь. - person ryanjdillon; 19.10.2018
comment
Используйте git cherry-pick tmpCommit, чтобы вернуть временную фиксацию без помощи. слияние-фиксация или git merge tmpCommit + git reset HEAD ^, чтобы получить изменения без фиксации. - person Samuel Åslund; 11.10.2019
comment
Как показывает этот ответ, иногда лучше прямо спросить, чего вы хотите достичь, а не как добиться этого с помощью данной техники. Временные ветки и вишня удобны в сложных ситуациях. - person Guney Ozsan; 09.11.2019
comment
если вы поставили файл частично, вам нужно будет спрятать свои изменения, прежде чем вернуться к исходной ветке и снова вставить их - person jan-glx; 15.05.2020

Почему бы вам не зафиксировать изменение для определенной ошибки и не создать патч на основе этой фиксации и ее предшественника?

# hackhackhack, fix two unrelated bugs
git add -p                   # add hunks of first bug
git commit -m 'fix bug #123' # create commit #1
git add -p                   # add hunks of second bug
git commit -m 'fix bug #321' # create commit #2

Затем, чтобы создать соответствующие патчи, используйте git format-patch:

git format-patch HEAD^^

Это создаст два файла: 0001-fix-bug-123.patch и 0002-fix-bug-321.patch.

Или вы можете создать отдельные ветки для каждой ошибки, чтобы вы могли объединить или переустановить исправления ошибок по отдельности или даже удалить их, если они не сработают.

person knittl    schedule 07.02.2013

git stash --keep-index - хорошее решение ... за исключением того, что оно некорректно работало на удаленных путях, что было исправлено в Git 2.23 (3 квартал 2019 г.)

См. commit b932f6a (16 июля 2019 г.) Thomas Gummerer (tgummerer).
(Объединено Junio ​​C Hamano - gitster - в фиксации f8aee85 >, 25 июл 2019)

stash: исправлена ​​обработка удаленных файлов с помощью --keep-index

git stash push --keep-index должен сохранять все изменения, которые были добавлены в индекс, как в индекс, так и на диск.

В настоящее время это работает некорректно, когда файл удаляется из индекса.
Вместо того, чтобы сохранять его удаленным на диске, ** - keep-index в настоящее время восстанавливает файл. **

Исправьте это поведение, используя 'git checkout' в режиме без наложения, который может точно восстановить индекс и рабочее дерево.
Это также упрощает код.

Обратите внимание, что это приведет к перезаписи неотслеживаемых файлов, если неотслеживаемый файл имеет то же имя, что и файл, который был удален в индексе.

person VonC    schedule 27.07.2019

Обязательно ли работать сразу над несколькими ошибками? И под «сразу» я имею в виду «одновременное редактирование файлов для устранения нескольких ошибок». Потому что, если вам это не нужно, я буду работать только над одной ошибкой за раз в вашей среде. Таким образом, вы можете использовать локальные ветки и перебазирование, что, на мой взгляд, намного проще, чем управлять сложным тайником / этапом.

Допустим, мастер находится в фиксации B. Теперь работаем над ошибкой №1.

git checkout -b bug1

Теперь вы на ветке bug1. Внесите некоторые изменения, зафиксируйте, дождитесь проверки кода. Это локально, поэтому вы никого не трогаете, и сделать патч из git diffs должно быть достаточно просто.

A-B < master
   \
    C < bug1

Теперь вы работаете над ошибкой 2. Вернитесь назад к освоению с git checkout master. Создайте новую ветку git checkout -b bug2. Внесите изменения, зафиксируйте, дождитесь проверки кода.

    D < bug2
   /
A-B < master
   \
    C < bug1

Давайте представим, что кто-то другой совершает E&F на мастере, пока вы ждете проверки.

    D < bug2
   /
A-B-E-F < master
   \
    C < bug1

Когда ваш код будет одобрен, вы можете переустановить его, чтобы стать мастером, выполнив следующие действия:

git checkout bug1
git rebase master
git checkout master
git merge bug1

Это приведет к следующему:

    D < bug2
   /
A-B-E-F-C' < master, bug1

Затем вы можете нажать, удалить локальную ветку bug1 и вперед. По одной ошибке в вашем рабочем пространстве, но с использованием локальных веток ваш репозиторий может обрабатывать несколько ошибок. И это позволяет избежать сложного сценического танца.

Ответьте на вопрос ctote в комментариях:

Что ж, вы можете вернуться к хранению для каждой ошибки и работать только с одной ошибкой за раз. По крайней мере, это избавит вас от проблемы постановки. Но, попробовав это, я лично нахожу это хлопотным. Тайники немного беспорядочные в графе журнала git. И что еще более важно, если вы что-то напортачите, вы не сможете вернуться. Если у вас грязный рабочий каталог и вы открываете тайник, вы не можете «отменить» это всплывающее окно. Гораздо сложнее испортить уже существующие коммиты.

So git rebase -i.

Когда вы переставляете одну ветку в другую, вы можете делать это в интерактивном режиме (флаг -i). Когда вы это сделаете, у вас есть возможность выбрать, что вы хотите делать с каждой фиксацией. Pro Git - отличная книга, которая также доступна в Интернете в формате HTML, и в ней есть хороший раздел о перебазировании и сжатии:

http://git-scm.com/book/ch6-4.html

Для удобства я украду их пример дословно. Представьте, что у вас есть следующая история коммитов, и вы хотите перебазировать и сжать bug1 на master:

    F < bug2
   /
A-B-G-H < master
   \
    C-D-E < bug1

Вот что вы увидите, набрав git rebase -i master bug1

pick f7f3f6d changed my name a bit
pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

Чтобы сжать все коммиты ветки в одну, оставьте первую фиксацию как «pick» и замените все последующие записи «pick» на «squash» или просто «s». У вас также будет возможность изменить сообщение фиксации.

pick f7f3f6d changed my name a bit
s 310154e updated README formatting and added blame
s a5f4a0d added cat-file
#
# Commands:
#  p, pick = use commit
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit

Так что да, раздавливание - это немного неудобно, но я все же рекомендую его, а не интенсивное использование тайников.

person Mike Monkiewicz    schedule 07.02.2013
comment
Спасибо за подробный пост! Это наверняка решает многие мои проблемы - единственная проблема, которую я вижу, заключается в том, что наша текущая команда попросила, чтобы все доставки были в одной фиксации. :( - person MrDuk; 08.02.2013
comment
Если им не нужна или не нужна ваша рабочая история в производственном репозитории, это нормально: сделайте свою главную историю отслеживания без истории, применяя различия, а не объединяя ветки. Вы можете решить, как сохранить ветку с декорированным мастером, которая имеет фактическую объединенную историю, и выполнять свою реальную работу с ее помощью, таким образом будет легко автоматизировать создание правильных различий. - person jthill; 08.02.2013
comment
Обратите внимание, что git checkout master; git checkout -b bug2 можно сократить до git checkout -b bug2 master. То же самое относится к git checkout bug1; git rebase master; git checkout master; git merge bug1, который идентичен git rebase master bug1; git push . bug1:master (конечно, уловка push неочевидна) - person knittl; 08.02.2013
comment
Спасибо за чаевые, knittl - person Mike Monkiewicz; 08.02.2013
comment
ctote: Что вы имеете в виду под единственной фиксацией? bug1 должна быть доставлена ​​за один коммит? Или они хотят получить bug1, bug2 и bug3 за один коммит? В любом случае, это, вероятно, просто вопрос перебазирования (и, возможно, сжатия с помощью rebase -i). Если вы приведете подробный пример вашей проблемы, я снова могу дать развернутый ответ. - person Mike Monkiewicz; 08.02.2013
comment
Извините, я должен был быть более ясным. Да, поэтому они хотят сохранить нашу историю кода в чистоте, имея только одну фиксацию на ошибку. Таким образом, как только архитектор начнет просматривать мой код, он сможет просмотреть единую консолидированную фиксацию. Итак, я предположил, что если я хочу перейти к ошибке 1, а затем начать работу над ошибкой 2, мне придется зафиксировать b1 перед переходом на b2. Я все время слышу ужасные истории о том, поверь мне, ты не хочешь раздавить коммиты - это так мерзко, что я не пробовал; подумаешь? - person MrDuk; 08.02.2013
comment
Я дал пошаговое руководство по хранению выше в основном ответе, чтобы я мог использовать необычное форматирование - person Mike Monkiewicz; 08.02.2013
comment
Спасибо за все детали! Текущий процесс, принятый большинством людей (из-за ограничения разрешенных коммитов), заключается в том, чтобы дважды клонировать один и тот же поток, один раз для разработки, а другой - для тестирования доставки / сборки. По сути, они будут #hackhack для разработчиков, создать файлы исправлений и применить их к базовой линии для тестирования сборки, вернуть все свои файлы исправлений и применить каждый исправление индивидуально для доставки. [продолжение ...] - person MrDuk; 08.02.2013
comment
[...] Вы видите преимущество одного перед другим? Основное преимущество, о котором я утверждаю, состоит в том, что проще выполнять тесты сборки для нескольких ошибок, применяя несколько файлов исправлений к их базовому потоку, вместо того, чтобы пытаться логически разделять все их ошибки в git. - person MrDuk; 08.02.2013
comment
Ага, я понимаю их точку зрения. Легче применить зашитые изменения к основной ветке для тестирования. Но гораздо проще испортить ваши изменения, вытаскивая их из тайника и обратно. Вам просто нужно будет найти рабочий процесс, который подойдет вам. - person Mike Monkiewicz; 09.02.2013
comment
Если вы используете локальные ветки и фиксируете ошибки, вы можете проверить: stackoverflow.com/questions/7516632/. Это позволит вам применить ветку к мастеру без потери указателя ветки. Если вы решите использовать тайники, могу ли я порекомендовать работать только над одной ошибкой за раз, спрятать ее, а затем вы можете использовать git stash apply, когда хотите протестировать сразу несколько (но сохраняя их отдельные патчи в тайнике). - person Mike Monkiewicz; 09.02.2013
comment
Я проголосовал против, потому что это не отвечает на исходный вопрос. Я нахожусь в ветке, над чем-то работаю, и я только что внес изменение, которое, как мне кажется, должно быть внесено в ветку интеграции отдельно. Все, что я хочу сделать, это подготовить это изменение и спрятать его, чтобы я мог переключиться на другую ветку и зафиксировать отдельно, вместо моей текущей ветки незавершенной работы. (Предупреждение, мерзавец впереди разглагольствует.) Абсурдно, что это так сложно сделать; Я должен представить, что это обычное явление. (Работаем в одной ветке и замечаем быстрое изменение, которое нужно внести, и забываем сначала переключиться.) - person jpmc26; 17.01.2015
comment
Возможно, помог OP, но не ответил на вопрос для дальнейшего использования. Я действительно хочу, чтобы люди, которые ответили, не считали, что знают все варианты использования и отстаивают свое мнение. Если вы собираетесь высказывать только свое мнение, по крайней мере, сначала ответьте на исходный вопрос ОП. - person MikeSchinkel; 20.01.2016
comment
Здесь нет ничего неправильного, и это ценная перспектива, но она также довольно объективно не отвечает на вопрос вообще, поэтому проголосовала против. - person danShumway; 15.03.2016
comment
в некоторых случаях (в очень крошечных проектах или проектах, которые еще не переданы другим) удобнее работать с одной веткой и добавлять чистые коммиты для шагов, которые вы сделали imho. Но ваш ответ, скорее всего, лучший вариант для других случаев. В моем текущем случае мне просто нужно было исправить крошечную проблему, я не осмелился бы создать ветку всего для одного двухстрочного коммита, так как он сам по себе может оставаться чистым и аккуратным. - person wmax; 09.08.2019

Другой подход к этому - создать временную фиксацию с файлами, которые вы не хотите хранить, затем спрятать оставшиеся файлы и аккуратно удалить последнюю фиксацию, сохраняя файлы нетронутыми:

git add *files that you don't want to be stashed*
git commit -m "temp"
git stash --include-untracked
git reset --soft HEAD~1

Таким образом, вы касаетесь только тех файлов, к которым хотите прикоснуться.

Обратите внимание: --include-untracked используется здесь также для хранения новых файлов (что, вероятно, именно то, что вам действительно нужно).

person Genjutsu    schedule 29.11.2020

Из ваших комментариев к ответу Майка Монкевича я предлагаю использовать более простую модель: используйте обычные ветки разработки, но используйте сквош-вариант слияния, чтобы получить одну фиксацию в вашей основной ветке:

git checkout -b bug1    # create the development branch
* hack hack hack *      # do some work
git commit
* hack hack hack *
git commit
* hack hack hack *
git commit
* hack hack hack *
git commit
git checkout master     # go back to the master branch
git merge --squash bug1 # merge the work back
git commit              # commit the merge (don't forget
                        #    to change the default commit message)
git branch -D bug1      # remove the development branch

Преимущество этой процедуры в том, что вы можете использовать обычный рабочий процесс git.

person Rudi    schedule 26.08.2015
comment
Я не понимаю, как этот ответ может помочь. Это не связано с исходным вопросом. - person frapen; 25.01.2017

Чтобы отсечь случайное изменение, особенно удаление нескольких файлов, сделайте следующее:

git add <stuff to keep> && git stash --keep-index && git stash drop

Другими словами, спрячьте хлам и выбросьте его вместе с тайником.

Проверено в git версии 2.17.1

person wmax    schedule 09.08.2019
comment
голос против без комментария бесполезен ни мне, ни следующему читателю ... zaenks grumpy anon. Хотя я могу представить себе одну проблему с этим однострочником: нужно быть очень осторожным, чтобы не забыть добавить все необходимые изменения в индекс, иначе эти важные изменения также будут удалены. Но опять же, неосторожное использование любого инструмента cli может быть очень опасным для вашего драгоценного времени и работы в худшем случае. - person wmax; 23.08.2019

Я не видел этого решения, которое не требует использования git stash:

Вам даже не нужно использовать git stash. Вы можете решить это с помощью специальной ветки , как описано здесь. (ветки дешевые).

В самом деле, вы можете изолировать по отдельности не- и поэтапные изменения с помощью нескольких последовательных команд, которые можно связать вместе в псевдоним git:

Создайте новую ветку и переключитесь на нее, в которой вы будете фиксировать отдельно поэтапные и неустановленные изменения: см. Здесь

В любой момент вы можете git cherry-pick -e одну фиксацию из созданной ветки, чтобы применить ее там, где вы хотите (-e, чтобы изменить ее сообщение фиксации).

Когда он вам больше не нужен, вы можете удалить эту ветку тайника. Возможно, вам придется использовать параметр -D для принудительного удаления (вместо обычного параметра -d), потому что указанная ветвь не объединяется, и git может подумать, что вы рискуете потерять данные, если удалите ее. Это верно, если у вас нет выбранных коммитов, которые были на нем до удаления:

git branch -D separated-stashes

Вы также можете добавить псевдоним к своему ~/.gitconfig, чтобы автоматизировать это поведение:

git config --global alias.bratisla '!git switch -c separated-stashes; git commit -m "staged changes"; git add -u; git commit -m "unstaged changes"; git switch -' # why this name ? : youtu.be/LpE1bJp8-4w

перед хранением
после сохранения



Конечно, вы также можете добиться того же результата, используя два последовательных тайника

Как указано в других ответах, у вас есть несколько способов спрятать только неустановленные или только поэтапные изменения, используя git stash (-k|--keep-index) в сочетании с другими командами.

Я лично считаю, что параметр -k очень сбивает с толку, поскольку он хранит все, но сохраняет поэтапные изменения в поэтапном состоянии (это объясняет, почему --keep-index). В то время как прятание чего-либо обычно перемещает его в тайник. С -k неустановленные изменения хранятся в обычном режиме, а поэтапные просто копируются в ту же запись тайника.


Шаг 0: у вас есть две вещи в вашем статусе git: файл, содержащий поэтапные изменения, и другой файл, содержащий неустановленные изменения.

Шаг 1: спрятать неустановленные + поэтапные изменения, но сохранить поэтапные в индексе:

git stash -k -m "all changes"

Часть -m "..." является необязательной, git stash -k на самом деле является псевдонимом для git stash push -k (который ничего не передает удаленно, кстати, не беспокойтесь), который принимает параметр -m для обозначения ваших записей для ясности (например, сообщение фиксации или тег, но для тайника Вход). Это более новая версия устаревшего git stash save.


Шаг 1bis (необязательно):

git stash

Спрятанные поэтапные изменения (которые все еще находятся в индексе). Этот шаг не является обязательным для следующего, но показывает, что вы можете вносить только поэтапные изменения в запись тайника, если хотите. Если вы используете эту строку, вам нужно git stash (pop|apply) && git add -u, прежде чем продолжить шаг 2.


Шаг 2 :

git commit -m "staged changes"

Делает коммит, содержащий только поэтапные изменения с шага 0, он содержит то же самое, что и запись в тайнике с шага 1bis.


Шаг 3 :

git stash (pop|apply)

Восстанавливает тайник с шага 1. Обратите внимание, что эта запись тайника содержала все, но, поскольку вы уже зафиксировали поэтапные изменения, этот тайник будет добавлять только неустановленные изменения с шага 0.

nb: restore здесь НЕ означает git restore, это другая команда.


Шаг 4:

git add -u

Добавляет содержимое всплывающего тайника в индекс


Шаг 5:

git commit -m "unstaged changes"

Неустановленный здесь, как указано в комментариях к шагам 2 и 3, относится к шагу 0. Фактически вы проводите и фиксируете поэтапные изменения с шага 0.


Сделанный ! Теперь у вас есть две отдельные фиксации, содержащие (не) поэтапные изменения с шага 0. Возможно, вы захотите исправить / перебазировать их либо для дополнительных изменений, либо переименовать / отбросить / раздавить их. В зависимости от того, что вы сделали со стеком своего тайника (pop или apply), вы также можете git stash (drop|clear) это сделать. Вы можете видеть свои записи в тайнике с git stash (list|show)

person dilavasso    schedule 18.10.2020

TL; DR; git stash-staged

После создания псевдонима:

git config --global alias.stash-staged '!bash -c "git stash -- \$(git diff --staged --name-only)"'

Здесь git diff возвращает список --staged файлов --name-only
И затем мы передаем этот список как pathspec в git stash запятую.

От man git stash:

git stash [--] [<pathspec>...]

<pathspec>...
   The new stash entry records the modified states only for the files
   that match the pathspec. The index entries and working tree
   files are then rolled back to the state in HEAD only for these
   files, too, leaving files that do not match the pathspec intact.

person Eugen Konkov    schedule 30.05.2020
comment
Работает ли это правильно, если для какого-то конкретного файла у меня есть как поэтапные, так и неустановленные изменения? На первый взгляд --name-only не похоже, что он справляется с этим делом. этот ответ кажется намного лучше. - person quetzalcoatl; 23.06.2020
comment
Кроме того, это в основном копия этого ответа - person quetzalcoatl; 23.06.2020
comment
@quetzalcoatl: Да, это похоже на тот ответ. Но этот предоставляет псевдоним, который сохраняет ваш ввод для следующих команд - person Eugen Konkov; 23.06.2020
comment
@quetzalcoatl: Вы правы. --name-only не будет обрабатывать поэтапные / неустановленные изменения сразу. Но почему вы сначала маркируете, а потом прячете? Желательно прямо сейчас припрятать необходимые изменения. Я рекомендую вам попробовать git stash push --patch описанное здесь - person Eugen Konkov; 23.06.2020