Имейте удаленный репозиторий мерзавца, отказываются от фиксаций слияния на нажатии

Что я хочу сделать:

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

Объяснение того, почему я хочу сделать это:

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

У меня есть центральный репозиторий мерзавца с ответвлением это, несколько разработчиков отслеживают. Каждому разработчику настроили удаленное для ответвления того центрального репозитория.

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

Для упрощения я не хочу, чтобы локальные ответвления отслеживания разработчика когда-либо были объединены с удаленным ответвлением. А скорее всегда быть перебазирующимся на удаленном ответвлении.

Мы частично осуществили это на машине разработчика путем установки ответвления. NAME.rebase = верный, который помогает проблемам предотвращения, если разработчик использует получение по запросу мерзавца, однако нам нужно решение осуществить это на стороне центрального репозитория.

Очень основное решение состояло бы в том, чтобы отказаться от фиксаций с комментарием: "Слияние переходит 'НАЗВАНИЕ' GITURL", однако, что-то больше вроде проверки, если бы все родители фиксации существуют в путях ответвления центрального репозитория, было бы более интересным.

Предложения? Решения?

Править:

Это - то, что я имею до сих пор:

#!/bin/sh
read sha1old sha1new refname

# check if this is merge commit
merge_commit="`git rev-list --parents --merges --no-walk $sha1new 2> /dev/null`"
if test -n "$merge_commit"
then
  # this was a merge commit
  # $merge_commit contains: sha1new sha1parent_1 ... sha1parent_n
fi
exit 0

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

9
задан chris 23 January 2010 в 10:58
поделиться

1 ответ

Один из способов предотвращения толчков, которые создадут нелинейную историю - это установка pre-receive крюка, который использует git rev-list --parents ... для проверки любого нового коммита, который имеет более одной скобки, и выход из него по ошибке, если это так. Чтобы справиться со вторым требованием, вы можете вместо этого проверить, что если есть более одного родителя, то все эти фиксации должны быть на существующих ветках в репозитории. Я не очень много тестировал это, но этот крюк pre-receive (или какой-нибудь его вариант) может быть тем, что вы хотите:

#!/usr/bin/ruby -w

# A pre-receive hook that should refuse any pushes that would update
# master in such a way that a non-linear history would be created,
# except where it involves a merge from another branch in this
# repository.  This has only had very cursory testing.

# This is a suggested answer to:
#   http://stackoverflow.com/questions/2039773/have-remote-git-repository-refuse-local-branch-merge-commits-on-push

ref_to_check = "refs/heads/master"

rev_old, rev_new, ref = STDIN.read.split(" ")

if ref == ref_to_check
  merge_bases = `git merge-base #{rev_old} #{rev_new}`.strip.split(/\s+/)
  unless $?.success? and merge_bases.length == 1
    STDERR.puts "No unique merge base found between #{rev_old} and #{rev_new}"
    exit(1)
  end
  rev_list_output = `git rev-list --parents #{merge_bases[0]}..#{rev_new}`
  list_of_revs_with_parents = rev_list_output.strip.split(/[\r\n]+/)
  list_of_revs_with_parents.each do |line|
    rev_with_parents = line.strip.split(/\s+/)
    if rev_with_parents.length > 2      
      parents = rev_with_parents.slice(1,rev_with_parents.length)
      # The question says to permit non-linear history if the merge is
      # from another branch in the central repository, so check
      # whether that's the case.  (If you just want to prevent all
      # pushes that add non-linear history, just exit with error
      # here.)
      any_parent_not_on_any_branch = false
      parents.each do |p|
        branches = `git branch --contains #{p} 2> /dev/null`
        if $?.success? and ! branches.strip.empty?
          STDERR.puts "More than one parent of commit #{rev_with_parents[0]}"
          STDERR.puts "... but parent #{p} is on branches:"
          STDERR.puts branches
        else
          STDERR.puts "Parent #{p} not found on any other"
          STDERR.puts "branch in this repository"
          any_parent_not_on_any_branch = true
          break
        end
      end
      if any_parent_not_on_any_branch
        STDERR.puts "Refusing push, since it would create non-linear history"
        STDERR.puts "for #{ref} and the merges don't just involve commits on"
        STDERR.puts "other branches in this repository."
        exit(2)
      end
    end
  end
end

Я надеюсь, что это будет полезно.

10
ответ дан 4 December 2019 в 21:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: