Git development
 help / color / mirror / Atom feed
* Moving a topic branch forward: rebase vs. resolve
From: Marc Singer @ 2006-07-06 21:10 UTC (permalink / raw)
  To: Git Mailing List

In moving a topic branch forward from about 2.6.16 to 2.6.18-rc1, I'm
finding little solace in either rebase or resolve.


  REBASE

Rebase is an attractive method as it preserves the change history,
though in the end the only interesting bits are those that are merged
with master.  


  --1---2----3---4   master
     \
      --A--B--C      topic


In rebasing ABC at 4, it looks like git is applying each patch in
turn.  While this is strictly correct, it can make for a tedious merge
if both A and C modify the same piece of code *and* if revision 2
makes both A and C merge with conflicts.  The result was an exhausting
march through the change sets.


  RESOLVE

So, I tried resolve which I would expect to apply the other direction,
merging 234 onto C.  git-resolve finishes in a single pass leaving
conflict markers in a number of files.  However, some of these are
unexpected, conflicts in files that I've not and which I'd expect to
merge cleanly.  For example

    diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
    index 2975291..fea24ba 100644
    --- a/Documentation/DocBook/Makefile
    +++ b/Documentation/DocBook/Makefile
    @@ -2,15 +2,21 @@ ###
     # This makefile is used to generate the kernel documentation,
     # primarily based on in-line comments in various source files.
     # See Documentation/kernel-doc-nano-HOWTO.txt for instruction in how
    -# to ducument the SRC - and how to read it.
    +# to document the SRC - and how to read it.
     # To add a new book the only step required is to add the book to the
     # list of DOCBOOKS.

     DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \
		kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
		procfs-guide.xml writing_usb_driver.xml \
    +<<<<<<< .merge_file_arWYZk
		kernel-api.xml journal-api.xml lsm.xml usb.xml \
		gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml
    +=======
    +           kernel-api.xml journal-api.xml lsm.xml usb.xml \
    +           gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
    +           genericirq.xml
    +>>>>>>> .merge_file_G8cSmh


We have a spelling fix and the addition of genericirq.xml.  What would
cause these sorts of conflicts?  Is there someting I can do to
eliminate them or resolve them properly?

Cheers.

^ permalink raw reply

* Re: qgit idea: marking refs (heads and tags)
From: Marco Costalba @ 2006-07-06 18:39 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git
In-Reply-To: <e8dnst$pvh$1@sea.gmane.org>

On 7/4/06, Jakub Narebski <jnareb@gmail.com> wrote:
>
> >> And also somewhat (but to much lesser extent) showing explicitely sha1-ids
> >> for commit, parents, tree, referenced object (in tag), to copy'n'paste to
> >> shell.
> >
> > Something as a typical browser "copy selected link" context menu entry?
>
> Yes, "copy sha1 of selected link" would be nice.
>

Patch pushed to public repo (git.kernel.org/pub/scm/qgit/qgit.git)

   Marco

^ permalink raw reply

* Re: comparing file contents in is_exact_match?
From: Martin Waitz @ 2006-07-06 17:55 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vwtar89wy.fsf@assigned-by-dhcp.cox.net>

[-- Attachment #1: Type: text/plain, Size: 275 bytes --]

hoi :)

On Thu, Jul 06, 2006 at 12:33:33AM -0700, Junio C Hamano wrote:
> Although I am not sure how much this would help with a regular
> workload, maybe something like this untested patch might help
> your situation?

works perfectly!
Thanks!

-- 
Martin Waitz

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* [ANNOUNCE] ClearCase UCM -> git converter
From: Rutger Nijlunsing @ 2006-07-06 17:36 UTC (permalink / raw)
  To: git

[-- Attachment #1: Type: text/plain, Size: 1483 bytes --]

Hi,

Find attached a ClearCase UCM -> git converter.

While UCM does have branches and so on, this importer imports one
stream. Since UCM is somewhat like an expensive CVS, it is quite
difficult to retrieve more information from UCM in a useful way: the
concept are just too poluted.

Features:
  - Author files support to map ClearCase usernames to git user names
  - Incrementally import one ClearCase UCM stream into git.
    Just rerun the script when new baselines were created.
  - Handles composite baselines
  - Auto-detection of VOB, stream, rules to load, .. as much
    as possible.
  - Auto repack after a lot of objects have been generated
  - Should be able to pick up where it left after an interruption.

HOWEVER, it is Windows only currently since I don't have a cleartool
unix client. It should not be too hard to convert though, since it
uses the normal 'cleartool' command line client to retrieve all
information.

Usage:

Just have your stream-to-be-converted running at, say, m:\mystream_int
(most likely an integration stream), and say something like:

	git-ucmimport m:\mystream_int c:\mystream_git

...and hopefully it should detect all configuration items and start
converting.

Can also be found at http://www.wingding.demon.nl .

Rutger.

-- 
Rutger Nijlunsing ---------------------------------- eludias ed dse.nl
never attribute to a conspiracy which can be explained by incompetence
----------------------------------------------------------------------

[-- Attachment #2: git-ucmimport.rb --]
[-- Type: text/plain, Size: 20028 bytes --]

#!/usr/bin/env ruby

# ClearCase UCM -> git importer.
#
# Imports the baselines of _one_ stream into a Git repository.
#
# Features:
#   - Author files support to map ClearCase usernames to git user names
#   - Incrementally import one ClearCase UCM stream into git.
#     Just rerun the script when new baselines were created.
#   - Handles composite baselines
#   - Auto-detection of VOB, stream, rules to load, .. as much
#     as possible.
#   - Auto repack after a lot of objects have been generated
#   - Should be able to pick up where it left after an interrruption.
#
# Assumptions:
#   - Works on Windows for me(TM). Not tested on Unix.
#
# Discussion:
# Importing the whole tree of streams (branches) of UCM into git is
# next to impossible. UCM has the concepts of 'activities' which
# contain versions of changed files, and a set of activities is
# delivered as a changeset. So far so good. However, activities may be
# reused (even over changeset boundary) and may be interleaved with
# each other. This makes it infeasible to map activities or changesets
# on git commits, which is a much nicer concept.
#
# 2006 Rutger Nijlunsing <git-ucmimport@tux.tmfweb.nl>

############################## Config documentation.
# Don't change those; just use the command line switches to set them.
# Section below is mainly for documentation purposes. ;)

# ClearCase: Directory with existing Dynamic view on integration
# stream to import. Probably a subdirectory on M:\, or under /view
$int_view_dir = ""

# Location of snapshot view on substream of integration stream. We are
# going to rebase this stream to a newer version in int_view, and then
# check in the result.
$sub_view_dir = ""

# Baseline in parent stream to start importing at if the destination
# snapshot view does not exist.
# If empty, takes first baseline.
# Use 'cleartool lsbl' in stream directory to get a list.
first_baseline = ""

# Subdirectory of $sub_view_dir to generate git repository at.  Only
# files in this directory or lower are added. This can be used when a
# common subdirectory is always added to the paths (which is common in
# ClearCase). If unsure, leave empty.
$sub_root = ""

# Filename with author mapping from ClearCase to Git. Leave empty ("")
# to have no mapping and use the ClearCase names.
# Format of file is lines containing:
#   'cc_author_name=Real Name <email@domain.com>'
$ucm_authors_file = ""

# Server Storage Location for the view storage directory.
# This is the same as can be found in the GUI:
#   ClearCase Explorer -> Join Project -> Next -> Next -> Next ->
#     Advanced Options -> [x] Use server storage location,
# and then the 'name' column of that table.
# Use empty string ("") for default.
stgloc = "ADVIEWS"

##############################

# Include required standard Ruby libraries
require 'find'
require 'fileutils'
require 'time'
require 'optparse'
require 'ostruct'

$VERBOSE = true
$verbose = true

def die(*txt); puts txt.flatten.join("\n"); exit 1; end

def read_ucm_authors(authors_filename)
  users = {}
  begin
    IO.foreach(authors_filename) { |line|
      if line =~ %r{^(\S+?)\s*=\s*(.+?)\s*<(.+)>\s*$}
        user, name, email = $1, $2, $3
        users[user] = [name, email]
      end
    }
  rescue Errno::ENOENT, Errno::EACCES
    die("Could not read #{authors_filename}: #{$!}")
  end
  if $verbose
    puts "Read #{users.size} authors from #{authors_filename}"
  end
  return users
end

def write_ucm_authors(users, authors_filename)
  begin
    File.open(authors_filename, "wb") { |io|
      users.keys.sort.each { |user|
        io.puts "#{user} = #{users[user][0]} <#{users[user][1]}>"
      }
    }
    if $verbose
      puts "Wrote #{users.size} authors to #{authors_filename}"
    end
  rescue Errno::EACCES
    die("Could not write #{authors_filename}: #{$!}")
  end
end

def read_write_ucm_authors
  # Maping from ClearCase author name to full name and email
  default_ucm_authors_file = "#{$git_dir}/ucm-authors"
  $users = File.readable?(default_ucm_authors_file) ?
  read_ucm_authors(default_ucm_authors_file) : {}
  # If authors file explicitly given, add
  if $ucm_authors_file && $ucm_authors_file != ""
    users_to_add = read_ucm_authors($ucm_authors_file)
    if users_to_add.size > 0
      $users.merge!(users_to_add) 
      write_ucm_authors($users, default_ucm_authors_file)
    end
  end
end

module Shell
  # Escape string string so that it is parsed to the string itself
  # Compare to Regexp.escape .
  def self.escape(string)
    (string !~ %r{[ "]}i && string != "") ? 
      string : '"' + string.gsub(%r{(["])}i, '\\\\\1') + '"'
  end if not defined? self.escape
end

# Run 'cleartool' and filter the output.
def system_filter_output(cmd, may_fail)
  no_merge_required = false
  hijacked = []
  p cmd
  File.popen("#{cmd} 2>&1", "rb") { |io|
    while line = io.gets
      line = line.rstrip
      next if line =~ %r{^[.]*$}
      next if line =~ %r{^End dir }
      next if line =~ %r{^Processing dir }
      next if line =~ %r{^Done loading }
      next if line =~ %r{^Log has been written to }
      next if line =~ %r{^Making dir } # Only interested in files...
      line = line.
	sub(%r{^Loading }, "+ ").
	sub(%r{^Unloaded }, "- ")
      no_merge_required = true if line =~ %r{^No versions require merging}
      if line =~ %r{^Keeping hijacked object "(.*)"}
	hijacked << $1
      else
	raise if line =~ %r{hijacked}
      end
      puts line
    end
  }
  # Some hijacked files might be left. Update them manually
  hijacked.each { |f|
    puts "Unhijacking #{f}"
    safe_system("cleartool update -overwrite #{Shell.escape(f)}")
  }
  ok = no_merge_required
  if !ok && !may_fail
    die(
	"!!! View at #{Dir.pwd} is not clean.",
	"!!! No checkout out files, hijacked files etc. may be present.",
	"!!! Restore the view (undo hijacking, undo checkouts etc.) and retry."
    )
  end
  return ok
end

def skip(*cmd); puts "Skipping #{cmd.inspect}"; end

# Run a command with its arguments.
# When cmd is an array, a boolean indicates whether the next argument should
# be emitted or not.
def safe_system(*cmd)
  emit = true
  cmdline = [cmd].flatten.collect { |arg|
    if (arg == true) || (arg == false)
      emit = arg
      arg = nil
    else
      arg = nil if !emit
      emit = true
    end
    arg.to_s
  }.join(" ")
  puts cmdline if $verbose
  system(cmdline)
  if $? != 0
    puts cmdline if !$verbose
    puts "!!! Command returned non-zero exit code: #{$?}"
    puts "!!! Working dir: #{Dir.pwd}"
    exit $?
  end
end

def safe_popen(cmd, mode = "w+", &callback)
  puts "|" + cmd if $verbose
  res = IO.popen(cmd, mode, &callback)
  if $? != 0
    puts cmd if !$verbose
    puts "!!! Command returned non-zero exit code: #{$?}"
    puts "!!! Working dir: #{Dir.pwd}"
    exit $?
  end
  return res
end

# Returns all rules loaded in the current directory
def read_loaded_rules
  rules = {}
  File.popen("cleartool catcs", "rb") { |io|
    while line = io.gets
      rules[$1] = true if line =~ %r{^element "\[[0-9a-f]{32}=(.*)\].*\" }
    end
  }
  rules = rules.keys
  return rules
end

class Activity
  attr_accessor :id, :author, :comment

  def is_activity; @id !~ %r{^(deliver|rebase)\.}; end

  def initialize(id, author, comment)
    @id = id
    @author = author
    @comment = comment
  end

  def hash; @id.hash; end
  def eql?(other); @id == other.id; end
end

# A baseline of a stream
class Baseline
  attr_reader :name		# Name of baseline
  attr_reader :date		# Date of creation of baseline
  attr_reader :author		# User who created the baseline
  attr_reader :comment
  attr_reader :children		# For composite baselines
  attr_reader :parent		# For non-composite baselines
  attr_accessor :component	# String

  def initialize(name, date, author, comment)
    @name = name
    @date = date
    @author = author
    @comment = comment
    @children = []
    @parent = nil
  end
  
  def set_parent(b); @parent = b; b.add_child(self); end
  def add_child(baseline); @children << baseline; end

  # Returns self and all children (recursively)
  def children_recursive
    res = [self]
    children.each { |c| res += c.children_recursive }
    return res
  end
end

# Make sure .git exists and save the state
def git_init_db
  Dir.chdir($git_root)
  if !File.directory?($git_dir)
    puts "\n=== Creating initial git repository at #{$git_root}"
    safe_system("git init-db")
    if !File.directory?($git_dir)
      die("!!! Could not create git repo at #{$git_root}")
    end
  end
  save_state
end

def git_commit(baseline, msg)
  Dir.chdir($sub_view_dir)
  puts "\n=== Removing ClearCase left-over files..."
  Find.find(".") { |elem|
    if elem =~ %r{\.(contrib|keep|renamed|unloaded|loading|mkelem)(\.\d+)?$} ||
	elem =~ %r{\.(updt|stackdump)$}
      puts "Removing #{elem}"
      FileUtils.rm_rf(elem)
    end
  }

  Dir.chdir($git_root)
  puts "\n=== Adding files to git"
  safe_system("git add .")

  author = baseline.author
  email = nil
  author, email = $users[author] if $users[author]
  author ||= "unknown"
  email ||= "unknown"

  ENV['GIT_AUTHOR_NAME'] = ENV['GIT_COMMITTER_NAME'] = author
  ENV['GIT_AUTHOR_EMAIL'] = ENV['GIT_COMMITTER_EMAIL'] = email
  date = baseline.date
  if date
    puts "Date: #{date}"
    ENV['GIT_AUTHOR_DATE'] = ENV['GIT_COMMITTER_DATE'] =
      date.strftime("+0000 %Y-%m-%d %H:%M:%S")
  else
    ENV.delete('GIT_AUTHOR_DATE')
    ENV.delete('GIT_COMMITTER_DATE')
  end

  puts "\n=== Committing new version to git"
  puts "Commit message:"
  puts msg
  # 'git commit' might fail if no data is added, so no safe_popen()
  cmd = "git commit --no-verify -F - --all"
  File.popen(cmd, "wb") { |io|
    io.print msg
  }

  puts "\n=== Tagging baseline in git"
  system("git tag -f #{baseline.name}")
end

$state_version = "20060706"

# Load state. Returns true in case of succes.
def load_state
  begin
    state = File.open($state, "rb") { |io| Marshal.load(io) }
    if state.version != $state_version
      die(
        "!!! Previous state has different version (#{state.version}) ",
        "!!! than this git-ucmimport version (#{$state_version})"
      )
    else
      $int_view_dir = state.int_view_dir
      $sub_view_dir = state.sub_view_dir
      $sub_root = state.sub_root
      return true
    end
  rescue Errno::ENOENT
  end
  return false
end

def save_state
  File.open($state + ".new", "wb") { |io|
    state = OpenStruct.new
    state.version = $state_version
    state.int_view_dir = $int_view_dir
    state.sub_view_dir = $sub_view_dir
    state.sub_root = $sub_root
    io.write(Marshal.dump(state))
  }
  # Rename atomically new state into _the_ state
  File.rename($state + ".new", $state)
end

######################################## Start of main

# Make sure Cygwin is in front of path. Otherwise we might fail
# if other Unix toolkits (like NutCracker) are simultanously installed.
ENV['PATH'] = "c:\\cygwin\\bin;" + ENV['PATH']

$state = ".git/git-ucmimport.state"
state_loaded = false
state_loaded ||= load_state if File.exists?($state)

puts "ClearCase UCM -> git importer"
puts "(c)2006 R. Nijlunsing <git-ucmimport@tux.tmfweb.nl>"
puts "License: LGPL."
puts
$opts = OptionParser.new
$opts.banner = %q{Usage:
  git-ucmimport [dynamic view to import] [dir to export to]
     For the initial conversion.

  git-ucmimport
     From the git repository to incrementally convert.

Example:
  git-ucmimport --authors-file c:\\temp\\authors m:\\jparser_int c:\\jparser_git
  ...to import the stream of view 'jparser_int' which is started at
  m:\\jparser_int into newly-generated stream, view and directory at
  c:\\jparser_git .  c:\\temp\\authors contains the usernames mapping.
  c:\\jparser_git will both be a UCM view as well as an git repo, but will
  be read-only! So to develop against the converted archive, use 'git clone'.

  To convert the view incrementally, go to the root of the git repository
  (which contains the '.git' directory), and call 'git-ucmimport' without
  any parameters. In this example case that would be from c:\\jparser_git .

  For more information regarding the options, read the top of this script.

}
$opts.on("--help", "-h", "This usage") { puts $opts; exit 1 }
$opts.on(
  "--authors-file FILE", "-A",
  "Add file with mapping from ClearCase user", "to git author"
) { |f| $ucm_authors_file = File.expand_path(f) }
$opts.on("\nOptions for first-time import:")
$opts.on(
  "--stgloc LOCATION",
  "Server Storage Location for the view",
  "storage directory [chosen by UCM]"
) { |s| stgloc = s }
$opts.on(
  "--first-baseline BASELINE",
  "Start importing at given baseline", "[oldest baseline]"
) { |bl| first_baseline = bl }
$opts.on(
  "--root DIRINREPO",
  "Make given directory the root of the git", "repository"
) { |sr| $sub_root = sr }
$opts.on("")
begin
  $opts.parse!(ARGV)
rescue OptionParser::InvalidOption
  die("!!! Invalid option", $opts)
end

if !state_loaded
  if ARGV.size != 2
    puts $opts
    die("!!! Need at least the import and export directory")
  end
  $int_view_dir, $sub_view_dir = ARGV
end

# Git: Location of git archive
$git_root = $sub_view_dir
$git_root += "/" + $sub_root if $sub_root && $sub_root != ""
$git_dir = "#{$git_root}/.git"
$state = "#{$git_dir}/git-ucmimport.state"

puts "UCM Source:      Dynamic view at \"#{$int_view_dir}\""
puts "UCM Mirror repo: Snapshot view at \"#{$sub_view_dir}\""
puts "git repo:        At \"#{$git_root}\""
puts "Start baseline:  At #{first_baseline}" if first_baseline && first_baseline != ""
puts

# Check for existance of git in $PATH
safe_system("git version")

if !File.directory?($int_view_dir)
  die(
      "!!! Cannot find \"#{$int_view_dir}\",",
      "!!! which should contain integration view directory.",
      "!!! Did you start your view?"
  )
end

puts "\n=== Retrieving all current baselines to import"
Dir.chdir($int_view_dir)
vob = nil			# String: VOB
int_stream = nil		# String: name of stream
baselines = {}			# From name to Baseline
baseline = nil
#File.open("c:\\temp\\lsbl.memberof", "rb") { |io|
File.popen("cleartool lsbl -member_of", "rb") { |io|
  while line = io.gets
    line = line.rstrip
    if line =~ %r{^([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+\"(.*)\"$}
      # New baseline found
      date, name, author, comment = $1, $2, $3, $4
      $VERBOSE = false		# Time.parse warns about year...
      baseline = Baseline.new(name, Time.parse(date), author, comment)
      $VERBOSE = true
      $stderr.print "." if baselines.size % 10 == 0
      baselines[name] = baseline
    elsif line =~ %r{^  component: ([^ @]+)@([^ ]+)$}
      baseline.component = $1
      vob = $2
    elsif line =~ %r{^  stream: ([^ @]+)@([^ ]+)$}
      int_stream = $1
    elsif line =~ %r{^    ([^ @]+)@([^ ]+) \(.*\)}
      # 'member of:' line    
      baseline.set_parent(baselines[$1])
    end
  end
}
$stderr.puts
# We only need to keep the root of all composite baselines sorted on time.
baselines =
  baselines.keys.
  find_all { |n| baselines[n].parent.nil? }. # Only keep root baselines
  collect { |n| baselines[n] }.
  sort_by { |b| b.date }	# Sort them on date
puts "Found #{baselines.size} (composite) baselines."

components = baselines.collect { |b| b.component }.uniq
if components.size != 1
  die(
      "!!! Not all baselines belong to the same component!",
      "!!! Too afraid to continue.",
      "!!! Components found: #{components.inspect}"
  )
end

if !first_baseline || first_baseline == ""
  first_baseline = baselines[0].name
end
first_baseline_idx = nil
baselines.each_with_index { |b, idx|
  first_baseline_idx = idx if b.name == first_baseline
}
if !first_baseline_idx
  die("!!! Could not find first_baseline with name \"#{first_baseline}\"")
end

# Create destination stream if needed
if !File.exist?($sub_view_dir)
  puts "\n=== Reading all rules loaded in stream to import"
  Dir.chdir($int_view_dir)
  loaded_rules = read_loaded_rules
  puts "Currently loaded rules: #{loaded_rules.inspect}"

  sub_stream = File.basename($sub_view_dir)
  puts "\n=== Creating read-only stream '#{sub_stream}'"
  safe_system(
    "cleartool mkstream",
    "-in stream:#{int_stream}@#{vob}",
    "-readonly",
    "-baseline baseline:#{first_baseline}",
    "#{sub_stream}@#{vob}"
  )

  Dir.chdir(File.dirname($sub_view_dir))
  puts "\n=== Creating snapshot view at #{$sub_view_dir}"
  safe_system(
    "cleartool mkview",
    "-snapshot -ptime",
    "-tag #{sub_stream}",
    "-stream #{sub_stream}@#{vob}",
    stgloc && stgloc != "", "-stgloc #{stgloc}",
    sub_stream
  )
  $sub_view_dir = Dir.pwd + "/" + sub_stream

  puts "\n=== Load rules and update view"
  Dir.chdir($sub_view_dir)
  loaded_rules.each { |rule|
    system_filter_output("cleartool update -overwrite -add_loadrules #{rule[1..-1]}", true)
  }

  git_init_db
  read_write_ucm_authors
  git_commit(baselines[first_baseline_idx], "Initial commit")
else
  read_write_ucm_authors
  puts "\n=== Updating view to be sure snapshot view matches UCM contents"
  Dir.chdir($sub_view_dir)
  system_filter_output("cleartool update -overwrite", true)
end

git_init_db

puts "\n=== Finding current baseline"
Dir.chdir($sub_view_dir)
cmd = "cleartool lsstream -long -obsolete"
p cmd
lsstream = `#{cmd}`
if lsstream !~ %r{^\s+foundation baselines:\s+([^@]+)@}m
  puts lsstream
  die("!!! Could not retrieve current baseline")
end
current_baseline = $1
puts "Current baseline: #{current_baseline}"
if current_baseline =~ %r{INITIAL$}
  die(
      "!!! Current baseline should be newer than INITIAL",
      "!!! Please rebase #{$sub_view_dir} to a newer baseline."
  )
end

current_baseline_idx = nil
baselines.each_with_index { |b, idx|
  current_baseline_idx = idx if b.name == current_baseline
}

if !current_baseline_idx
  die(
    "!!! Did not find our current baseline in Integration Stream.",
    "!!! Make sure that stream of view #{$sub_view_dir} is really",
    "!!! a child of stream of view #{$int_view_dir}"
  )
end

baselines_to_commit = baselines[current_baseline_idx + 1 .. -1]

if baselines_to_commit.empty?
  puts "\nNothing to do, already up-to-date."
  exit 0
end

puts "Got #{baselines_to_commit.size} baselines to convert to git commits"

puts "\n=== Abort previous rebase attempt (if any)."
Dir.chdir($sub_view_dir)
system_filter_output("cleartool rebase -cancel -force", true)

baselines_to_commit.each_with_index { |baseline, idx|
  # If a lot of loose objects in Git, repack.
  # Counts numbers of 'objects' directories, 256 max.
  Dir.chdir($git_root)
  if Dir[".git/objects/??"].size >= 253
    puts "\n=== Repacking."
    # To err is non-fatal, so no safe_system is needed.
    system("git repack -d")
  end

  puts
  puts "\n=== [#{idx + 1}/#{baselines_to_commit.size}]"
  puts "=== Reading effect of rebasing of #{$sub_view_dir} to baseline #{baseline.name}"
  Dir.chdir($sub_view_dir)
  activities = []

  # In the composite baseline, we get little information about the
  # activities we bring in. Therefore, ask all contained baselines
  # about the activities it contains.
  baseline_names = baseline.
    children_recursive.collect { |cbl| cbl.name }.join(",")
  cmd = "cleartool rebase -preview -baseline #{baseline_names}"
  safe_popen(cmd, "rb") { |io|
    while line = io.gets
      line = line.rstrip
      if line =~ %r{^\tactivity:([^\t]*)\t([^\t]*)\t\"(.*)\"$}
	id, author, comment = $1, $2, $3
	activities << Activity.new(id, author, comment)
      end
    end
  }
  activities = activities.uniq

  if activities.empty?
    puts "? New baseline contains no new activities, skipping"
    next
  end

  puts "Will retrieve activities:"
  activities.each { |a|
    puts "  #{a.author} #{a.id}"
  }

  system_filter_output("cleartool rebase -qall -baseline #{baseline.name}", false)

  subject =
    activities.find_all { |a| a.is_activity }.
    collect { |a| a.comment }.join(" / ") + "\n\n"
  msg = subject +
    activities.collect { |a| "#{a.comment}\nActivity: #{a.id}\n\n" }.join("")
  git_commit(baseline, msg)

  puts "\n=== Completing ClearCase UCM rebase."
  system_filter_output("cleartool rebase -complete", true)
}

^ permalink raw reply

* Re: Does Git run on Windows ?
From: Aaron Gray @ 2006-07-06 17:18 UTC (permalink / raw)
  To: Git Mailing List
In-Reply-To: <46a038f90607051956w72c5e662g72feb242795e61c4@mail.gmail.com>

>> This maybe the crunch and reason to use CVS for now :(?)
>
> If you are only supporting some users on Windows, you may be able to
> use git-cvsserver for them. Looks like a cvsserver but it is a GIT
> repository ;-)

Thanks. This looks like the best option. Run Git, GitWeb, and git-cvsserver
on our Linux server. Allowing Windows users to connect via CVS and GitWeb.
Nice, looks like the right solution, best of both worlds.

Running Cygwin, Perl, and Python is not really something I could expect of
Windows programmers.

Many thanks,

Aaron

^ permalink raw reply

* More fully-fleshed-out builtin "git prune"
From: Linus Torvalds @ 2006-07-06 17:16 UTC (permalink / raw)
  To: Junio C Hamano, Git Mailing List


This actually removes the objects to be pruned, unless you specify "-n" 
(at which point it will just tell you which files it would prune).

This doesn't do the pack-file pruning that the shell-script used to do, 
but if somebody really wants to, they could add it easily enough. I wonder 
how useful it is, though, considering that "git repack -a -d" is just a 
lot more efficient and generates a better end result.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---

I've tested this somewhat, including the "object only reachable through 
the index" case, and used it to do a few real prunes. It's a lot faster 
(because it only does the trivial reachability part), and it all _seems_ 
fine and the code is fairly obvious and certainly simple enough. 

That said, this is "git prune". Getting things wrong here would be bad. 
People should double- and triple-check this.

 Makefile        |    4 -
 builtin-prune.c |  259 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 builtin.h       |    2 
 git-prune.sh    |   44 ---------
 git.c           |    3 -
 5 files changed, 265 insertions(+), 47 deletions(-)

diff --git a/Makefile b/Makefile
index 7fa4a27..d355622 100644
--- a/Makefile
+++ b/Makefile
@@ -120,7 +120,7 @@ SCRIPT_SH = \
 	git-fetch.sh \
 	git-ls-remote.sh \
 	git-merge-one-file.sh git-parse-remote.sh \
-	git-prune.sh git-pull.sh git-rebase.sh \
+	git-pull.sh git-rebase.sh \
 	git-repack.sh git-request-pull.sh git-reset.sh \
 	git-resolve.sh git-revert.sh git-sh-setup.sh \
 	git-tag.sh git-verify-tag.sh \
@@ -230,7 +230,7 @@ BUILTIN_OBJS = \
 	builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
 	builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \
 	builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o \
-	builtin-update-ref.o builtin-fmt-merge-msg.o
+	builtin-update-ref.o builtin-fmt-merge-msg.o builtin-prune.o
 
 GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
 LIBS = $(GITLIBS) -lz
diff --git a/builtin-prune.c b/builtin-prune.c
new file mode 100644
index 0000000..fc55b76
--- /dev/null
+++ b/builtin-prune.c
@@ -0,0 +1,259 @@
+#include "cache.h"
+#include "refs.h"
+#include "tag.h"
+#include "commit.h"
+#include "tree.h"
+#include "blob.h"
+#include "tree-walk.h"
+#include "diff.h"
+#include "revision.h"
+#include "builtin.h"
+#include "cache-tree.h"
+
+static const char prune_usage[] = "git prune [-n]";
+static int show_only = 0;
+static struct rev_info revs;
+
+static int prune_object(char *path, const char *filename, const unsigned char *sha1)
+{
+	if (show_only) {
+		printf("would prune %s/%s\n", path, filename);
+		return 0;
+	}
+	unlink(mkpath("%s/%s", path, filename));
+	rmdir(path);
+	return 0;
+}
+
+static int prune_dir(int i, char *path)
+{
+	DIR *dir = opendir(path);
+	struct dirent *de;
+
+	if (!dir)
+		return 0;
+
+	while ((de = readdir(dir)) != NULL) {
+		char name[100];
+		unsigned char sha1[20];
+		int len = strlen(de->d_name);
+
+		switch (len) {
+		case 2:
+			if (de->d_name[1] != '.')
+				break;
+		case 1:
+			if (de->d_name[0] != '.')
+				break;
+			continue;
+		case 38:
+			sprintf(name, "%02x", i);
+			memcpy(name+2, de->d_name, len+1);
+			if (get_sha1_hex(name, sha1) < 0)
+				break;
+
+			/*
+			 * Do we know about this object?
+			 * It must have been reachable
+			 */
+			if (lookup_object(sha1))
+				continue;
+
+			prune_object(path, de->d_name, sha1);
+			continue;
+		}
+		fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
+	}
+	closedir(dir);
+	return 0;
+}
+
+static void prune_object_dir(const char *path)
+{
+	int i;
+	for (i = 0; i < 256; i++) {
+		static char dir[4096];
+		sprintf(dir, "%s/%02x", path, i);
+		prune_dir(i, dir);
+	}
+}
+
+static void process_blob(struct blob *blob,
+			 struct object_array *p,
+			 struct name_path *path,
+			 const char *name)
+{
+	struct object *obj = &blob->object;
+
+	if (obj->flags & SEEN)
+		return;
+	obj->flags |= SEEN;
+	/* Nothing to do, really .. The blob lookup was the important part */
+}
+
+static void process_tree(struct tree *tree,
+			 struct object_array *p,
+			 struct name_path *path,
+			 const char *name)
+{
+	struct object *obj = &tree->object;
+	struct tree_desc desc;
+	struct name_entry entry;
+	struct name_path me;
+
+	if (obj->flags & SEEN)
+		return;
+	obj->flags |= SEEN;
+	if (parse_tree(tree) < 0)
+		die("bad tree object %s", sha1_to_hex(obj->sha1));
+	name = strdup(name);
+	add_object(obj, p, path, name);
+	me.up = path;
+	me.elem = name;
+	me.elem_len = strlen(name);
+
+	desc.buf = tree->buffer;
+	desc.size = tree->size;
+
+	while (tree_entry(&desc, &entry)) {
+		if (S_ISDIR(entry.mode))
+			process_tree(lookup_tree(entry.sha1), p, &me, entry.path);
+		else
+			process_blob(lookup_blob(entry.sha1), p, &me, entry.path);
+	}
+	free(tree->buffer);
+	tree->buffer = NULL;
+}
+
+static void process_tag(struct tag *tag, struct object_array *p, const char *name)
+{
+	struct object *obj = &tag->object;
+	struct name_path me;
+
+	if (obj->flags & SEEN)
+		return;
+	obj->flags |= SEEN;
+
+	me.up = NULL;
+	me.elem = "tag:/";
+	me.elem_len = 5;
+
+	if (parse_tag(tag) < 0)
+		die("bad tag object %s", sha1_to_hex(obj->sha1));
+	add_object(tag->tagged, p, NULL, name);
+}
+
+static void walk_commit_list(struct rev_info *revs)
+{
+	int i;
+	struct commit *commit;
+	struct object_array objects = { 0, 0, NULL };
+
+	/* Walk all commits, process their trees */
+	while ((commit = get_revision(revs)) != NULL)
+		process_tree(commit->tree, &objects, NULL, "");
+
+	/* Then walk all the pending objects, recursively processing them too */
+	for (i = 0; i < revs->pending.nr; i++) {
+		struct object_array_entry *pending = revs->pending.objects + i;
+		struct object *obj = pending->item;
+		const char *name = pending->name;
+		if (obj->type == TYPE_TAG) {
+			process_tag((struct tag *) obj, &objects, name);
+			continue;
+		}
+		if (obj->type == TYPE_TREE) {
+			process_tree((struct tree *)obj, &objects, NULL, name);
+			continue;
+		}
+		if (obj->type == TYPE_BLOB) {
+			process_blob((struct blob *)obj, &objects, NULL, name);
+			continue;
+		}
+		die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name);
+	}
+}
+
+static int add_one_ref(const char *path, const unsigned char *sha1)
+{
+	struct object *object = parse_object(sha1);
+	if (!object)
+		die("bad object ref: %s:%s", path, sha1_to_hex(sha1));
+	add_pending_object(&revs, object, "");
+	return 0;        
+}
+
+static void add_one_tree(const unsigned char *sha1)
+{
+	struct tree *tree = lookup_tree(sha1);
+	add_pending_object(&revs, &tree->object, "");
+}
+
+static void add_cache_tree(struct cache_tree *it)
+{
+	int i;
+
+	if (it->entry_count >= 0)
+		add_one_tree(it->sha1);
+	for (i = 0; i < it->subtree_nr; i++)
+		add_cache_tree(it->down[i]->cache_tree);
+}
+
+static void add_cache_refs(void)
+{
+	int i;
+
+ 	read_cache();
+	for (i = 0; i < active_nr; i++) {
+		lookup_blob(active_cache[i]->sha1);
+		/*
+		 * We could add the blobs to the pending list, but quite
+		 * frankly, we don't care. Once we've looked them up, and
+		 * added them as objects, we've really done everything 
+		 * there is to do for a blob
+		 */
+	}
+	if (active_cache_tree)
+		add_cache_tree(active_cache_tree);
+}
+
+int cmd_prune(int argc, const char **argv, char **envp)
+{
+	int i;
+
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+		if (!strcmp(arg, "-n")) {
+			show_only = 1;
+			continue;
+		}
+		usage(prune_usage);
+	}
+
+	/*
+	 * Set up revision parsing, and mark us as being interested
+	 * in all object types, not just commits.
+	 */
+	init_revisions(&revs);
+	revs.tag_objects = 1;
+	revs.blob_objects = 1;
+	revs.tree_objects = 1;
+
+	/* Add all external refs */
+	for_each_ref(add_one_ref);
+
+	/* Add all refs from the index file */
+	add_cache_refs();
+
+	/*
+	 * Set up the revision walk - this will move all commits
+	 * from the pending list to the commit walking list.
+	 */
+	prepare_revision_walk(&revs);
+
+	walk_commit_list(&revs);
+
+	prune_object_dir(get_object_directory());
+
+	return 0;
+}
diff --git a/builtin.h b/builtin.h
index d9e5483..5339d86 100644
--- a/builtin.h
+++ b/builtin.h
@@ -25,6 +25,8 @@ extern int cmd_diff(int argc, const char
 extern int cmd_format_patch(int argc, const char **argv, char **envp);
 extern int cmd_count_objects(int argc, const char **argv, char **envp);
 
+extern int cmd_prune(int argc, const char **argv, char **envp);
+
 extern int cmd_push(int argc, const char **argv, char **envp);
 extern int cmd_grep(int argc, const char **argv, char **envp);
 extern int cmd_rm(int argc, const char **argv, char **envp);
diff --git a/git-prune.sh b/git-prune.sh
deleted file mode 100755
index c5a5d29..0000000
--- a/git-prune.sh
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/sh
-
-USAGE='[-n] [--] [<head>...]'
-. git-sh-setup
-
-dryrun=
-echo=
-while case "$#" in 0) break ;; esac
-do
-    case "$1" in
-    -n) dryrun=-n echo=echo ;;
-    --) break ;;
-    -*) usage ;;
-    *)  break ;;
-    esac
-    shift;
-done
-
-sync
-case "$#" in
-0) git-fsck-objects --full --cache --unreachable ;;
-*) git-fsck-objects --full --cache --unreachable $(git-rev-parse --all) "$@" ;;
-esac |
-
-sed -ne '/unreachable /{
-    s/unreachable [^ ][^ ]* //
-    s|\(..\)|\1/|p
-}' | {
-	cd "$GIT_OBJECT_DIRECTORY" || exit
-	xargs $echo rm -f
-	rmdir 2>/dev/null [0-9a-f][0-9a-f]
-}
-
-git-prune-packed $dryrun
-
-if redundant=$(git-pack-redundant --all 2>/dev/null) && test "" != "$redundant"
-then
-	if test "" = "$dryrun"
-	then
-		echo "$redundant" | xargs rm -f
-	else
-		echo rm -f "$redundant"
-	fi
-fi
diff --git a/git.c b/git.c
index 2567301..16e37e5 100644
--- a/git.c
+++ b/git.c
@@ -188,7 +188,8 @@ static void handle_internal_command(int 
 		{ "stripspace", cmd_stripspace },
 		{ "update-index", cmd_update_index },
 		{ "update-ref", cmd_update_ref },
-		{ "fmt-merge-msg", cmd_fmt_merge_msg }
+		{ "fmt-merge-msg", cmd_fmt_merge_msg },
+		{ "prune", cmd_prune },
 	};
 	int i;
 

^ permalink raw reply related

* Re: [PATCH 1/3] configure: Add test for Perl
From: Dennis Stosberg @ 2006-07-06 15:44 UTC (permalink / raw)
  To: Alex Riesen; +Cc: git
In-Reply-To: <81b0412b0607060840g4df16edbm7df69d6c8edcc071@mail.gmail.com>

Alex Riesen wrote:

> Is it still MPlayer's?

That is being fixed in the third patch.

Regards,
Dennis

^ permalink raw reply

* Re: [PATCH 1/3] configure: Add test for Perl
From: Alex Riesen @ 2006-07-06 15:40 UTC (permalink / raw)
  To: Dennis Stosberg; +Cc: git
In-Reply-To: <20060706124025.G325584e9@leonov.stosberg.net>

On 7/6/06, Dennis Stosberg <dennis@stosberg.net> wrote:
>  Miscellaneous options:
>    --cc=COMPILER          use this C compiler to build MPlayer [gcc]

Is it still MPlayer's?

^ permalink raw reply

* Re: [PATCH 1/3] configure: Add test for Perl
From: Dennis Stosberg @ 2006-07-06 15:34 UTC (permalink / raw)
  To: Timo Hirvonen; +Cc: Matthias Lederhofer, git
In-Reply-To: <20060706172756.a42f1627.tihirvon@gmail.com>

Timo Hirvonen wrote:

>         if test -x "$1"
>         then
>                 echo "$1"
>                 return 0
>         fi

When run in the Git source directory, this will find the perl/
subdir.  If the user gives an absolute path to the perl binary,
there will be no auto-detection anyway, so I think we don't need it.

> It is not needed but might be useful if PERL is user configurable
> variable and can contain either full path or basename. For example this
> code
> 
>     test "$PROG" || PROG=prog
>     PROG=`path_find "$PROG"`
> 
> works with these cases
> 
>     $ PROG=/usr/bin/program ./configure
>     $ PROG=program-1.2 ./configure

I will add that.  For the compiler, the script already checks $CC.
I wonder whether

  --with-perl=...
  --with-python=... 

is more common (more similar to autoconf) than

  --perl=
  --python=

Regards,
Dennis

^ permalink raw reply

* Re: git on HP-UX
From: Pavel Roskin @ 2006-07-06 14:53 UTC (permalink / raw)
  To: Michal Rokos; +Cc: git
In-Reply-To: <200607060950.34558.michal.rokos@nextsoft.cz>

Hello!

On Thu, 2006-07-06 at 09:50 +0200, Michal Rokos wrote:
> Hello,
> 
> I needed following changes in order to make git compile on HP-UX:
> +ifeq ($(uname_S),HP-UX)
> +	NO_IPV6 = YesPlease
> +	NO_CURL = YesPlease

Is there any fundamental problem with curl and IPv6 on HP-UX?  I don't
think so.

Sorry for using your path as a bad example, but the appearance of such
patches is a perfect argument for a real configure script.  If we
continue patching Makefile, we'll drown in such conditionals.  And the
worst thing is, nobody without access to an HP-UX system will know why
IPv6 isn't working there.  Makefile will become a pile of code that
cannot be easily verified for correctness.

Autoconf based tests can actually test if certain code can be compiled
and linked.  If HP-UX fixed IPv6, the test would enable it.  If some
genius manages to compile curl on HP-UX, http support will be enabled on
that machine with no manual changes in Makefile.

I hope the Autoconf based configure is on its way to git, but I don't
see in in the "pu" branch yet.  I'm not very keen about reinventing
Autoconf and hacking a hand-made configure script.

-- 
Regards,
Pavel Roskin

^ permalink raw reply

* Re: [PATCH 1/3] configure: Add test for Perl
From: Timo Hirvonen @ 2006-07-06 14:27 UTC (permalink / raw)
  To: Matthias Lederhofer; +Cc: dennis, git
In-Reply-To: <E1FyUNT-0007Ko-JR@moooo.ath.cx>

Matthias Lederhofer <matled@gmx.net> wrote:

> This will not work with spaces in $PATH. I'd do something like this if
> cut is portable (I have only freebsd and linux to test):

This works at least with SunOS /bin/sh, dash, posh and bash.

path_find()
{
        if test -x "$1"
        then
                echo "$1"
                return 0
        fi
	_ifs="$IFS"
	IFS=:
        for i in $PATH
        do
                if test -x "$i/$1"
                then
			IFS="$_ifs"
                        echo "$i/$1"
                        return 0
                fi
        done
	IFS="$_ifs"
        return 1
}

> Is there any reason to check the current directory first? "which"
> doesn't do it for me and without ./ in the front it does not work
> (without . is not in $PATH).

It is not needed but might be useful if PERL is user configurable
variable and can contain either full path or basename. For example this
code

    test "$PROG" || PROG=prog
    PROG=`path_find "$PROG"`

works with these cases

    $ PROG=/usr/bin/program ./configure
    $ PROG=program-1.2 ./configure

-- 
http://onion.dynserv.net/~timo/

^ permalink raw reply

* Re: [PATCH 1/3] configure: Add test for Perl
From: Dennis Stosberg @ 2006-07-06 14:25 UTC (permalink / raw)
  To: git, Timo Hirvonen
In-Reply-To: <20060706141725.28115.qmail@775c2aaf180a85.315fe32.mid.smarden.org>

Gerrit Pape wrote:

> This should work with shell/builtins only, no sed/cut:
>
>  path=${PATH}:
>  while test -n "$path"; do
>    p=${path%%:*}/$1
>    test ! -x "$p" || { echo "$p"; return 0; }
>    path=${path#*:}

$ exec /bin/sh
$ uname -a
SunOS hostname 5.9 Generic_118558-25 sun4u sparc SUNW,Ultra-5_10 Solaris
$ echo ${PATH%%:*}
bad substitution
$ echo ${PATH#*:}
bad substitution

Regards,
Dennis

^ permalink raw reply

* Re: [PATCH 1/3] configure: Add test for Perl
From: Gerrit Pape @ 2006-07-06 14:17 UTC (permalink / raw)
  To: git; +Cc: Timo Hirvonen, Dennis Stosberg
In-Reply-To: <E1FyUNT-0007Ko-JR@moooo.ath.cx>

On Thu, Jul 06, 2006 at 03:58:47PM +0200, Matthias Lederhofer wrote:
> This will not work with spaces in $PATH. I'd do something like this if
> cut is portable (I have only freebsd and linux to test):

This should work with shell/builtins only, no sed/cut:

 path=${PATH}:
 while test -n "$path"; do
   p=${path%%:*}/$1
   test ! -x "$p" || { echo "$p"; return 0; }
   path=${path#*:}
 done
 test ! -x "$1" || { echo "$1" && return 0; }
 return 1

Regards, Gerrit.

^ permalink raw reply

* Re: [PATCH 1/3] configure: Add test for Perl
From: Matthias Lederhofer @ 2006-07-06 13:58 UTC (permalink / raw)
  To: Timo Hirvonen; +Cc: Dennis Stosberg, git
In-Reply-To: <20060706161011.ccc2ea1c.tihirvon@gmail.com>

> "which" isn't portable. On SunOS 5.9 "which foo" prints error message to
> stdout and returns 0.  I use this in my own configure scripts:
> 
> path_find()
> {
>         if test -x "$1"
>         then
>                 echo "$1"
>                 return 0
>         fi
>         for i in `echo $PATH | sed 's/:/ /g'`
>         do
>                 if test -x "$i/$1"
>                 then
>                         echo "$i/$1"
>                         return 0
>                 fi
>         done
>         return 1
> }

This will not work with spaces in $PATH. I'd do something like this if
cut is portable (I have only freebsd and linux to test):

path_find()
{
    path="$PATH"
    while [ "$path" != "" ]; do
        p="`echo $path | cut -d : -f 1`"
        if [ "$p" = "$path" ]; then
            path=""
        else
            path="`echo $path | cut -d : -f 2-`"
        fi
        if [ -x "$p/$1" ]; then
            echo "$p/$1"
            return 0
        fi
    done
    return 1
}

Is there any reason to check the current directory first? "which"
doesn't do it for me and without ./ in the front it does not work
(without . is not in $PATH).

^ permalink raw reply

* Re: [PATCH 1/3] configure: Add test for Perl
From: Dennis Stosberg @ 2006-07-06 13:29 UTC (permalink / raw)
  To: Timo Hirvonen; +Cc: git
In-Reply-To: <20060706161011.ccc2ea1c.tihirvon@gmail.com>

Timo Hirvonen wrote:

> "which" isn't portable. On SunOS 5.9 "which foo" prints error message to
> stdout and returns 0.  I use this in my own configure scripts:

Yes, you're right and that function looks fine.  I will resend the
patches later, but I'll wait a few hours for further comments.

Regards,
Dennis

^ permalink raw reply

* Re: [PATCH 1/3] configure: Add test for Perl
From: Timo Hirvonen @ 2006-07-06 13:10 UTC (permalink / raw)
  To: Dennis Stosberg; +Cc: git
In-Reply-To: <20060706124025.G325584e9@leonov.stosberg.net>

Dennis Stosberg <dennis@stosberg.net> wrote:

> +	echocheck "for perl"
> +	if test -z "$_perl" ; then
> +		_perl=`which perl`
> +		test "$_perl" || die "cannot find path to perl"
> +	fi
> +	echores "$_perl"

"which" isn't portable. On SunOS 5.9 "which foo" prints error message to
stdout and returns 0.  I use this in my own configure scripts:

path_find()
{
        if test -x "$1"
        then
                echo "$1"
                return 0
        fi
        for i in `echo $PATH | sed 's/:/ /g'`
        do
                if test -x "$i/$1"
                then
                        echo "$i/$1"
                        return 0
                fi
        done
        return 1
}

-- 
http://onion.dynserv.net/~timo/

^ permalink raw reply

* Re: [PATCH 1/3] configure: Add test for Perl
From: Randal L. Schwartz @ 2006-07-06 13:03 UTC (permalink / raw)
  To: Dennis Stosberg; +Cc: git
In-Reply-To: <20060706124025.G325584e9@leonov.stosberg.net>

>>>>> "Dennis" == Dennis Stosberg <dennis@stosberg.net> writes:

Dennis> +	_perl_version=`"$_perl" -e 'require 5.6.0;printf "%vd", $^V'`

perl -V:version gives you the version like:

        version='5.8.6';

nice and eval-able. :)  But you can just rely on the exit status from

        perl -e 'eval { require 5.006; 1 } or exit 1'

which will be good (0) if the perl is new enough, and bad (1) if the perl is
too old.  (Perl4 will really barf and give an error as well, but still
be an exit 1.)

-- 
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<merlyn@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!

^ permalink raw reply

* Re: git2rss --- publish changes from git-log via RSS
From: Bennett Todd @ 2006-07-06 12:53 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git
In-Reply-To: <e8elej$4sa$1@sea.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 931 bytes --]

2006-07-04T21:09:32 Jakub Narebski:
> Added to http://git.or.cz/gitwiki/InterfacesFrontendsAndTools#git2rss
> Please correct/expand the info if needed.

Thanks. But I'm not sure it belongs there. If anybody else turns out
to be interested, and we work out how to update it to pull out the
Bent-specific stuff hardcoded in it, and document the result, then
maybe. At best it might be an example someone could copy, if they
wanted to publish an rss of git-log, with some hardwired assumptions
about the log format and the archive structure. It's not based on
darcs2rss, it's a complete rewrite, and much simpler since I used
XML::RSS::SimpleGen.

> BTW. gitweb includes RSS feed, see e.g.:
>   http://www.kernel.org/git/?p=git/git.git;a=rss
>   http://www.kernel.org/git/?p=git/git.git;a=opml

Can it be used for offline generation? I don't run any CGIs on my
webserver, I re-generate bent.xml whenever I push any updates.

-Bennett

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* [PATCH 3/3] configure: Try to figure out compiler options
From: Dennis Stosberg @ 2006-07-06 12:41 UTC (permalink / raw)
  To: git

This patch adds tests to determine of what flavour the used
compiler is and sets CFLAGS and the PIC flag appropriately.

Signed-off-by: Dennis Stosberg <dennis@stosberg.net>
---
 Makefile      |    3 ++-
 config-lib.sh |   56 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile
index 4dc5379..23c784e 100644
--- a/Makefile
+++ b/Makefile
@@ -96,6 +96,7 @@ ALL_CFLAGS = $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)
 PERL_CFLAGS =
 PERL_LDFLAGS =
+PICFLAG = -fPIC
 STRIP ?= strip
 
 prefix = $(HOME)
@@ -483,7 +484,7 @@ endif
 endif
 endif
 ifdef USE_PIC
-	ALL_CFLAGS += -fPIC
+	ALL_CFLAGS += $(PICFLAG)
 endif
 ifdef NO_ACCURATE_DIFF
 	BASIC_CFLAGS += -DNO_ACCURATE_DIFF
diff --git a/config-lib.sh b/config-lib.sh
index 50ad6e9..6000ec9 100755
--- a/config-lib.sh
+++ b/config-lib.sh
@@ -35,9 +35,9 @@ compile_check() {
 	echo
 	cat "$1"
 	echo
-	echo "$_cc $CFLAGS $_inc_extra $_ld_static $_ld_extra -o $TMPO $@"
+	echo "$_cc $_cflags $_inc_extra $_ld_static $_ld_extra -o $TMPO $@"
 	rm -f "$TMPO"
-	$_cc $CFLAGS $_inc_extra $_ld_static $_ld_extra -o "$TMPO" "$@" || return $?
+	$_cc $_cflags $_inc_extra $_ld_static $_ld_extra -o "$TMPO" "$@" || return $?
 	echo
 	echo "ldd $TMPO"
 	$_ldd "$TMPO" || return $?
@@ -261,7 +261,7 @@ Installation directories:
   --gitpythondir=DIR     use this prefix for python libraries [PREFIX/share/git-core/python]
 
 Miscellaneous options:
-  --cc=COMPILER          use this C compiler to build MPlayer [gcc]
+  --cc=COMPILER          use this C compiler to build Git [cc]
   --perl=PATH            path to perl binary [autodetect]
   --python=PATH          path to python binary [autodetect]
   --target=PLATFORM      target platform (i386-linux, arm-linux, etc)
@@ -351,8 +351,8 @@ EOF
 				i[3-9]86*|x86|x86pc|k5|k6|k6_2|k6_3|k6-2|k6-3|pentium*|athlon*|i586_i686|i586-i686|BePC) host_arch=i386 ;;
 				ia64) host_arch=ia64 ;;
 				x86_64|amd64)
-				if [ -n "`$_cc -dumpmachine | sed -n '/^x86_64-/p;/^amd64-/p'`" -a \
-					-z "`echo $CFLAGS | grep -- -m32`"  ]; then
+				if [ -n "`$_cc -dumpmachine 2>/dev/null | sed -n '/^x86_64-/p;/^amd64-/p'`" -a \
+					-z "`echo $_cflags | grep -- -m32`"  ]; then
 					host_arch=x86_64
 				else
 					host_arch=i386
@@ -408,7 +408,51 @@ test_setup() {
 	TMPS="$I/git-conf-$RANDOM-$$.S"
 }
 
+cc_flavour() {
+
+	echocheck "whether cc is GCC"
+	cat > $TMPC <<EOF
+#ifndef __GNUC__
+#error Not GCC
+#endif
+int main(void) { return 0; }
+EOF
+	if cc_check ; then
+		echores "yes"
+		_cc_flavour="gcc"
+		return
+	fi
+	echores "no"
+
+	echocheck "whether cc is Sun CC"
+	cat > $TMPC <<EOF
+#ifndef __SUNPRO_C
+#error Not SUN CC
+#endif
+int main(void) { return 0; }
+EOF
+	if cc_check ; then
+		echores "yes"
+		_cc_flavour="suncc"
+		return
+	fi
+	echores "no"
+}
+
 basic_tests() {
+	_cc_flavour=unknown
+	cc_flavour
+
+	if test "$_cc_flavour" = "gcc" ; then
+		_cflags="-g -O2 -Wall"
+		_picflag="-fPIC"
+	elif test "$_cc_flavour" = "suncc"; then
+		_cflags="-g -xO3"
+		_picflag="-KPIC"
+	fi
+	test "$CFLAGS" && _cflags="$CFLAGS"
+	test "$PICFLAG" && _picflag="$PICFLAG"
+
 	echocheck "if your build environment is sane"
 	cat > $TMPC <<EOF
 int main(void) { return 0; }
@@ -457,6 +501,8 @@ write_config() {
 # -------- Generated by configure -----------
 
 CC = $_cc
+CFLAGS = $_cflags
+PICFLAG = $_picflag
 PERL_PATH = $_perl
 PYTHON_PATH = $_python
 INSTALL = $_install
-- 
1.4.1

^ permalink raw reply related

* [PATCH 1/3] configure: Add test for Perl
From: Dennis Stosberg @ 2006-07-06 12:40 UTC (permalink / raw)
  To: git

This patch adds two tests to the configuration script. The first
one tries to find a perl binary in the path.  The second one checks
whether the found perl is of a sufficient version.

It also adds a --perl=/path parameter to override the autodetection
of the perl binary.

Signed-off-by: Dennis Stosberg <dennis@stosberg.net>
---
 config-lib.sh |   19 ++++++++++++++++++-
 1 files changed, 18 insertions(+), 1 deletions(-)

diff --git a/config-lib.sh b/config-lib.sh
index 68fecc5..69999a8 100755
--- a/config-lib.sh
+++ b/config-lib.sh
@@ -262,6 +262,7 @@ Installation directories:
 
 Miscellaneous options:
   --cc=COMPILER          use this C compiler to build MPlayer [gcc]
+  --perl=PATH            path to perl binary [autodetect]
   --target=PLATFORM      target platform (i386-linux, arm-linux, etc)
   --with-install=PATH    use a custom install program (useful if your OS uses
                          a GNU-incompatible install utility by default and
@@ -296,6 +297,8 @@ EOF
 
 		--cc=*)
 			_cc=`echo $ac_option | cut -d '=' -f 2` ;;
+		--perl=*)
+			_perl=`echo $ac_option | cut -d '=' -f 2` ;;
 		--target=*)
 			_target=`echo $ac_option | cut -d '=' -f 2` ;;
 		--with-install=*)
