Спрятать только один файл из нескольких файлов, которые изменились с Git?

Как я могу занести только один из нескольких измененных файлов в моей ветке?

Ответ 1

Обновление: следующий ответ предназначен для git до git 2.13. Для git 2.13 и выше, посмотрите другой ответ ниже.


Предупреждение

Как отмечено в комментариях, это помещает все в stash, как поэтапный, так и не постановочный. --Keep-index просто оставляет индекс в покое после того, как stash сделан. Это может привести к конфликтам слияния при последующем открытии stashа.


Это сохранит все, что вы еще не добавили. Просто git add вещи, которые вы хотите сохранить, затем запустите.

git stash --keep-index

Например, если вы хотите разделить старый коммит на несколько наборов изменений, вы можете использовать следующую процедуру:

  1. git rebase -i <last good commit>
  2. Отметьте некоторые изменения как edit.
  3. git reset HEAD^
  4. git add <files you want to keep in this change>
  5. git stash --keep-index
  6. Исправьте вещи по мере необходимости. Не забудьте git add вносить изменения.
  7. git commit
  8. git stash pop
  9. При необходимости повторите С# 5.
  10. git rebase --continue

Ответ 2

Вы также можете использовать git stash save -p "my commit message". Таким образом, вы можете выбрать, какие блоки должны быть добавлены в тайник, а также целые файлы.

Вам будет предложено несколько действий для каждого блока:

   y - stash this hunk
   n - do not stash this hunk
   q - quit; do not stash this hunk or any of the remaining ones
   a - stash this hunk and all later hunks in the file
   d - do not stash this hunk or any of the later hunks in the file
   g - select a hunk to go to
   / - search for a hunk matching the given regex
   j - leave this hunk undecided, see next undecided hunk
   J - leave this hunk undecided, see next hunk
   k - leave this hunk undecided, see previous undecided hunk
   K - leave this hunk undecided, see previous hunk
   s - split the current hunk into smaller hunks
   e - manually edit the current hunk
   ? - print help

Ответ 3

Поскольку git по сути своей относится к управлению всем содержимым и индексом репозитория (а не одним или несколькими файлами), git stash, что неудивительно, со всем рабочим каталогом ,

Фактически, начиная с Git 2.13 (Q2 2017), вы можете хранить отдельные файлы с помощью git stash push:

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

Когда для pathspec задано ' git stash push ', новый stash записывает измененные состояния только для файлов, которые соответствуют pathspec

См. " Сохранение изменений в определенных файлах " для получения дополнительной информации.

Контрольный пример не требует пояснений:

test_expect_success 'stash with multiple pathspec arguments' '
    >foo &&
    >bar &&
    >extra &&
    git add foo bar extra &&

    git stash push -- foo bar &&   

    test_path_is_missing bar &&
    test_path_is_missing foo &&
    test_path_is_file extra &&

    git stash pop &&
    test_path_is_file foo &&
    test_path_is_file bar &&
    test_path_is_file extra

Оригинальный ответ (ниже, июнь 2010 г.) был о ручном выборе того, что вы хотите спрятать.

Casebash комментарии:

Это (оригинальное решение stash --patch) хорошо, но часто я модифицировал много файлов, поэтому использование патча раздражает

ответ Букзора (поднял, ноябрь 2011) предлагает более практичное решение, основанное на
git add + git stash --keep-index.
Иди посмотри и провозгласи его ответ, который должен быть официальным (вместо моего).

Об этой опции chhh указывает альтернативный рабочий процесс в комментариях:

после такого git reset --soft вы должны сделать " git reset --soft ", чтобы получить чистую постановку:
Чтобы перейти к исходному состоянию - которое является чистой промежуточной областью и только с некоторыми выбранными нематериальными модификациями, можно мягко сбросить индекс, чтобы получить (не совершая ничего, как вы - букзор - сделал).


(Оригинальный ответ, июнь 2010 г.: тайник)

Тем не менее, git stash save --patch может позволить вам получить частичное копирование, после которого вы:

С помощью --patch вы можете интерактивно выбирать --patch между HEAD и рабочим деревом, которое нужно спрятать.
Запись stash составлена таким образом, что ее индексное состояние совпадает с индексным состоянием вашего репозитория, а его рабочее дерево содержит только изменения, выбранные вами в интерактивном режиме. Выбранные изменения затем откатываются с вашего рабочего дерева.

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

git stash --patch --no-keep-index

может быть лучше.


Если --patch не работает, ручной процесс может:

