Что происходит с локальным переданным кодом, если ветка git удаляется на сервере, а на сервере создается новая ветка с тем же именем? - PullRequest
0 голосов
/ 05 октября 2019

Я создаю функциональную ветку 'Fb1' на сервере и подключаюсь к ней локально, извлекаю код, начинаю кодировать и фиксирую код в локальной ветви.

Затем я переключаюсь на другую ветку 'Fb2', извлеките код и начните кодирование.

Между тем, если кто-то удалит функциональную ветвь 'Fb1' на сервере, прежде чем я нажму код, и заново создаст ветку Fb1 на сервере с новым кодом, а затем я сделаювыборка, чтобы синхронизировать мои локальные репозитории с серверными репозиториями. Теперь у меня все еще есть доступ к моему локальному Fb1, переданному по коммиту, или он перезаписывается с помощью кода ветки Rhe neq Fb1 на сервере и как мне получить доступ к коду Fb1 в проводнике команды Visual Studio?

Ответы [ 3 ]

0 голосов
/ 05 октября 2019

Есть несколько вещей, происходящих более или менее одновременно, что может быть довольно запутанным. Чтобы сохранить все как есть, начните с этого понятия: Git не относится к файлам. Git составляет около коммитов . Коммиты содержат файлов, поэтому в результате Git будет хранить файлы;но Git заботится о коммитах с их большими уродливыми хеш-идентификаторами.

Вы видели хеш-идентификаторы коммитов в выводе git log, вероятно. Например, они выглядят как bc12974a897308fd3254cf0cc90319078fe45eea - это коммит в Git-репозитории для самого Git. Каждый коммит получает свой уникальный хэш-идентификатор. Никакой другой коммит нигде и никогда не может использовать этот хэш-идентификатор. Git взял это для себя и теперь , что коммит. Все ваши коммиты будут иметь разные хеш-идентификаторы. 1 Каждый Git везде автоматически соглашается с каждым другим Git везде, какой хеш-идентификатор для каждого коммита после того, как он сделан, и без хеш-идентификатора коммитакогда-либо меняется, так что bc12974a8973... всегда и навсегда является тем конкретным коммитом в Git-репозитории для Git.

Branch names , например fb1 или fb3, 2 входят в картину, потому что простые люди не могут вспомнить или ввести большие уродливые хэш-идентификаторы. Я должен был вырезать и вставить этот, чтобы сделать это правильно. Эти имена позволяют вам - и Git - найти хеш-идентификаторы.

Вы можете создавать и уничтожать ветки в любое время. Чтобы создать ветку, вы выбираете некоторую фиксацию - какой-то хеш-идентификатор, который вы можете найти по другому имени или запустив git log и вырезая и вставляя необработанный хеш-идентификатор - и говорите Git: Создайте новое имя,и в этом имени сохраните этот здесь необработанный хэш-идентификатор:

git branch gitty bc12974a897308fd3254cf0cc90319078fe45eea

назначает вышеуказанный хэш-идентификатор имени gitty. (Ваш Git гарантирует, что этот хэш-идентификатор действительно существует в вашем хранилище и является хеш-идентификатором коммита. 3 ) Если вы используете другое имя:

git branch gitty master

Git first turnимя master в необработанный хэш-идентификатор, затем помещает необработанный хеш-идентификатор в новое имя gitty.

Чтобы узнать, какой хеш-идентификатор представляет любое имя в данный момент, используйте git rev-parse:

$ git rev-parse master
bc12974a897308fd3254cf0cc90319078fe45eea

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


1 Технически, ему разрешено повторно использовать хэш-идентификаторы, пока два Gits с повторно используемыми идентификаторами никогда не встречаются друг с другом. Так что, если вы никогда не попытаетесь объединить Git-репозиторий для Git с вашим собственным Git-репозиторием, что бы вы ни делали, ваш Git может повторно использовать этот хэш-идентификатор. Вероятность фактического хеш-коллизии крайне мала, за исключением случаев, когда кто-то намеренно форсирует коллизию. См. Также Как недавно обнаруженное столкновение SHA-1 влияет на Git?

2 Я поместил их в нижний регистр. В общем случае неразумно смешивать имена в верхнем и нижнем регистре для имен веток и файлов, если вы хотите, чтобы ваш репозиторий работал правильно на большинстве систем MacOS и Windows.

3 Git использует хэш-идентификаторыбольше, чем просто коммиты. Например, они также определяют конкретное содержимое определенных версий файлов. Следовательно, когда вы делаете тысячи коммитов, которые в основном повторно используют большинство файлов, новые коммиты просто возвращаются к уже существующим, уже зафиксированным файлам.


Нарисуйте картинку

Несмотря на то, что эти хэш-идентификаторы действительно конкретны, они не нужны людям: мы просто не можем держать их все прямо. Опять же, это , почему мы используем ветку names . Но внутри Git Git использует хэш-идентификаторы. Это будет иметь больше смысла в вашей собственной голове, если вы рисуете картинки.

ПомнитеТо, что каждый коммит содержит снимок - набор файлов, как бы они ни выглядели в тот момент, когда вы сделали этот коммит, - но он также содержит некоторую дополнительную информацию, которую Git называет метаданные ,Эти метаданные включают имя и адрес электронной почты лица, сделавшего коммит, а также отметку даты и времени для коммита. Он включает в себя сообщение журнала: щелкните ссылку на копию GitHub этого коммита Git, и вы увидите, что строка его темы - Fourth batch (а остальное - просто строка подписи - не самое лучшее сообщение о коммите, но оно может быть хуже 4 ). Возможно, наиболее важной частью метаданных коммита является то, что каждый коммит содержит необработанные хэш-идентификаторы своих родительских коммитов.

Когда выполняется одна вещьхеш-идентификатор другого коммита, мы говорим, что первое указывает на второй коммит. Так что, если имя fb1 содержит хеш-идентификатор коммита, имя ветви fb1 указывает на коммит. Этот коммит сам содержит хэш-идентификатор родительского коммита. Родительский коммит содержит хеш-идентификатор своего родителя и т. Д .:

... <--o  <--o  <--o   <--fb1

, где каждый раунд o представляет коммит.

Все эти стрелки идуттолько один путь - назад - так по определению, имя ветки указывает на последний коммит в цепочке коммитов. У самих коммитов есть внутренние стрелки назад, которые связывают их вместе.

Когда вы делаете ветку и начинаете коммитить, Git заставляет новые коммиты указывать назад на более старые коммиты. Затем он перемещает имя ветви вперед , чтобы оно указывало на новый коммит. Давайте нарисуем это, используя одиночные заглавные буквы для замены хеш-идентификаторов коммитов (поскольку хеш-идентификаторы слишком большие и некрасивые):

...-F--G--H   <-- master, fb1 (HEAD)

Я опишу, что слово (HEAD) здесь делает простомомент. Здесь для удобства я нарисовал все внутренние стрелки просто как соединительные линии. Мы можем просто держать в наших умах, что они указывают назад;Большую часть времени нам не о чем беспокоиться.

Мы только что создали fb1 из master, поэтому оба имени указывают на один и тот же коммит , помеченныйH (для хэш-идентификатора) здесь. Обратите внимание, что все коммиты находятся в обеих ветках: это странная вещь, которую делает Git, чего не делают другие системы контроля версий. Коммиты находятся в нескольких ветвях одновременно.

Теперь давайте сделаем новый коммит, который мы назовем I. Мы выполняем обычный шаг беспорядок с некоторыми файлами, запускаем на них git add, запускаем git commit и предоставляем Git сообщение журнала. Git упаковывает новый снимок (всех файлов, а не только тех, которые мы изменили) и устанавливает родителя нового коммита равным H, так что новый коммит I указывает на H:

...-F--G--H   <-- master, fb1 (HEAD)
           \
            I

Теперь Git обновляет имя ветки, чтобы оно указывало на I. Какое имя ветви обновляет Git? Вот тут и приходит HEAD. HEAD сообщает Git , какую ветку мы проверили . У нас fb1 проверено, и, следовательно, было commit H. Теперь, когда Git создал новый коммит I, Git обновляет имя , к которому прикреплен HEAD , так что мы получаем:

...-F--G--H   <-- master
           \
            I   <-- fb1 (HEAD)

Теперь мы создали новыйсовершить на ветке fb1. Коммиты до H все еще находятся на обеих ветвях. Коммит I, новый, имеет только на fb1.

Если мы сделаем больше коммитов, они также будут только на fb1:

...-F--G--H   <-- master
           \
            I--J   <-- fb1 (HEAD)

4 В комиксе xkcd новые коммиты направлены вниз. В выводе git log --graph --oneline более новые коммиты идут вверх. В способе рисования фрагментов графа коммитов в StackOverflow новые коммиты направлены вправо. Рисунки графиков можно ориентировать любым способом, который помогает вам их просматривать, поэтому выбирайте любой способ, который вам подходит.


Ветви - это здорово, давайте сделаем больше!

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

git checkout master
git branch fb2
git checkout fb2

или более просто:

git checkout -b fb2 master

, который делает все это за один шаг. В результате наш график вообще не изменяется, но мы добавляем новое имя , fb2 и добавляем туда HEAD:

...-F--G--H   <-- master, fb2 (HEAD)
           \
            I--J   <-- fb1

Теперь у нас зафиксирован коммит H с новым именем fb2. Если мы запустим git log, мы увидим коммит H, затем коммит G, затем коммит F и т. Д. git log начинается там, где мы находимся, затем следует внутренним стрелкам назад.

Обратите внимание, что коммиты I и J все еще находятся в нашем хранилище, и мы все еще можем их найти: имя fb1 находит коммит J, а из коммита J мы можем отступить черезвнутренняя стрелка, указывающая назад, чтобы найти I. Обычный git log не будет отображать эти два коммита: нам нужно запустить git log fb1, чтобы увидеть их, чтобы git log начинался с коммита J, обозначенного именем fb1, а не с HEAD и, следовательно, найти H.

Теперь, когда мы находимся в этой новой позиции, давайте сделаем два новых коммита. Они получат свои собственные уникальные, большие уродливые хэш-идентификаторы, но мы просто назовем их K и L. Давайте нарисуем их - и для удобства давайте перевернем fb1 в верхний ряд:

            I--J   <-- fb1
           /
...-F--G--H   <-- master
           \
            K--L   <-- fb2 (HEAD)

Теперь у нас есть три ветки в нашем собственном репозитории Git, найденные по трем именам fb1, fb2master. Эти три ветви находят три коммита, но каждый из этих трех коммитов находит больше коммитов: Git начинает с того коммита, который мы ему сообщаем, затем идет назад, следуя внутренним стрелкам, направленным назад.

Потому что коммит Hявляется родителем I и K, мы находим коммит H три раза. Мы находим его родителя, G, тоже три раза и так далее для всех коммитов, стоящих за ним. Все эти коммиты теперь находятся на всех трех ветвях. Но коммиты I-J имеют значение только на ветви fb1, а коммиты K-L имеют только на ветви fb2.

Удаление имен

Предположим, мы должны были удалить полностью master имя, используя git branch -d master:

            I--J   <-- fb1
           /
...-F--G--H
           \
            K--L   <-- fb2 (HEAD)

Теперь у нас нет ветви с именем master. Но у нас все еще есть все его коммитов . Их по-прежнему легко найти: мы можем начать с fb1 (коммит J) или fb2 (коммит L) и вернуться к H, и есть H. Таким образом, все эти коммиты все еще там, все еще в двух ветвях. Они были на трех ветвях раньше;теперь они на двоих.

Мы можем вернуть master, используя git branch master <hash-of-H> (вырезать и вставить идентификатор хеша из git log), а затем сказать Git удалить имя fb1. В любом случае, сейчас мы вообще не можем удалить fb2, потому что мы стоим на нем (HEAD прикреплен к fb2). Мы должны сказать Git принудительно удалить fb1, потому что посмотрите, что произойдет, если мы сделали:

            I--J   ???
           /
...-F--G--H   <-- master
           \
            K--L   <-- fb2 (HEAD)

Как только имя fb1 исчезнет, ​​как мы будемнайти коммит J? Мы зависим от поиска коммита J, чтобы найти коммит I тоже. Мы все еще можем найти L и K и H и т. Д., Но если мы удалим name fb1, мы потеряем идентификатор хеша для последнего коммита в этой ветви.