@@ -409,8 +412,21 @@ int main(void) { return 0; }
 EOF
 	{ cc_check && tmp_run; } || die "unusable compiler or produced binary"
 	echores yes
-}
 
+	echocheck "for perl"
+	if test -z "$_perl" ; then
+		_perl=`which perl`
+		test "$_perl" || die "cannot find path to perl"
+	fi
+	echores "$_perl"
+
+	echocheck "perl version"
+	_perl_version=`"$_perl" -e 'require 5.6.0;printf "%vd", $^V'`
+	if test -z "$_perl_version" ; then
+		die "your perl version is too old"
+	fi
+	echores "$_perl_version"
+}
 
 write_config() {
 	echo "Creating config.mak.autogen"
@@ -420,6 +436,7 @@ write_config() {
 # -------- Generated by configure -----------
 
 CC = $_cc
+PERL_PATH = $_perl
 INSTALL = $_install
 
 EOF
-- 
1.4.1

^ permalink raw reply related

* [PATCH 2/3] configure: Add test for Python
From: Dennis Stosberg @ 2006-07-06 12:40 UTC (permalink / raw)
  To: git

The test tries to find the path to a suitable Python binary.
It also adds a --python=/path parameter to override the autodetection.

Signed-off-by: Dennis Stosberg <dennis@stosberg.net>
---
 config-lib.sh |   22 ++++++++++++++++++++++
 1 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/config-lib.sh b/config-lib.sh
index 69999a8..50ad6e9 100755
--- a/config-lib.sh
+++ b/config-lib.sh
@@ -263,6 +263,7 @@ Installation directories:
 Miscellaneous options:
   --cc=COMPILER          use this C compiler to build MPlayer [gcc]
   --perl=PATH            path to perl binary [autodetect]
+  --python=PATH          path to python binary [autodetect]
   --target=PLATFORM      target platform (i386-linux, arm-linux, etc)
   --with-install=PATH    use a custom install program (useful if your OS uses
                          a GNU-incompatible install utility by default and
@@ -299,6 +300,8 @@ EOF
 			_cc=`echo $ac_option | cut -d '=' -f 2` ;;
 		--perl=*)
 			_perl=`echo $ac_option | cut -d '=' -f 2` ;;
+		--python=*)
+			_python=`echo $ac_option | cut -d '=' -f 2` ;;
 		--target=*)
 			_target=`echo $ac_option | cut -d '=' -f 2` ;;
 		--with-install=*)
