Почему Git говорит, что моя основная ветка «уже обновлена», хотя это не так?

119

Основная проблема

Я просто удалил ВСЕ код из файла в моем проекте и зафиксировал изменения в моем локальном git (специально). я сделал

git pull upstream master

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

Git сообщает мне, что все обновлено.

Все определенно НЕ обновлено - весь удаленный код все равно удаляется.

Другая важная информация

У меня только одна ветка называется "master".

Недавно я установил "master" для отслеживания восходящего потока следующим образом:

Мастер ветки настроен для отслеживания удаленного мастера ветки из восходящего потока.

Команда git branch -vvдает:

* master 7cfcb29 [upstream/master: ahead 9] deletion test

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

Обновить

Я думал, что это очевидно, но в любом случае это моя цель:

Получите самый последний код в моей системе.

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

user1971506
источник
1
Очевидно, что если вы удалите исходный код, попробуйте «потянуть» простым «pull», чтобы git не переопределил ваши локальные изменения (в данном случае ваши удаления), не гарантируя, что вы действительно хотите отменить свои локальные изменения. Первый ответ, кажется, объясняет, как именно это можно сделать.
CashCow

Ответы:

211

Я думаю, ваша основная проблема здесь в том, что вы неверно истолковываете и / или не понимаете, что делает git и почему он это делает.

Когда вы клонируете какой-либо другой репозиторий, git делает копию того, что находится «там». Он также берет «свои» метки веток, такие как master, и делает копию той метки, чье «полное имя» в вашем дереве git (обычно) remotes/origin/master(но в вашем случае remotes/upstream/master). В большинстве случаев вы можете опустить и эту remotes/часть, поэтому вы можете ссылаться на эту оригинальную копию как upstream/master.

Если вы сейчас внесете и зафиксируете некоторые изменения в каком-то файле (файлах), вы единственный, кто внесет эти изменения. Тем временем другие люди могут использовать исходный репозиторий (из которого вы создали свой клон) для создания других клонов и изменения этих клонов. Конечно, только они со своими изменениями. В конце концов, у кого-то могут быть изменения, которые они отправляют обратно первоначальному владельцу (с помощью "push", патчей или чего-то еще).

Команда git pullв основном является сокращением от git fetchFollow git merge. Это важно, потому что это означает, что вам нужно понимать, что на самом деле делают эти две операции.

Команда git fetchговорит вернуться туда, откуда вы клонировали (или иным образом настроили как место для извлечения), и найти «новые вещи, которые кто-то добавил, изменил или удалил». Эти изменения копируются и применяются к вашей копии того, что вы получили от них ранее . Они не применяются к вашей собственной работе, только к их.

Команда git mergeболее сложная, и вы ошибаетесь. Что он делает, немного упрощенно, - это сравнивает «то, что вы изменили в своей копии», с «изменениями, которые вы получили от кого-то другого и, таким образом, были добавлены в вашу копию чужой-работы». Если ваши изменения и их изменения не конфликтуют, mergeоперация объединяет их вместе и дает вам «фиксацию слияния», которая связывает вашу разработку и их разработку вместе (хотя есть очень распространенный «простой» случай, когда у вас нет меняется и вы получаете "перемотку вперед").

Ситуация, с которой вы сейчас сталкиваетесь, - это та, в которой вы внесли изменения и зафиксировали их - фактически девять раз, отсюда «впереди 9» - и они не внесли никаких изменений. Итак, fetchпослушно ничего не получает, а затем mergeпринимает их отсутствие изменений и тоже ничего не делает.

Вы хотите посмотреть или, может быть, даже "сбросить" до "их" версию кода.

Если вы просто хотите взглянуть на него, вы можете просто проверить эту версию:

git checkout upstream/master

Это говорит git, что вы хотите переместить текущий каталог в ветку, чье полное имя действительно remotes/upstream/master. Вы увидите их код на момент последнего запуска git fetchи получения последнего кода.

Если вы хотите отказаться от всех собственных изменений, вам нужно изменить представление git о том, какую ревизию masterдолжен называть ваш ярлык . В настоящее время он называет вашу самую последнюю фиксацию. Если вы вернетесь в эту ветку:

git checkout master

