Найти, когда "удаленный нами" файл был удален в git - PullRequest
2 голосов
/ 05 мая 2020

У меня есть две ветки: master и давно работающая функциональная ветка, называемая feature. Я постоянно сливаюсь из master в feature.

Один из моих конфликтов слияния:

Unmerged paths:
  (use "git add/rm <file>..." as appropriate to mark resolution)
    deleted by us:   foo.file

При слиянии я увидел следующее сообщение:

CONFLICT (modify/delete): foo.file deleted in HEAD and modified in origin/master. Version origin/master of foo.file left in tree.

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

$ git log --oneline --name-status --full-history -- foo.file
0e051cd636 (feature) Merge from master
ee5c4f1ccc (feature) Merge from master
c200d5d8b2 (master) Add foo.file
A   foo.file

Я надеялся увидеть строку D foo.file из --name-status, но я этого не сделал . И когда я сделал show на двух фиксациях слияния, я получил пустой результат:

$ git show 0e051cd636 -- foo.file
$ git show ee5c4f1ccc -- foo.file
$ 

Эта команда также дает пустой результат:

$ git log --diff-filter=D --summary foo.file
$

Я также пробовал rev-list как предложенный в связанном вопросе, но он также имел пустой вывод:

$ git rev-list -n 1 HEAD -- foo.file
$

Итак, как я могу определить, когда этот файл был удален?

Ответы [ 2 ]

0 голосов
/ 07 мая 2020

TL; DR: добавьте -m к вашей команде git log.

У команды git log есть неприятная маленькая привычка / недостаток: когда она встречает merge, коммитит, по умолчанию он не запускает на них git diff. Это относится как к git log -p (вариант «показать разницу»), так и к git log -- foo.file. Вы (правильно) вставили --full-history, чтобы избавиться от дурной привычки git log other включать Упрощение истории при использовании с именем файла - иногда это нормально, но не в том случае, если вы заботиться о - но он все еще ленив насчет коммитов слияния.

Большой молоток здесь, эквивалентный --full-history с точки зрения того, чтобы git log делать всю работу, это использовать -m. Это указывает Git (виртуально) разделить каждое слияние. Основная проблема c заключается в следующем:

  • Каждая фиксация, включая фиксацию слияния, хранит снимок всех файлов. 1
  • Но обычно мы хотим увидеть, что изменило в файлах, которые изменили (git log -p).

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

Но фиксация слияния по определению имеет как минимум двое родителей. Что нужно Git извлечь и сравнить? Если мы сравним дочерний элемент с его первым родителем, мы получим один набор файлов и изменений; если мы сравним дочерний элемент со вторым родителем, мы получим другой набор файлов и изменений. 2 Какой из них должен git log показать?

Чит-ответ по умолчанию для git log это: не беспокойтесь!

То есть git log просто говорит себе: О, эй, фиксация слияния ... это сложно! Я просто не буду беспокоиться о том, чтобы делать что-нибудь и надеюсь, что никто не заметит.

Если файл удален из-за слияния, а git log не Ничего не скажешь, вы никогда не увидите, что файл удаляется.

Флаг -m сообщает git log: Когда вы сталкиваетесь с фиксацией слияния - фиксацией, имеющей n ≥ 2 родителей, - сделайте одну отдельные git diff из каждый родитель и потомок, как если бы было n отдельных коммитов с одним родителем. Это легко сделать: нет никакой проблемы «что нам делать с несколькими родителями» Больше. Итак, это обычная разница, и она покажет вам удаление, если есть удаление.

Есть другие флаги, которые вы можете использовать, чтобы заставить git log работать усерднее, но они не обязательно помогут в этом частный случай. Поскольку -m является Большим молотком, он всегда работает; он просто может произвести больше продукции, чем вам нужно. Если вы Git ниндзя, вы можете go для хирургических подходов с -c или --cc и / или --first-parent и / или выборочным упрощением истории болезни. Но -m --full-history делает свое дело.


1 Точнее, каждая фиксация хранит моментальные снимки всех файлов, находящихся в этой фиксации. Сказанное таким образом звучит излишне: коммит хранит файлы, которые он хранит. Идея здесь состоит в том, чтобы различать guish эти важные случаи: сохраняет ли фиксация diff из предыдущей фиксации или сохраняет моментальный снимок? ответ в том, что он хранит снимок. Если бы у нас не было коммитов слияния, это могло бы не иметь значения, но у нас есть есть коммиты слияния, поэтому в конечном итоге это действительно важно.

(Даже тогда, если Git всегда хранится сравнение с предыдущим первым родителем, вместо хранения снимков, мы могли бы построить то, что нам нужно. Итак, мы вернулись к «может быть, это не имеет значения». Но на самом деле Git буквально хранит снимки, поэтому мы могли бы просто описать, как это работает, а не теоретические эквиваленты. :-))

2 Если два родителя - разные коммиты, но оба родителя имеют один и тот же снимок, мы фактически получим одинаковый набор изменений от обоих сравнений. Хотя это довольно редко.

0 голосов
/ 05 мая 2020

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

git log --diff-filter=D --summary

Итак, вы видите все удаленные файлы с помощью commit-ha sh, где вы удаляете файл.

из git документация различий

...