Поскольку Git - это всего лишь , фиксирует , Git не позволит нам удалить fb1, не форсируя его, и, конечно, мы не должны. Однако, если fb1 все еще указывает на H - так что мы можем найти коммит H через fb2 - Git будет , давайте удалим fb1, не форсируя его.

Использование другого Git: git fetch

Все вышеперечисленное описывает, как мы используем наш Git-репозиторий локально. Но в вашем случае у вас есть другой репозиторий Git, хранящийся на GitHub. Ваш Git называет этот другой Git origin - это, в основном, короткое имя для URL, который вы используете, чтобы ваш Git говорил с Git на GitHub.

Вы можете запустить:

git fetch origin

впусть ваш Git вызывает их Git. Ваш Git использует URL-адрес, сохраненный в имени origin - Git называет эту вещь remote , и это просто короткое имя для URL-адреса и некоторых других полезных данных - чтобы позвонить своему Git и вашему Git иих Git имеют разговор. Их Git перечисляет все их имена веток и их необработанные хэш-идентификаторы коммитов. Ваш Git проверяет, есть ли у вас эти коммиты или нет. Если у вас нет коммитов - помните, хеш-идентификаторы коммитов универсальны для каждого Git, так что ваш Git может просто проверить по ID - ваш Git затем попросит их Gitупаковать эти коммиты. Кроме того, ваш Git получит все файлы этих коммитов, их родительские коммиты и их файлы и так далее. Ваш Git и его Git общаются друг с другом, чтобы выяснить, какие коммиты у вас уже есть, и, следовательно, не нужны, чтобы они отправляли вам только то, что вам нужно. какими бы ни были их хеш-идентификаторы - теперь они хранятся в Git. Но ваш Git должен иметь какое-то имя для последнего нового коммита в любой обновленной ветке. Именно здесь приходят ваши имена для удаленного отслеживания .

Скажем, например, что они добавили коммит к своему мастеру. Мы назовем этот коммит M:

            I--J   <-- fb1
           /
...-F--G--H   <-- master
           \
            \--M   <-- ???
             \
              K--L   <-- fb2 (HEAD)

Какое имя будет использовать ваш Git, чтобы запомнить их master? Ответ здесь заключается в том, что ваш Git создает ваше собственное имя origin/master в отдельном пространстве имен 5 , так что мы получаем:

            I--J   <-- fb1
           /
...-F--G--H   <-- master
           \
            \--M   <-- origin/master
             \
              K--L   <-- fb2 (HEAD)

Фактически, вы уже имел и origin/master, указывая на H ранее. Мы просто не нарисовали его!

Теперь, если вы создали fb1 в Git над origin и сделали git fetch, вы также получите origin/fb1. Это будет указывать на то, какой коммит fb1 на Git Gub указывает на.

Если кто-то еще, кто также может манипулировать GitHub Git, перемещает или удаляет свои fb1, у вашего Git все еще есть свой fb1. Это никогда не исчезнет само по себе: это ваша ветвь, и вы управляете ею. Ваш origin/fb1 может двигаться, и если вы установите свой Git на prune имена для удаленного слежения, ваш origin/fb1 может полностью исчезнуть. Но ваш fb1, ваша ветвь, находится под вашим контролем. Вы выбираете, как переместить или удалить его.


5 Полное имя ветви в вашем хранилище начинается с refs/heads/. Полное имя имя для удаленного отслеживания origin/master равно refs/remotes/origin/master. Это не начинается с refs/heads/, поэтому вы можете создать свое собственное имя локальной ветви, refs/heads/origin/master, которое отличается от вашего имени для удаленного отслеживания.

Не делайте этого! Он не сломается Git , но может сломаться вы . :-) Если вы случайно сделали это, переименуйте вашу локальную ветку, чтобы ее имя больше не начиналось с origin/, чтобы сбить с толку.


Как насчет git push?

Команда git push в основном противоположна git fetch: ваш Git вызывает их Git, а затем вместо получения новых коммитов от них вы даете новые коммиты до их.