Для одного или нескольких файлов промежуточным решением будет:

  • скопировать их за пределы Git репо
    (На самом деле, eleotlecram предлагает интересную альтернативу)
  • git stash
  • скопировать их обратно
  • git stash # на этот раз спрятаны только те файлы, которые вы хотите
  • git stash pop [email protected]{1} # повторно применить все ваши модификации файлов
  • git checkout -- afile # сбросить файл до содержимого HEAD перед любыми локальными изменениями

В конце этого довольно громоздкого процесса у вас будет спрятан только один или несколько файлов.

Ответ 4

Если git stash -p (или git add -p с stash --keep-index) было бы слишком громоздким, мне было проще использовать diff, checkout и apply:

Чтобы "зашить" конкретный файл/только dir:

git diff path/to/dir > stashed.diff
git checkout path/to/dir

Затем после

git apply stashed.diff

Ответ 5

Используйте git stash push, например:

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

Например:

git stash push -- my/file.sh

Это доступно с Git 2.13, выпущенным в spring 2017.

Ответ 6

Скажем, у вас есть 3 файла

a.rb
b.rb
c.rb

и вы хотите сохранить только b.rb и c.rb, но не a.rb

вы можете сделать что-то вроде этого

# commit the files temporarily you don't want to stash
git add a.rb
git commit -m "temp" 

# then stash the other files
git stash save "stash message"

# then undo the previous temp commit
git reset --soft HEAD^
git reset

И все готово! НТН.

Ответ 7

Другой способ сделать это:

# Save everything
git stash 

# Re-apply everything, but keep the stash
git stash apply

git checkout <"files you don't want in your stash">

# Save only the things you wanted saved
git stash

# Re-apply the original state and drop it from your stash
git stash apply [email protected]{1}
git stash drop [email protected]{1}

git checkout <"files you put in your stash">

Я придумал это после того, как я (еще раз) пришел на эту страницу и мне не понравились первые два ответа (первый ответ просто не отвечает на вопрос, и мне не очень нравилось работать с -p интерактивный режим).

Идея такая же, как и то, что @VonC предложила использовать файлы вне репозитория, вы сохраняете необходимые изменения где-то, удаляете изменения, которые не хотите в своем кошельке, а затем повторно применяете изменения, которые вы переместили из путь. Тем не менее, я использовал git stash как "где-то" (и, как результат, один дополнительный шаг в конце: удаление cahnges, которые вы помещаете в stash, потому что вы также отбросили их).

Ответ 8

Обновление (2/14/2015). Я немного перезаписал script, чтобы лучше справляться с ситуациями конфликтов, которые теперь должны быть представлены как конфликты без взаимодействия, а не с файлами .rej.


Мне часто кажется более интуитивным делать обратный подход @bukzor. То есть, чтобы внести некоторые изменения, а затем занести только эти поэтапные изменения.

К сожалению, git не предлагает git stash --only-index или аналогичный, поэтому я взломал script, чтобы сделать это.

#!/bin/sh

# first, go to the root of the git repo
cd `git rev-parse --show-toplevel`

# create a commit with only the stuff in staging
INDEXTREE=`git write-tree`
INDEXCOMMIT=`echo "" | git commit-tree $INDEXTREE -p HEAD`

# create a child commit with the changes in the working tree
git add -A
WORKINGTREE=`git write-tree`
WORKINGCOMMIT=`echo "" | git commit-tree $WORKINGTREE -p $INDEXCOMMIT`

# get back to a clean state with no changes, staged or otherwise
git reset -q --hard

# Cherry-pick the index changes back to the index, and stash.
# This cherry-pick is guaranteed to succeed
git cherry-pick -n $INDEXCOMMIT
git stash

# Now cherry-pick the working tree changes. This cherry-pick may fail
# due to conflicts
git cherry-pick -n $WORKINGCOMMIT

CONFLICTS=`git ls-files -u`
if test -z "$CONFLICTS"; then
    # If there are no conflicts, it safe to reset, so that
    # any previously unstaged changes remain unstaged
    #
    # However, if there are conflicts, then we don't want to reset the files
    # and lose the merge/conflict info.
    git reset -q
fi

Вы можете сохранить приведенный выше script как git-stash-index где-то на своем пути и затем вызывать его как git stash-index

# <hack hack hack>
git add <files that you want to stash>
git stash-index

Теперь в stash содержится новая запись, в которой содержатся только те изменения, которые вы поставили, а ваше рабочее дерево все еще содержит любые неустановленные изменения.

В некоторых случаях изменения рабочего дерева могут зависеть от изменений индекса, поэтому, когда вы меняете изменения индекса, изменения рабочего дерева имеют конфликт. В этом случае вы получите обычные конфликты без конфликтов, которые вы можете разрешить с помощью git merge/git mergetool/etc.