тогда git resetкоманда позволит вам как бы "переместить метку". Единственная оставшаяся проблема (при условии, что вы действительно готовы отказаться от всего, что делали) - это найти, куда должна указывать этикетка.

git logпозволит вам найти числовые имена - такие вещи, как - 7cfcb29которые являются постоянными (никогда не меняющимися) именами, и есть смехотворное количество других способов назвать их, но в этом случае вам просто нужно имя upstream/master.

Чтобы переместить метку, удалив свои собственные изменения (все, что вы зафиксировали, на самом деле можно восстановить в течение некоторого времени, но после этого будет намного сложнее, поэтому будьте очень уверены):

git reset --hard upstream/master

--hardРассказывает мерзавец , чтобы уничтожить то , что вы делаете, переместить текущую метку ветви, а затем проверить данное обязательство.

Это не очень распространенное явление - действительно захотеть git reset --hardи уничтожить кучу работы. Более безопасный метод (значительно упрощающий восстановление этой работы, если вы решите, что некоторые из них в конце концов стоили) - переименовать существующую ветку:

git branch -m master bunchofhacks

а затем создайте новую локальную ветку с именем, masterкоторая «отслеживает» (мне не очень нравится этот термин, поскольку я думаю, что он сбивает людей с толку, но это термин git :-)) исходный (или восходящий) мастер:

git branch -t master upstream/master

с которыми вы можете заняться:

git checkout master

Что делают последние три команды (есть ярлыки, чтобы сделать это всего лишь двумя командами), так это изменить имя, вставленное в существующую метку, затем создать новую метку, а затем переключиться на нее:

прежде чем что-либо делать:

C0 -    "remotes/upstream/master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9    "master"

после git branch -m:

C0 -    "remotes/upstream/master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9    "bunchofhacks"

после git branch -t master upstream/master:

C0 -    "remotes/upstream/master", "master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9    "bunchofhacks"

Вот C0последний коммит (полное дерево исходных текстов), который вы получили, когда впервые сделали свой git clone. С C1 по C9 - ваши коммиты.

Обратите внимание, что если бы вы сделали git checkout bunchofhacksи затем git reset --hard HEAD^^, это изменило бы последнее изображение на:

C0 -    "remotes/upstream/master", "master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 -    "bunchofhacks"
                                                      \
                                                       \- C8 --- C9

Причина в том, что HEAD^^имя ревизии два выше заголовка текущей ветки (которая была бы непосредственно перед сбросом bunchofhacks), а reset --hardзатем перемещает метку. Коммиты C8 и C9 теперь в основном невидимы (вы можете использовать такие вещи, как reflog, и git fsckнаходить их, но это уже не тривиально). Ваши ярлыки принадлежат вам, чтобы перемещать их как хотите. Команда fetchпозаботится о тех, которые начинаются с remotes/. Принято сопоставлять «ваш» с «их» (так что, если у них есть, remotes/origin/mauveвы бы mauveтоже назвали свое ), но вы можете ввести «их», когда захотите назвать / увидеть коммиты, которые вы получили «от них». (Помните, что «одна фиксация» - это все дерево исходных текстов. Вы можете выбрать один конкретный файл из одной фиксации, git showнапример,

Торек
источник
12
Я многому научился из вашего отличного ответа. Но я все еще не понимаю, почему я получаю сообщение о статусе git: «Ваша ветка обновлена ​​с помощью 'origin / master'», когда исходное репо на несколько коммитов опережает мое текущее репо. Я могу получить последнюю информацию с помощью git pull, но как мне узнать, что мне нужно вытащить, если в сообщении говорится, что я в курсе?
Кристофер Верби,
@ChristopherWerby: похоже, что вы выполняете git mergeкоманду из командной строки (это то, что я делаю сам, это разумный метод). Однако обратите внимание, что это git pullначинается сначала с запуска git fetch, а затем с запуска git merge(или, git rebaseесли вы скажете ему сделать это вместо этого). Это шаг выборки, который фактически переносит новые коммиты для объединения (или только для перебазирования).
torek
@torek Есть ли какая-нибудь команда, кроме той git status, которую я могу использовать, чтобы увидеть, опережает ли вышестоящее репо мое текущее репо? Сообщение, которое я получаю git status, говорит: «Ваша ветка обновлена ​​с помощью 'origin / master'», сбивает меня с толку, заставляя думать, что у меня есть последние изменения, а у меня нет. Иногда я получаю сообщение вроде «origin / master на 5 коммитов впереди вашей ветки» (перефразируя). Но это непоследовательно.
Кристофер Верби
1
Это все еще не отвечает на вопрос, почему git statusговорится: «Ваша ветка обновлена», когда немедленное git fetchзатем опускает более сотни объектов и разрешает почти сотню дельт, упоминает несколько новых ветвей и пару новых тегов и изменяет основной (удаленный отслеживание), фиксация главы ветки - а затем другой статус git весело и лукаво по-прежнему говорит: «Ваша ветка обновлена». Очевидно, что многое произошло от источника, но ветвь была "актуальной с происхождением" как до, так и после?
NeilG
1
git pullgit fetchсначала выполняется , затем git merge(или другая вторая команда по вашему выбору). Этот git fetchшаг обновляет память вашего Git об их статусе Git, вызывая их Git и получая от них все новое. Вы git statusтолько проверяете память своего Git об их Git.
torek
19

У меня была такая же проблема, как и у вас.

Я сделал это git status git fetch git pull, но моя ветвь все еще отставала от происхождения. У меня были папки и файлы, перемещенные на удаленный компьютер, и я видел файлы в Интернете, но на моем локальном компьютере они отсутствовали.

Наконец, эти команды обновили все файлы и папки на моем локальном компьютере:

git fetch --all
git reset --hard origin/master 

или если вам нужна ветка

git checkout your_branch_name_here
git reset --hard origin/your_branch_name_here
jturi
источник
2
Спасибо! это действительно сработало. Помните, что имена веток чувствительны к регистру!
André Ramon
4

Любые изменения, которые вы фиксируете, например удаление всех файлов вашего проекта, останутся в силе после извлечения. Все, что делает вытягивание, - это объединяет последние изменения откуда-то еще в вашу собственную ветку, и если ваша ветка удалила все, то в лучшем случае вы получите конфликты слияния, когда исходящие изменения затрагивают удаленные вами файлы. Короче говоря, да, все в актуальном состоянии.

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

Обновить:

ПОЛУЧИТЕ САМЫЕ ПОСЛЕДНИЕ КОДЫ В МОЕЙ СИСТЕМЕ

Вы, кажется, не понимаете, что у вас уже есть самый последний код, который принадлежит вам. Если вы действительно хотите увидеть самые последние работы кого-то еще в главной ветке, просто выполните:

git fetch upstream
git checkout upstream/master

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

Райан Стюарт
источник
На самом деле мне нужна самая последняя версия чужого кода в моей системе. Однако эти две команды этого не сделали. Все, что я получаю, это «уже на ветке мастера». Код в моих файлах не отражает код другого человека.
user1971506
Извини, должно было быть upstream/master. Обновил свой ответ.
Райан Стюарт
3

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

git checkout HEAD^1  # Get off your repo's master.. doesn't matter where you go, so just go back one commit
git branch -d master  # Delete your repo's master branch
git checkout -t upstream/master  # Check out upstream's master into a local tracking branch of the same name
Павел
источник
1

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

  1. Перейти к мастеру

    $ git checkout upstream master
    
  2. Удалите ненужную ветку. (Примечание: он должен иметь -D вместо обычного флага -d, потому что ваша ветка намного опережает ведущую.)

    $ git branch -d <branch_name>
    
  3. Создать новую ветку

    $ git checkout -b <new_branch_name>
    
BrotherDonkey
источник
1

Хотя ни один из этих ответов у меня не сработал, я смог исправить проблему с помощью следующей команды.

git fetch origin

Это помогло мне.

Doctiger
источник
0

Просто дружеское напоминание, если у вас есть файлы локально, которых нет в github, но вы git statusговорите

В вашей ветке обновлено значение origin / master. нечего делать, рабочее дерево чистое

Это может случиться, если файлы находятся в .gitignore

Попробуйте бежать

cat .gitignore 

и посмотреть, появляются ли там эти файлы. Это объясняет, почему git не хочет перемещать их на удаленный компьютер.

Стивек
источник