@@ -426,6 +429,24 @@ EOF
 		die "your perl version is too old"
 	fi
 	echores "$_perl_version"
+
+	echocheck "for python"
+	for __py_bin in python python2.4 python2.3; do
+		test "$_python" && continue
+
+		__candidate=`which $__py_bin`
+		test "$__candidate" || continue
+
+		$__candidate - <<EOF || continue
+import sys
+v = sys.version_info
+if v < (2, 3):
+    sys.exit(1)
+EOF
+		_python=$__candidate
+	done
+	test "$_python" || die "cannot find path to python"
+	echores "$_python"
 }
 
 write_config() {
@@ -437,6 +458,7 @@ # -------- Generated by configure ------
 
 CC = $_cc
 PERL_PATH = $_perl
+PYTHON_PATH = $_python
 INSTALL = $_install
 
 EOF
-- 
1.4.1

^ permalink raw reply related

* [RFH] further upload-pack/fetch-pack tweaks
From: Junio C Hamano @ 2006-07-06  8:43 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, Ralf Baechle, Linus Torvalds

I was reviewing this issue and have an updated attempt to solve
the issue slightly differently.  I think I have something
working but would like to borrow extra sets of eyeballs.

    From: Junio C Hamano <junkio@cox.net>
    Subject: [PATCH/RFC] upload-pack: stop "ack continue" when we know common commits for wanted refs
    To: Ralf Baechle <ralf@linux-mips.org>
    cc: git@vger.kernel.org, Linus Torvalds <torvalds@osdl.org>
    Date: Fri, 26 May 2006 19:20:54 -0700
    Message-ID: <7vfyiwi4xl.fsf@assigned-by-dhcp.cox.net>

    When the downloader's repository has more roots than the server
    side has, the "have" exchange to figure out recent common
    commits ends up traversing the whole history of branches that
    only exist on the downloader's side.  When the downloader is
    asking for newer commits on the branch that exists on both ends,
    this is totally unnecessary.

    This adds logic to the server side to see if the wanted refs can
    reach the "have" commits received so far, and stop issuing "ack
    continue" once all of them can be reached from "have" commits.

The idea in the new implementation is to notice that the
downloader sent "have" for an object we do not know about, and
when we already have some "have" from them and some "want" are
still not known if they are already reachable from these
"have"s, we traverse the commit ancestry down to oldest "have"s
so far (this is just a heuristic) to see if all of "want" have
some common ancestor with the other side.  When we know all
"want" can be reachable by some "have" we have seen so far, we
send "ACK continue" when the downloader sends a "have" that we
do not have, to cause the downloader to stop traversing that
futile branch which leads to the root we do not have.  The code
sits near the tip of "pu".

I've started from a clone of git.git repository and tried to
fetch "todo" branch from another clone that does not have
anything but the "todo" branch.  So the downloader has five
extra roots (one for git.git itself, one for gitk, one for
gitweb, and one each for htmldocs and manpages).

        # upstream is just "todo" branch and nothing else
        git clone -n git.git upstream
        cd upstream
        mv .git/refs trash
        mkdir -p .git/refs/heads .git/refs/tags
        echo 'ref: refs/heads/master' >.git/HEAD
        cat trash/heads/todo >.git/refs/heads/master
        git repack -a -d
        cd ..

        # downloader has up-to-date git.git but stale "todo"
	git clone -n git.git downloader
        cd downloader
        git checkout todo
        git reset --hard HEAD~30
        git repack -a -d

        # try downloading things from upstream
        git fetch-pack -k -v ../upstream master 2>/var/tmp/new.out
	git fetch-pack -k -v --exec=old-git-upload-pack \
        	../upstream master 2>/var/tmp/old.out


It does send smaller number of "have"s than the current code,
but I noticed that near the end of transfer, after it gets an
"ACK continue" for a common commit on "todo" branch and an "ACK
continue" for a not-common commit on "master" branch, it keeps
sending the commits that are marked on the fetch-pack side as
COMMON_REF (so the last ref sent is v0.99^0 commit), although
upload-pack has told the downloader that whatever is reachable
from "master" branch are commits both sides agreed are common,
so I suspect it should not go down that path that far to reach
v0.99^0 commit.

I have a feeling that either get_rev() or mark_common() logic is
not marking ancestors of commit that are known to be common
properly.  Does this ring a bell?

^ permalink raw reply

* git on HP-UX
From: Michal Rokos @ 2006-07-06  7:50 UTC (permalink / raw)
  To: git

Hello,

I needed following changes in order to make git compile on HP-UX:
# uname -s -r -m
HP-UX B.11.11 9000/800

Packages installed:
OpenSSL	A.00.09.07-d.002
perl		B.5.6.1.C
+ unofficial:
gcc		4.1.1
libiconv	1.10
make	3.80
zlib		1.2.3

Has to be compiled with:
PERL_PATH=/opt/perl/bin/perl gmake prefix=/opt/git install

Please keep me on CC (I'm not subscribed).

Signed-off-by: Michal Rokos <michal.rokos@nextsoft.cz>

--- a/Makefile
+++ b/Makefile
@@ -328,6 +328,17 @@ ifeq ($(uname_S),IRIX64)
 	# for now, build 32-bit version
 	ALL_LDFLAGS += -L/usr/lib32
 endif
+ifeq ($(uname_S),HP-UX)
+	NO_IPV6 = YesPlease
+	NO_CURL = YesPlease
+	NO_SETENV = YesPlease
+	NO_STRCASESTR = YesPlease
+	NO_STRLCPY = YesPlease
+	NEEDS_LIBICONV = YesPlease
+	ALL_CFLAGS += -D_REENTRANT -D_XOPEN_SOURCE -D_HPUX_SOURCE -I/opt/openssl/include -Dhstrerror=strerror
+	ALL_LDFLAGS += -L/opt/openssl/lib
+	INSTALL = $(PWD)/compat/compat_install
+endif
 ifneq (,$(findstring arm,$(uname_M)))
 	ARM_SHA1 = YesPlease
 endif
--- a/compat/compat_install	2006-07-06 09:31:27.000000000 +0200
+++ b/compat/compat_install	2006-07-06 09:31:18.000000000 +0200
@@ -0,0 +1,34 @@
+#!/usr/bin/sh
+#
+# Copyright (c) 2006 Michal Rokos
+#
+# Dummy 'install' replacement intended to be used
+# on HP-UX under sh-posix.
+
+while getopts 'dm:' opt; do
+    case $opt in
+    d) DIR_MODE=1;;
+    m) MODE=$OPTARG;;
+    \?) echo "Unknown argument $OPTARG"; exit 1;;
+    esac
+done
+shift $((OPTIND-1))
+
+if [[ -n "$DIR_MODE" ]] && [[ -n "$MODE" ]]; then
+    mkdir -p -m "$MODE" "$@"
+elif [[ -n "$DIR_MODE" ]]; then
+    mkdir -p "$@"
+else
+    set -A args "$@"
+    last=$#
+    dest=${args[last-1]}
+    unset args[last-1]
+    set "${args[@]}"
+
+    cp "$@" "$dest"
+
+    [[ -n "$MODE" ]] && chmod "$MODE" "$@"
+fi
+
+exit 0
+