Это не совсем противоположно. Когда вы получаете новые коммиты от , ваш Git автоматически создает или обновляет ваши имена для удаленного отслеживания, так что у вас есть имена origin/*, по которым можно найти их новые коммиты. Но когда вы git push фиксируете для их, вы просите них установить их ветвь имён.

Итакнапример, если вы git push зафиксировали I и J, вы почти наверняка захотите попросить их установить их имя ветви fb1 в соответствии с вашим.

Давайтескажем, у нас есть коммит M, и мы уже обновили наш собственный master, чтобы включить его. У них есть fb1, указывающие на коммит H, и у них еще нет fb2, так что в нашем репозитории мы имеем этот график:

            I--J   <-- fb1
           /
...-F--G--H--M   <-- master, origin/master, origin/fb1
           \
            K--L   <-- fb2 (HEAD)

Теперь мы можем запустить:

git push origin fb1

Это отправит коммиты I и J им: у них их нет, но они нужны для перемещенияих fb1, чтобы указать на J. Тогда наш Git спросит их Git: Пожалуйста, если все в порядке, установите ваш fb1 сейчас так, чтобы он указывал на J.

В этом случае это будет быть хорошо. Они установят свои fb1, чтобы указать J. Ваш Git подтвердит это, обновив свой собственный origin/fb1, и теперь у вас есть:

            I--J   <-- fb1, origin/fb1
           /
...-F--G--H--M   <-- master, origin/master
           \
            K--L   <-- fb2 (HEAD)

в вашем хранилище. У них просто есть master, идентифицирующие M и fb1, идентифицирующие J;у них еще нет fb2.

А как насчет git pull?

Команда git pull - это просто сокращение для:

  • rungit fetch;
  • затем выполните вторую команду Git, обычно git merge, но вы можете выбрать git rebase.

Я советую новичкам делать Git, чтобы избегать git pull, потому что он скрывает этот двухэтапный процесс и оставляет их в безвыходном положении, когда по какой-то причине не удается выполнить команду second . команда со сложными режимами сбоев.

Rebase в некотором смысле хуже: в действительности, это повторяющаяся серия команд git cherry-pick (за которыми следует одно перемещение метки ветвления), и каждый является формой слияния. Так что, если слияние может потерпеть неудачу, то и каждый вишнёк. Если существует пять коммитов для выбора вишни, чтобы выполнить перебазирование, есть пять шагов, которые могут потерпеть неудачу!

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

Можно использовать git pull - вместо этого удобствоиз git fetch, за которым следует вторая команда, но просто помните, что это именно то, что есть, чтобы при сбое второй команды вы знали , какую вторую команду вы использовали и что делать дальше. Даже зная все это, я в основном сам не использую git pull, потому что мне часто нравится запускать git log между git fetch и второй командой, чтобы посмотреть, что git fetch выбрал. Иногда это меняет , использую ли я git merge или git rebase!

Заключение

Учитывая все вышесказанное, давайте посмотрим на вопрос темы:

Что происходит с локальным подтвержденным кодом, если ветка git удалена на сервере?

Ничего. С местными коммитами вообще ничего не происходит. Ваши местные филиалы ваши , причем как вы хотите. Вы выбираете, что будет дальше.

0 голосов
/ 07 октября 2019

Ваша локальная ветвь не будет затронута, вы все равно сможете запустить:

git checkout Fb1
  • Если вы хотите заново создать удаленную ветку с именем Fb1:

    git push origin -u Fb1
    
  • Если вы хотите перенести это в новую удаленную ветку с именем Fb3:

    # with this command : your local 'Fb1' branch will be linked to remote 'Fb3'
    git push origin -u Fb1:Fb3
    

    или, возможно, более ясно:

    # rename your  local 'Fb1' branch to 'Fb3' :
    git checkout Fb1
    git branch -m Fb3
    
    # push this 'Fb3' branch to remote :
    git push origin -u Fb3
    
0 голосов
/ 05 октября 2019

Я думаю, вам просто нужно переключиться обратно на ветку Fb1. Вы должны найти это, как вы оставили это. Даже если он был удален на сервере, вы можете получить к нему доступ локально.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...