Ответ 9

Поскольку создание ветвей в Git тривиально, вы можете просто создать временную ветвь и проверить в ней отдельные файлы.

Ответ 10

На тот случай, если вы на самом деле имеете в виду отмену изменений всякий раз, когда вы используете git stash (и на самом деле не используете git stash для его временного хранения), в этом случае вы можете использовать

git checkout -- <file>

[ ПРИМЕЧАНИЕ ]

Этот git stash - просто более быстрая и простая альтернатива ветвлению и тому подобному.

Ответ 11

Сохраните следующий код в файле, например, с именем stash. Использование stash <filename_regex>. Аргумент - это регулярное выражение для полного пути файла. Например, чтобы запереть a/b/c.txt, stash a/b/c.txt или stash .*/c.txt и т.д.

$ chmod +x stash
$ stash .*.xml
$ stash xyz.xml

Код для копирования в файл:

#! /usr/bin/expect --
log_user 0
set filename_regexp [lindex $argv 0]

spawn git stash -p

for {} 1 {} {
  expect {
    -re "diff --git a/($filename_regexp) " {
      set filename $expect_out(1,string)
    }
    "diff --git a/" {
      set filename ""
    }
    "Stash this hunk " {
      if {$filename == ""} {
        send "n\n"
      } else {
        send "a\n"
        send_user "$filename\n"
      }
    }
    "Stash deletion " {
      send "n\n"
    }
    eof {
      exit
    }
  }
}

Ответ 12

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

$ git stash -- filename.ext

Если это неотслеживаемый/новый файл, вам придется сначала его разместить.

Этот метод работает в git версии 2. 13+

Ответ 13

Проблема с "промежуточным" решением VonC по копированию файлов вне репозитория Git заключается в том, что вы теряете информацию о пути, что делает копирование кучи файлов позже более сложным.

Найдите легче использовать tar (аналогичные инструменты, вероятно, сделают) вместо копии:

  • tar cvf/tmp/stash.tar path/to/some/путь к файлу/в/some/other/file (... и т.д.)
  • git checkout path/to/some/путь к файлу/в/some/other/file
  • git stash
  • tar xvf/tmp/stash.tar
  • и т.д.. (см. предложение VonC "промежуточное" )

Ответ 14

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

git stash
git checkout master
git stash pop
git add <files that you want to commit>
git commit -m 'Minor feature'
git stash
git checkout topic1
git stash pop
...<resume work>...

Обратите внимание, что первые stash и stash pop могут быть устранены, вы можете переносить все свои изменения на ветвь master при проверке, но только в случае отсутствия конфликтов. Также, если вы создаете новую ветку для частичных изменений, вам понадобится тайник.

Вы можете упростить его при отсутствии конфликтов и новой ветки:

git checkout master
git add <files that you want to commit>
git commit -m 'Minor feature'
git checkout topic1
...<resume work>...

Штамм даже не нужен...

Ответ 15

Это можно сделать легко в 3 этапа с помощью SourceTree.

  • Временно зафиксировать все, что вы не хотите спрятать.
  • Git добавить все остальное, а затем сохранить его.
  • Введите временную фиксацию, запустив git reset, нацелив фиксацию до вашего временного.

Все это можно сделать в течение нескольких секунд в SourceTree, где вы можете просто щелкнуть по файлам (или даже отдельным строкам), которые вы хотите добавить. После добавления просто привяжите их к временному фиксации. Затем установите флажок, чтобы добавить все изменения, а затем нажмите кнопку "Скрыть", чтобы сохранить все. С укороченными изменениями взгляните на свой список фиксаций и отметьте хеш для фиксации перед вашей временной фиксацией, затем запустите "git reset hash_b4_temp_commit", что в основном напоминает "выскакивание" фиксации путем сброса ваша ветка к фиксации прямо перед ней. Теперь у вас осталось только то, что вы не хотели спрятать.

Ответ 16

Я бы использовал git stash save --patch. Я не считаю интерактивность раздражающей, потому что во время нее есть варианты, чтобы применить желаемую операцию к целым файлам.

Ответ 17

Каждый ответ здесь настолько сложный...

Как насчет этого: "stash":

git diff /dir/to/file/file_to_stash > /tmp/stash.patch
git checkout -- /dir/to/file/file_to_stash

Чтобы вернуть файл обратно:

git apply /tmp/stash.patch

Точное совпадение с тем, как скопировать один файл и снова вставить его.

Ответ 18

Вы можете просто сделать это:

git stash push "filename"

или с дополнительным сообщением

git stash push -m "Some message" "filename"

Ответ 19

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

  • git stash -p (--patch): выберите hunks вручную, исключая невоспроизводимые файлы
  • git stash -k (--keep-index): запишите все отслеживаемые/невоспроизводимые файлы и сохраните их в рабочем каталоге
  • git stash -u (--include-untracked): сохранить все отслеживаемые/невоспроизводимые файлы
  • git stash -p (--patch) -u (--include-untracked): неверная команда

В настоящее время наиболее разумным методом, позволяющим записывать любые файлы с отслеживанием/без следа, является:

  • Временно зафиксируйте файлы, которые вы не хотите сохранять
  • Добавить и сохранить
  • Поместить временную фиксацию

Я написал простую script для этой процедуры в ответе на другой вопрос, и есть шаги для выполнения процедуры в SourceTree здесь.

Ответ 20

Решение

Локальные изменения:

  • file_A (модифицированный) не поставлен
  • file_B (модифицированный) не поставлен
  • file_C (модифицированный) не организован

Чтобы создать тайник "my_stash" только с изменениями в file_C:

1. git add file_C
2. git stash save --keep-index temp_stash
3. git stash save my_stash
4. git stash pop [email protected]#{1}

Готово.


объяснение

  1. добавить file_C в область подготовки
  2. создайте временный тайник с именем "temp_stash" и сохраните изменения в file_C
  3. создать требуемый тайник ("my_stash") только с изменениями в file_C
  4. примените изменения в "temp_stash" (file_A и file_B) к своему локальному коду и удалите тайник

Вы можете использовать git status между шагами, чтобы увидеть, что происходит.

Ответ 21

В этой ситуации я git add -p (интерактивный), git commit -m blah, а затем спрятать оставшееся при необходимости.

Ответ 22

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

Попробуйте добавить файлы, используя "git add filepath".

Далее выполните эту строку

git stash --keep-index

Ответ 23

git add .                           //stage all the files
git reset <pathToFileWillBeStashed> //unstage file which will be stashed
git stash                           //stash the file(s)
git reset .                         // unstage all staged files
git stash pop                       // unstash file(s)

Ответ 24

Чтобы сохранить один файл, используйте git stash --patch [file].

Это будет подсказывать: Stash this hunk [y,n,q,a,d,j,J,g,/,e,?]?? Stash this hunk [y,n,q,a,d,j,J,g,/,e,?]?? , Просто введите (копить этот ломоть и все последующие ломти в файле) и все в порядке. a

Ответ 25

Аналогичная ситуация. Сделал фиксацию и понял, что это не нормально.

git commit -a -m "message"
git log -p

Основываясь на ответах, это помогло мне.

# revert to previous state, keeping the files changed
git reset HEAD~
#make sure it ok
git diff
git status
#revert the file we don't want to be within the commit
git checkout specs/nagios/nagios.spec
#make sure it ok
git status
git diff
#now go ahead with commit
git commit -a -m "same|new message"
#eventually push tu remote
git push

Ответ 26

Я не знаю, как это сделать в командной строке, используя только SourceTree. Допустим, вы изменили файл A и имеете два смены в файле B. Если вы хотите сохранить только второй кусок в файле B и оставить все остальное нетронутым, сделайте следующее:

  • Сценическое все
  • Выполните изменения в вашей рабочей копии, которые отменят все изменения в файле A. (например, запустите инструмент внешнего разграничения и создайте файлы.)
  • Сделать файл B выглядеть так, как будто к нему применяется только второе изменение. (например, запустить внешний инструмент сравнения и отменить первое изменение.)
  • Создайте кошелек, используя "Keep staged changes".
  • Не все вещи
  • Готово!

Ответ 27

Одним сложным способом было бы сначала передать все:

git add -u
git commit // creates commit with sha-1 A

Reset вернитесь к исходной фиксации, но проверьте файл the_one_file из нового коммита:

git reset --hard HEAD^
git checkout A path/to/the_one_file

Теперь вы можете зашить the_one_file:

git stash

Очистка путем сохранения фиксированного содержимого в вашей файловой системе при возврате к исходному фиксации:

git reset --hard A
git reset --soft HEAD^

Да, несколько неудобно...

Ответ 28

Я не нашел ответа на то, что мне было нужно, и это так же просто:

git add -A
git reset HEAD fileThatYouWantToStash
git commit -m "committing all but one file"
git stash

Это фиксирует ровно один файл.

Ответ 29

Быстрый ответ


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

git checkout <branch-name> -- <file-path>

Вот фактический пример:

git checkout master -- battery_monitoring/msg_passing.py