-- 
Michal Rokos

NextSoft s.r.o.
Vyskočilova 1/1410
140 21 Praha 4
phone:  +420 267 224 311
fax:    +420 267 224 307
mobile: +420 736 646 591
e-mail: michal.rokos@nextsoft.cz

^ permalink raw reply

* Re: comparing file contents in is_exact_match?
From: Martin Waitz @ 2006-07-06  7:41 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vwtar89wy.fsf@assigned-by-dhcp.cox.net>

[-- Attachment #1: Type: text/plain, Size: 539 bytes --]

On Thu, Jul 06, 2006 at 12:33:33AM -0700, Junio C Hamano wrote:
> Martin Waitz <tali@admingilde.org> writes:
> > so perhaps we need three phases instead of two:
> > first sort out all renames that can be detected by the sha1,
> > then compare file contents and finally do the diff.
> 
> Makes sort-of sense.
> 
> Although I am not sure how much this would help with a regular
> workload, maybe something like this untested patch might help
> your situation?

patch looks good, I'll try it in the evening.

-- 
Martin Waitz

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: comparing file contents in is_exact_match?
From: Junio C Hamano @ 2006-07-06  7:33 UTC (permalink / raw)
  To: Martin Waitz; +Cc: git
In-Reply-To: <20060706071629.GB12512@admingilde.org>

Martin Waitz <tali@admingilde.org> writes:

>> Because your working tree can be out of sync with respect to
>> what's in the index, in which case we cannot trust the sha1
>> while running diff-index (without --cached flag).
>
> so perhaps we need three phases instead of two:
> first sort out all renames that can be detected by the sha1,
> then compare file contents and finally do the diff.

Makes sort-of sense.

Although I am not sure how much this would help with a regular
workload, maybe something like this untested patch might help
your situation?

-- >8 --
diffcore-rename: try matching up renames without populating filespec first

Signed-off-by: Junio C Hamano <junkio@cox.net>

---
diff --git a/diffcore-rename.c b/diffcore-rename.c
index d57e865..affff7a 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -96,11 +96,15 @@ static struct diff_rename_src *register_
 	return &(rename_src[first]);
 }
 
