Мерзавец и применить
Я новичок в Git и не совсем понятно, как работает копирование.
Допустим, я работаю на ветке мастера и попробую git pull
и получаю ошибку о том, что мои локальные изменения будут перезаписаны и их необходимо будет спрятать или зафиксировать. Если я не поставил свои изменения и не запустил git stash
затем сделайте git pull
и и обновить успешно, что происходит, когда я git stash apply
?
В общем, если кто-то еще изменяет файлы и я запускаю git pull
что происходит, когда я run git stash apply
? перезаписывает ли файлы, которые были только что обновлены, независимо от того, были ли они созданы, когда я их спрятал? Перезаписывает ли каждый файл, который я только что обновил git pull
, с файлами, которые были спрятаны?
3 ответа
Быстрая версия на вынос "TL;DR", так что можно вернуться позже и изучить больше
git stash
вешает шкатулку - это своеобразная форма коммита слияния, которого нет ни в одной ветви - на текущем HEAD
совершить. Позже git stash apply
Когда вы выполняете какой-либо коммит - возможно, другой коммит - затем пытаетесь восстановить изменения, которые выполняет git-вычисления, просматривая как свисающую шкатулку, так и коммит, с которого она зависает.
Когда вы закончите с изменениями, вы должны использовать git stash drop
чтобы освободить шкатулку от коммита, на котором она была "спрятана". (А также, git stash pop
это просто сокращение для "применить, затем автоматически отбросить". Тем не менее, я рекомендую оставить эти два шага раздельными, если вам не нравится результат "применить" и вы хотите повторить попытку позже.)
Длинная версия
git stash
на самом деле довольно сложный.
Говорят, что "git имеет гораздо больше смысла, когда вы понимаете X", для многих различных значений "X", что обобщает на "git имеет гораздо больше смысла, когда вы понимаете git".:-)
В этом случае, чтобы действительно понять stash
, вам нужно понять, как работают коммиты, ветки, область index/staging, пространство имен ссылок git и объединяет, потому что git stash
создает очень специфический коммит слияния, на который ссылается имя вне обычных пространств имен - странный вид слияния, который вообще не "на ветке" - и git stash apply
использует механизм слияния git, чтобы попытаться "повторно применить" изменения, сохраненные, когда была сделана особая фиксация слияния, при необходимости сохраняя различие между поэтапными и неустановленными изменениями.
К счастью, вам не нужно понимать все это, чтобы использовать git stash
,
Здесь вы работаете над какой-то веткой (master
) и у вас есть некоторые изменения, которые еще не готовы, поэтому вы не хотите фиксировать их в ветке. 1 Тем временем кто-то положил что-то хорошее - или, по крайней мере, вы надеетесь, что это хорошо - origin/master
на удаленном репо, так что вы хотите забрать их.
Допустим, вы и они оба начали с коммитов, которые заканчиваются в - A - B - C
т.е. C
последний коммит, который у вас был в репо, когда вы начали работать над веткой master
, Новое "что-то хорошее" фиксирует, мы позвоним D
а также E
,
В твоем случае ты бежишь git pull
и это терпит неудачу с проблемой "рабочий каталог не чист". Итак, вы бежите git stash
, Это фиксирует ваши вещи за вас, в особой, странной манере, так что ваш рабочий каталог теперь чистый. Теперь вы можете git pull
,
С точки зрения рисования коммитов (график, как вы получаете с gitk
или же git log --graph
), теперь у вас есть что-то вроде этого. Тайник - это маленькая сумка i-w
свисать с коммита вы были "на", в вашем master
ветка, когда ты побежал git stash
, (Причина имен i
а также w
является то, что это - "i"ndex / staging-area и "w" части тайника.)
- A - B - C - D - E <-- HEAD=master, origin/master
|\
i-w <-- the "stash"
Этот рисунок - то, что вы получите, если начали работать над master
и никогда не делал никаких коммитов. Таким образом, ваш последний коммит был C
, После изготовления тайника git pull
смог добавить коммиты D
а также E
в ваше местное отделение master
, Спрятанный мешок с работами все еще висит C
,
Если вы сделали несколько своих коммитов - мы им позвоним Y
, за ваш коммит и Z
просто для двух коммитов - результат "stash затем pull" выглядит так:
.-------- origin/master
- A - B - C - D - E - M <-- HEAD=master
\ /
Y - Z
|\
i-w <-- the "stash"
На этот раз после stash
повесил сумку Z
, pull
- что просто fetch
затем merge
- пришлось сделать реальное слияние, а не просто "перемотка вперед". Так что это делает коммит M
Слияние совершают. origin/master
ярлык по-прежнему относится к коммиту E
не M
, Ты сейчас на master
при совершении M
, который является объединением E
а также Z
, Ты "на шаг впереди" origin/master
,
В любом случае, если вы сейчас запускаете git stash apply
Сценарий stash (это сценарий оболочки, который использует множество низкоуровневых команд git "plumbing") эффективно 2 делает это:
git diff stash^ stash > /tmp/patch
git apply /tmp/patch
Это различия stash
какие имена w
- часть "рабочего дерева" тайника - против правильного 3 родителя. Другими словами, он узнает "что вы изменили" между правильным родительским коммитом (C
или же Z
в зависимости от обстоятельств) и спрятанное рабочее дерево. Затем он применяет изменения к проверенной версии, которая либо E
или же M
опять же в зависимости от того, с чего вы начали.
Между прочим, git stash show -p
на самом деле просто работает то же самое git diff
команда (без > /tmp/patch
часть конечно). Без -p
, он запускает различие с --stat
, Так что если вы хотите увидеть подробно, что git stash apply
слиться, использовать git stash show -p
, (Это не покажет вам, что git stash apply
может попытаться применить из индексной части тайника; это небольшая ошибка, которую я имею со сценарием тайника.)
В любом случае, после того, как тайник применяется чисто, вы можете использовать git stash drop
удалить ссылку на шкатулку, чтобы ее можно было собрать мусором. Пока не уронишь, у него есть имя (refs/stash
ака stash@{0}
) так что он держится "навсегда"... за исключением того факта, что если вы делаете новый тайник, stash
Скрипт "выталкивает" текущий тайник в рефлог (так что его имя становится stash@{1}
) и заставляет новый тайник использовать refs/stash
название. Большинство записей reflog остаются на 90 дней (вы можете настроить это как-то иначе), а затем истекает. Срок действия таймеров по умолчанию не истекает, но если вы настроите это иначе, "толкаемый" тайник может потеряться, поэтому будьте осторожны с зависимостью от "сохранить навсегда", если вы начнете настраивать git по своему вкусу.
Обратите внимание, что git stash drop
"выталкивает" сюда стэкинг, перенумеровывая stash@{2}
в stash@{1}
и делая stash@{1}
стать простым stash
, использование git stash list
чтобы увидеть тайник
1 В любом случае, неплохо идти вперед и совершать их, а потом делать git rebase -i
сдавить или исправить дальнейшие вторые, третьи, четвертые,..., nth коммиты и / или переписать временный коммит "контрольной точки". Но это не зависит от этого.
2 Это немного сложнее, потому что вы можете использовать --index
пытаться держать поэтапные изменения поэтапно, но на самом деле, если вы посмотрите в сценарий, вы увидите фактическую последовательность команд git diff ... | git apply --index
, Это действительно просто применить diff, в этом случае! В конце концов это вызывает git merge-recursive
однако, непосредственно, чтобы слиться в рабочем дереве, позволяя вносить те же самые изменения из другого места. Равнина git apply
потерпит неудачу, если ваш патч сделает что-то "хорошее" D
а также E
также делает.
3 Это использует магический синтаксис именования в git с небольшим предварительным планированием внутри stash
скрипт. Потому что тайник - это смехотворный коммит, w
имеет двух или даже трех родителей, но сценарий stash устанавливает его так, чтобы "первым родителем" был исходный коммит, C
или же Z
в зависимости от обстоятельств. "Второй родитель" stash^2
является индексным состоянием на момент принятия, показанным как i
в маленькой висящей шкатулке, и "третий родитель", если он существует, - это файлы без возможности обработки и, возможно, игнорирования, из git stash save -u
или же git stash save -a
,
Обратите внимание, что в этом ответе я предполагаю, что вы не тщательно подготовили часть своего рабочего дерева и не используете git stash apply --index
восстановить поэтапный указатель. Не делая ничего из этого, вы делаете i
совершать в значительной степени избыточно, так что нам не нужно беспокоиться об этом во время apply
шаг. Если вы используете apply --index
или эквивалентные, и с постановочными предметами, вы можете попасть в гораздо большее количество угловых случаев, где тайник не будет применяться чисто.
Эти же предостережения применяются, с еще большим количеством угловых случаев, к тайникам, сохраненным с -u
или же -a
Третий коммит.
Для этих особо сложных случаев, git stash
предоставляет способ превратить тайник в полноценную ветку - но я оставлю все это другому ответу.
Команда stash git запоминает, откуда взялся тайник:
git stash list
выход
stash@{0}: WIP on master.color-rules.0: 35669fb [NEW] another step toward initial cube
Где вы можете увидеть, на каком SHA1 он был сделан. Таким образом, если вы применили git stash, git pull, git stash и у вас возник конфликт, то stash не сбрасывается (оно будет действовать только в том случае, если вы удалили или приложение прошло успешно). Таким образом, вы всегда можете получить SHA1 из списка git stash и
git checkout 35669fb
git stash apply
и это гарантированно работает. Я рекомендую использовать опцию -b и указать имя ветви для этого восстановления.
Это, как говорится, мой любимый рабочий процесс ВСЕГДА проверять под новым "личным" именем, чтобы избежать таких проблем
Вообще незафиксированные изменения всегда плохо. Либо ваши изменения хороши, а затем передайте их, либо они хуже, чем их отбросить. Выполнение любых операций git с незафиксированными изменениями может вызвать проблемы, и git не сможет вам помочь, так как git не знает ни о чем, что вы не совершали.
Сказав это, вернемся к вашему вопросу.;)
Git, как правило, довольно умный. Когда вы применяете свой тайник, он пытается объединить ваши изменения с другими изменениями. Большую часть времени это просто работает.
Если изменения действительно конфликтуют, потому что вы изменили одни и те же строки другим способом, git скажет вам, и вам придется разрешить конфликт самостоятельно. - Даже в этом случае Git поможет вам, имея git mergetool
, которая запустит подходящую команду, чтобы показать вам конфликты и позволит вам разрешить их один за другим.