Могу ли я использовать git diff для неотслеживаемых файлов?

270

Можно ли попросить git diff включить неотслеживаемые файлы в свой вывод diff? Или мой лучший выбор - добавить новые файлы, которые я создал, и существующие файлы, которые я отредактировал, и использовать

git diff --cached

?

Эндрю Гримм
источник

Ответы:

267

В последних версиях git вы можете git add -Nиспользовать файл (или --intent-to-add), который добавляет блоб нулевой длины к индексу в этом месте. В результате ваш «неотслеживаемый» файл теперь становится модификацией для добавления всего содержимого в этот файл нулевой длины, и это отображается в выводе «git diff».

git diff

echo "this is a new file" > new.txt
git diff

git add -N new.txt
git diff
diff --git a/new.txt b/new.txt
index e69de29..3b2aed8 100644
--- a/new.txt
+++ b/new.txt
@@ -0,0 +1 @@
+this is a new file

К сожалению, как указано, вы не можете, git stashпока у вас есть --intent-to-addфайл, ожидающий, как это. Хотя, если вам нужно спрятать, просто добавьте новые файлы, а затем спрячьте их. Или вы можете использовать обходной путь эмуляции:

git update-index --add --cacheinfo \
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 new.txt

(настройка псевдонима - ваш друг здесь).

araqnid
источник
Оказывается, моя копия Git недостаточно свежая, чтобы добавить -N, но это отвечает на мой вопрос.
Эндрю Гримм
1
Вы можете эмулировать «git add -N new.txt» с «git update-index --add --cacheinfo 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 new.txt» (как мне удалось поставить это на неправильный ответ?)
araqnid
Функция добавлена ​​в 1.6.1: github.com/git/git/blob/master/Documentation/RelNotes/1.6.1.txt
2013 г.
1
Что, если у вас много новых файлов, есть ли простой способ добавить их все, а затем изменить?
Вик
1
@Vicgit add -N .
Натан
92

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

git diff --no-index tracked_file untracked_file
Гарольд
источник
3
Работает ли это, если у вас есть более одного неотслеживаемого файла, который вы создали с момента последнего коммита?
Эндрю Гримм
12
Да, идеальный ответ! Затем я могу использовать git diff --no-index untracked_file_1 untracked_file_2для git diffраскраски синтаксиса и т. Д. На diffs ... красиво.
Колин Д. Беннетт
40
Я не понимаю, почему вы сравниваете отслеживаемый файл с несвязанным неотслеживаемым файлом. Если вы просто хотели , чтобы получить дифф выход для неотслеживаемого файла, вы можете просто использовать /dev/nullвместо: git diff --no-index -- /dev/null <untracked_file>.
4
Или просто cat untracked_file_1, или, возможно, printf '\e[1;32m%s\e[0m\n' "$(cat untracked_file_1)"если вам действительно нужен зеленый выход. :) (Хотя на более серьезной ноте, обратите внимание, что подстановка команд удалит завершающие символы новой строки из вашего файла.)
Wildcard
8
Это должен быть принятый ответ - он не требует изменения индекса git; который, как говорит оригинальный автор, имеет свою
обратную
38

Для моей интерактивной повседневной работы (где я постоянно разрабатываю рабочее дерево по отношению к HEAD и хотел бы, чтобы неотслеживаемые файлы были включены в diff), add -N/--intent-to-addон непригоден, потому что он ломается git stash .

Так вот моя git diffзамена. Это не особо чистое решение, но, поскольку я действительно использую его только в интерактивном режиме, у меня все в порядке с хаком:

d() {
    if test "$#" = 0; then
        (
            git diff --color
            git ls-files --others --exclude-standard |
                while read -r i; do git diff --color -- /dev/null "$i"; done
        ) | `git config --get core.pager`
    else
        git diff "$@"
    fi
}

dПечатая просто включит неотслеживаемые файлы в diff (что меня беспокоит в моем рабочем процессе), и d args...будет вести себя как обычный git diff.

Ноты:

  • Здесь мы используем тот факт, что git diffна самом деле объединяются отдельные разностные различия, поэтому невозможно определить dвыходные данные из «реального различий» - за исключением того факта, что все неотслеживаемые файлы сортируются последними.
  • Единственная проблема с этой функцией заключается в том, что выходные данные окрашены даже при перенаправлении; но я не могу потрудиться добавить логику для этого.
  • Я не мог найти способ включить неотслеживаемые файлы, просто собрав список аргументов для git diff. Если кто-то выяснит, как это сделать, или если какая-то функция будет добавлена gitв какой-то момент в будущем, пожалуйста, оставьте примечание здесь!
Джо Лисс
источник
4
По иронии судьбы, мой git update-index --add --cacheinfo 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 new.txtобходной путь, который я предложил для более старых gits , работает git stash, предполагая, что у вас уже есть e69de29bb в вашей базе данных, например, при попытке использовать add -Nранее. Так что, по-видимому, это не совсем то же самое, что и git add -N: я не знаю, как.
araqnid
2
testКстати, вы выполняете сравнение строк, а не проверку числового равенства с помощью вашей команды. Ничего не должно влиять, но test "$#" -eq 0точнее то, что задумано.
Wildcard
1
Да, все еще выглядит так, как будто вам нужно сделать это попарно ... но можно подделать его в один, lessчтобы вам не нужно было нажимать qдля каждого файла, и это выглядит точно так же git diff, удаляя разбиение на страницы для каждого файла ( -P), добавляя его впоследствии ( | less), сохраняя цвет ( --color=always) и интерпретируя его как цвет ( less -rили less -R). Так в целом это:do git -P diff --color=always -- /dev/null "$i"; done | less -r
hyperpallium
В случае, если вы хотите, чтобы вас беспокоили в будущем test -t 1(например, if [ -t 1 ]; then color_arg=--color; fiчто-то вроде этого), это способ для оболочки проверить, является ли ее вывод терминалом, что является полезным способом выбора цвета. И xargsможет дать способ избавиться от цикла while. Вам все еще понадобится -n 1это, так что он все равно будет запускать git несколько раз, и все равно должен быть попарно таким образом, но ... он избавляется от, whileи read, может быть, так лучше ?! Я оставляю это читателю.
Линд
28

Не на 100%, но если по какой-то причине вы не хотите добавлять свои файлы в индекс, как предполагает принятый ответ, вот еще один вариант:

Если файлы не отслеживаются, очевидно, что diff - это весь файл, так что вы можете просто просмотреть их с меньшим количеством:

less $(git ls-files --others --exclude-standard)

Перейдите между ними с помощью :nи :pдля следующего и предыдущего ..

Обновление из комментариев: Если вам нужен формат патча, вы также можете комбинировать его с git diff:

git ls-files --others --exclude-standard | xargs -n 1 git --no-pager diff /dev/null | less

В этом случае вы также можете перенаправить вывод в файл или использовать другую команду diff.

user1587520
источник
6
Вы также можете запустить git diff /dev/null <untracked_tile>и получить патч в формате патча, а не «просто» файл
SimSimY
2
этот ответ в сочетании с git diff является идеальным решением.
iwind
22
git add -A
git diff HEAD

При необходимости сгенерируйте патч, а затем:

git reset HEAD
Амол Пуджари
источник
Это может привести к потере предыдущей (предварительной) работы, добавляя все. Особенно в случае, если кто-то использует git add -pочень часто (что я обычно рекомендую, между прочим) ... Это дает способ сделать основную вещь, просто ... следует отметить, что у нее есть потенциал для нежелательной стороны последствия.
Линд
13

это работает для меня:

git add my_file.txt
git diff --cached my_file.txt
git reset my_file.txt

Последний шаг не является обязательным, он оставит файл в предыдущем состоянии (без отслеживания)

полезно, если вы тоже создаете патч:

  git diff --cached my_file.txt > my_file-patch.patch
Алехандро Морено
источник
Специфика этой пары добавления / сброса - хороший контраст с подходом дробовика stackoverflow.com/a/50486906/313756 ... спасибо за это.
Линд
9

Изменения работают, когда поставлены и не поставлены с этой командой. Новые файлы работают при постановке:

$ git diff HEAD

Если они не организованы, вы увидите только различия файлов.

alairock
источник
26
HEADэто значение по умолчанию , так что это то же самое, git diffчто не решает проблему.
Юлиан
4
Это требует git addот каждого не отслеживаемого файла
SilvioQ
Если вы отредактируете этот ответ, включив git addего, то проще всего будет проверить, что вы только что добавили / хотите добавить
KCD
8

Для одного файла:

git diff --no-index /dev/null new_file

Для всех новых файлов:

for next in $( git ls-files --others --exclude-standard ) ; do git --no-pager diff --no-index /dev/null $next; done;

Как псевдоним:

alias gdnew="for next in \$( git ls-files --others --exclude-standard ) ; do git --no-pager diff --no-index /dev/null \$next; done;"

Для всех измененных и новых файлов, объединенных в одну команду:

{ git --no-pager diff; gdnew }
radzimir
источник
2

обычно, когда я работаю с командами удаленного определения местоположения, для меня важно, чтобы у меня были предварительные знания о том, какие изменения были сделаны другими командами в том же файле, прежде чем я буду следовать этапам git untrack -> staged -> commit для этого, я написал скрипт bash, который помогите мне избежать ненужного разрешения конфликта слияния с удаленной командой или создания новой локальной ветки и сравнения и слияния в основной ветке

#set -x 
branchname=`git branch | grep -F '*' |  awk '{print $2}'`
echo $branchname
git fetch origin ${branchname}
for file in `git status | grep "modified" | awk "{print $2}" `
do
echo "PLEASE CHECK OUT GIT DIFF FOR "$file 
git difftool FETCH_HEAD $file ;
done

В приведенном выше сценарии я выбираю удаленную основную ветвь (не обязательно ее основную ветвь), чтобы FETCH_HEAD создал список только моего измененного файла и сравнил измененные файлы с git difftool

здесь много difftool, поддерживаемых git, я настраиваю 'Meld Diff Viewer' для хорошего сравнения GUI.

ADG
источник
-9

Предполагая, что у вас нет локальных коммитов,

git diff origin/master
Pradhan
источник
8
Вопрос просит git diffкоманду, которая включает неотслеживаемые файлы. Эта команда не включает их. Кроме того, наличие локальных коммитов не имеет абсолютно никакого отношения к вопросу.
toon81
JFTR, я git merge --squash mybranchи git diff masterпоказал мне изменения в неотслеживаемых файлах.
Муаммар
2
Это невозможно. Вы, кажется, смущены тем, что означает «не отслеженный». Не отслеживание не означает, что файл отслеживается в одной ветви, а не в другой, это означает, что он нигде не находится "в Git". Сквош ты или нет, без разницы. git diffне показывает различий в неотслеживаемых файлах: поскольку они не отслеживаются, по определению различий нет. Просто так работает Git. :)
toon81