-static int is_exact_match(struct diff_filespec *src, struct diff_filespec *dst)
+static int is_exact_match(struct diff_filespec *src,
+			  struct diff_filespec *dst,
+			  int contents_too)
 {
 	if (src->sha1_valid && dst->sha1_valid &&
 	    !memcmp(src->sha1, dst->sha1, 20))
 		return 1;
+	if (!contents_too)
+		return 0;
 	if (diff_populate_filespec(src, 1) || diff_populate_filespec(dst, 1))
 		return 0;
 	if (src->size != dst->size)
@@ -242,7 +246,7 @@ void diffcore_rename(struct diff_options
 	struct diff_queue_struct *q = &diff_queued_diff;
 	struct diff_queue_struct outq;
 	struct diff_score *mx;
-	int i, j, rename_count;
+	int i, j, rename_count, contents_too;
 	int num_create, num_src, dst_cnt;
 
 	if (!minimum_score)
@@ -273,16 +277,23 @@ void diffcore_rename(struct diff_options
 
 	/* We really want to cull the candidates list early
 	 * with cheap tests in order to avoid doing deltas.
+	 * The first round matches up the up-to-date entries,
+	 * and then during the second round we try to match
+	 * cache-dirty entries as well.
 	 */
-	for (i = 0; i < rename_dst_nr; i++) {
-		struct diff_filespec *two = rename_dst[i].two;
-		for (j = 0; j < rename_src_nr; j++) {
-			struct diff_filespec *one = rename_src[j].one;
-			if (!is_exact_match(one, two))
-				continue;
-			record_rename_pair(i, j, MAX_SCORE);
-			rename_count++;
-			break; /* we are done with this entry */
+	for (contents_too = 0; contents_too < 2; contents_too++) { 
+		for (i = 0; i < rename_dst_nr; i++) {
+			struct diff_filespec *two = rename_dst[i].two;
+			if (rename_dst[i].pair)
+				continue; /* dealt with an earlier round */
+			for (j = 0; j < rename_src_nr; j++) {
+				struct diff_filespec *one = rename_src[j].one;
+				if (!is_exact_match(one, two, contents_too))
+					continue;
+				record_rename_pair(i, j, MAX_SCORE);
+				rename_count++;
+				break; /* we are done with this entry */
+			}
 		}
 	}
 

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox