it-swarm.com.ru

Как мне сказать git всегда выбирать мою локальную версию для конфликтующих слияний в конкретном файле?

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

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

90
saffsd

В отношении конкретного экземпляра файла конфигурации я бы согласился с ответом Рона :
Конфигурация должна быть «приватной» для вашего рабочего пространства (следовательно, «игнорируется», как в «объявленном в файле .gitignore»).
У вас может быть файл конфигурации template с tokenized values ​​ и сценарий, преобразующий этот файл config.template в частный (и игнорируемый) файл конфигурации.


Однако это конкретное замечание не отвечает на более общий вопрос, т. Е. На ваш вопрос (!):

Как мне сказать git всегда выбирать локальную версию для конфликтующих слияний в конкретном файле? (для любого файла или группы файлов)

Этот тип слияния является «копированием слиянием», при котором вы всегда будете копировать «нашу» или «их» версию файла всякий раз, когда возникает конфликт.

(поскольку Брайан Ванденберг notes в комментариях , 'ours' и 'theirs' здесь используются для слияния.
Это в обратном порядке для rebase: см. « Why is the meaning of “ours” and “theirs” reversed with git-svn », который использует rebase, « git rebase, отслеживая« local »и« remote » «)

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

В этом случае «пользовательский драйвер слияния» - это очень простой скрипт, который в основном не изменяет текущую версию, что позволяет вам всегда выбирать локальную версию. 


Давайте проверим это в простом сценарии с msysgit 1.6.3 для Windows в простой сессии DOS:

cd f:\prog\git\test
mkdir copyMerge\dirWithConflicts
mkdir copyMerge\dirWithCopyMerge
cd copyMerge
git init
Initialized empty Git repository in F:/prog/git/test/copyMerge/.git/

Теперь давайте создадим два файла, которые будут иметь конфликты, но будут объединены по-разному.

echo a > dirWithConflicts\a.txt
echo b > dirWithCopyMerge\b.txt
git add -A
git commit -m "first commit with 2 directories and 2 files"
[master (root-commit) 0adaf8e] first commit with 2 directories and 2 files

Мы введем «конфликт» в содержимое обоих этих файлов в двух разных ветках git:

git checkout -b myBranch
Switched to a new branch 'myBranch'
echo myLineForA >> dirWithConflicts\a.txt
echo myLineForB >> dirWithCopyMerge\b.txt
git add -A
git commit -m "add modification in myBranch"
[myBranch 97eac61] add modification in myBranch

git checkout master
Switched to branch 'master'
git checkout -b hisBranch
Switched to a new branch 'hisBranch'
echo hisLineForA >> dirWithConflicts\a.txt
echo hisLineForB >> dirWithCopyMerge\b.txt
git add -A
git commit -m "add modification in hisBranch"
[hisBranch 658c31c] add modification in hisBranch

Теперь давайте попробуем объединить «hisBranch» с «myBranch»:

  • ручное разрешение для конфликтующих слияний
  • кроме для dirWithCopyMerge\b.txt, где я всегда хочу сохранить мою версию b.txt.

Поскольку слияние происходит в 'MyBranch', мы вернемся к нему и добавим директивы 'gitattributes', которые будут настраивать поведение слияния.

git checkout myBranch
Switched to branch 'myBranch'
echo b.txt merge=keepMine > dirWithCopyMerge\.gitattributes
git config merge.keepMine.name "always keep mine during merge"
git config merge.keepMine.driver "keepMine.sh %O %A %B"
git add -A
git commit -m "prepare myBranch with .gitattributes merge strategy"
[myBranch ec202aa] prepare myBranch with .gitattributes merge strategy

У нас есть файл .gitattributes, определенный в каталоге dirWithCopyMerge (определенный только в ветке, где произойдет слияние: myBranch), и у нас есть файл .git\config, который теперь содержит драйвер слияния.

[merge "keepMine"]
        name = always keep mine during merge
        driver = keepMine.sh %O %A %B

Если вы еще не определили keepMine.sh и все равно запускаете слияние, вот что вы получите.

git merge hisBranch
sh: keepMine.sh: command not found
fatal: Failed to execute internal merge
git st
# On branch myBranch
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   dirWithConflicts/a.txt
#
no changes added to commit (use "git add" and/or "git commit -a")

type dirWithConflicts\a.txt
a
<<<<<<< HEAD:dirWithConflicts/a.txt
myLineForA
=======
hisLineForA
>>>>>>> hisBranch:dirWithConflicts/a.txt

Это хорошо

  • a.txt готов к объединению и в нем есть конфликт
  • b.txt все еще остается нетронутым, поскольку драйвер слияния должен позаботиться об этом (из-за директивы в файле .gitattributes в его каталоге).

Определите keepMine.sh в любом месте вашего %PATH% (или $PATH для нашего друга из Unix. Конечно, я делаю и то и другое: у меня есть сеанс Ubuntu в сеансе VirtualBox)

Как и прокомментировано by lrkwz и описано в разделе " Стратегии слияния " в Настройка атрибутов Git - Git , вы можете заменить сценарий оболочки командой Shell true.

git config merge.keepMine.driver true

Но в общем случае вы можете определить файл скрипта:

keepMine.sh

# I want to keep MY version when there is a conflict
# Nothing to do: %A (the second parameter) already contains my version
# Just indicate the merge has been successfully "resolved" with the exit status
exit 0

(это был один простой драйвер слияния;) (Еще проще в этом случае использовать true)
(Если вы хотите сохранить другую версию, просто добавьте перед строкой exit 0:
cp -f $3 $2.
Это оно. Драйвер слияния всегда будет держать версию, поступающую из другой ветки, отменяя любые локальные изменения)

Теперь давайте попробуем объединить с самого начала:

git reset --hard
HEAD is now at ec202aa prepare myBranch with .gitattributes merge strategy

git merge hisBranch
Auto-merging dirWithConflicts/a.txt
CONFLICT (content): Merge conflict in dirWithConflicts/a.txt
Auto-merging dirWithCopyMerge/b.txt
Automatic merge failed; fix conflicts and then commit the result.

Слияние не удается ... только для a.txt.
Отредактируйте a.txt и оставьте строку из «hisBranch», затем:

git add -A
git commit -m "resolve a.txt by accepting hisBranch version"
[myBranch 77bc81f] resolve a.txt by accepting hisBranch version

Давайте проверим, что b.txt был сохранен во время этого слияния

type dirWithCopyMerge\b.txt
b
myLineForB

Последний коммит представляет собой слияние full:

git show -v 77bc81f5e
commit 77bc81f5ed585f90fc1ca5e2e1ddef24a6913a1d
Merge: ec202aa 658c31c
git merge hisBranch
Already up-to-date.

(Строка, начинающаяся с Merge, доказывает это)


Учтите, что вы можете определить, объединить и/или перезаписать драйвер слияния, как Git будет:

  • проверить <dir>/.gitattributes (который находится в том же каталоге, что и рассматриваемый путь): будет преобладать над другим .gitattributes в каталогах
  • Затем он проверяет .gitattributes (который находится в родительском каталоге), будет устанавливать директивы, только если он еще не установлен
  • Наконец, он проверяет $GIT_DIR/info/attributes. Этот файл используется для переопределения настроек в дереве. Он перезапишет директивы <dir>/.gitattributes.

Под «объединением» я подразумеваю «агрегировать» драйвер множественного слияния.
Ник Грин пытается, в комментариях , чтобы на самом деле объединить драйверы слияния: см. " Слияние pom через драйвер python git ".
Однако, как уже упоминалось в его другой вопрос , он работает только в случае конфликтов (одновременное изменение в обеих ветвях).

133
VonC

У нас есть несколько конфигурационных файлов, которые мы никогда не хотим перезаписывать. Однако .gitignore и .gitattributes не работали в нашей ситуации. Нашим решением было хранить файлы конфигурации в ветке конфигов. Затем разрешите изменять файлы во время git-слияния, но сразу же после слияния используйте «ветку git checkout -». скопировать наши файлы конфигурации из ветки конфигов после каждого слияния . Подробный ответ на стекопоток здесь

0
HamletHub