Class: Tetra::Git
- Inherits:
-
Object
- Object
- Tetra::Git
- Includes:
- Logging, ProcessRunner
- Defined in:
- lib/tetra/facades/git.rb
Overview
facade to git, currently implemented with calls to the git command
Instance Method Summary collapse
-
#archive(directory, id, destination_path) ⇒ Object
archives version id of directory in destination_path.
-
#changed_files(directory, id) ⇒ Object
returns the list of files changed from since_id including changes in the working tree and staging area.
-
#commit_directories(directories, message) ⇒ Object
adds all files in the specified directories, removes all files not in the specified directories, commits with message.
-
#commit_file(path, message) ⇒ Object
commits one single file.
-
#disable_special_files(path) ⇒ Object
renames git special files to ‘disable’ them.
-
#format_patch(directory, from_id, destination_path) ⇒ Object
generates patch files to changes to directory in destination_path since from_id.
-
#init ⇒ Object
inits a repo.
-
#initialize(directory) ⇒ Git
constructor
inits a new git manager object pointing to the specified directory.
-
#latest_comment(comment_prefix) ⇒ Object
returns the comment of the most recent commit that has the specified comment prefix in its message returns nil if such commit does not exist.
-
#latest_id(comment_prefix) ⇒ Object
returns the id of the most recent commit that has the specified comment prefix in its message returns nil if such commit does not exist.
-
#merge_with_id(path, new_path, id) ⇒ Object
3-way merges the git file at path with the one in new_path assuming they have a common ancestor at the specified id returns the conflict count.
-
#revert_directories(directories, id) ⇒ Object
reverts multiple directories’ contents as per specified id.
-
#undo_last_commit ⇒ Object
reverts the whole repo to the last commit while leaving changes in the working directory.
Methods included from ProcessRunner
Methods included from Logging
Constructor Details
#initialize(directory) ⇒ Git
inits a new git manager object pointing to the specified directory
13 14 15 |
# File 'lib/tetra/facades/git.rb', line 13 def initialize(directory) @directory = directory end |
Instance Method Details
#archive(directory, id, destination_path) ⇒ Object
archives version id of directory in destination_path
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/tetra/facades/git.rb', line 161 def archive(directory, id, destination_path) Dir.chdir(@directory) do FileUtils.mkdir_p(File.dirname(destination_path)) log.debug "archiving #{directory} from #{id} to #{destination_path}" # This streams stdout from git directly to stdin of xz without loading # data into Ruby memory (which could be big). git_command = ["git", "archive", "--format=tar", id, "--", directory] xz_command = ["xz", "-9e"] statuses = Open3.pipeline(git_command, xz_command, out: destination_path) unless statuses.all?(&:success?) fail ExecutionFailed.new( "git archive pipeline failed (exit codes: #{statuses.map(&:exitstatus)})", statuses.last.exitstatus ) end end destination_path end |
#changed_files(directory, id) ⇒ Object
returns the list of files changed from since_id including changes in the working tree and staging area
146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/tetra/facades/git.rb', line 146 def changed_files(directory, id) Dir.chdir(@directory) do tracked_files = [] begin tracked_files += git_cmd("diff-index", "--name-only", id, "--", directory).split rescue ExecutionFailed => e raise e if e.status != 1 end untracked_files = git_cmd("ls-files", "--exclude-standard", "--others", "--", directory).split tracked_files + untracked_files end end |
#commit_directories(directories, message) ⇒ Object
adds all files in the specified directories, removes all files not in the specified directories, commits with message
51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/tetra/facades/git.rb', line 51 def commit_directories(directories, ) log.debug "committing with message: #{}" Dir.chdir(@directory) do if directories.any? git_cmd("rm", "-r", "--cached", "--ignore-unmatch", *directories) git_cmd("add", *directories) end git_cmd_with_stdin(, "commit", "--allow-empty", "-F", "-") end end |
#commit_file(path, message) ⇒ Object
commits one single file
64 65 66 67 68 69 70 |
# File 'lib/tetra/facades/git.rb', line 64 def commit_file(path, ) Dir.chdir(@directory) do log.debug "committing path #{path} with message: #{}" git_cmd("add", path) git_cmd_with_stdin(, "commit", "--allow-empty", "-F", "-") end end |
#disable_special_files(path) ⇒ Object
renames git special files to ‘disable’ them
101 102 103 104 105 106 107 108 109 110 |
# File 'lib/tetra/facades/git.rb', line 101 def disable_special_files(path) Dir.chdir(File.join(@directory, path)) do # We look for .git directories or .gitignore files recursively Dir.glob("**/.git*", File::FNM_DOTMATCH).each do |file| next unless file.match?(/\.git(ignore)?$/) FileUtils.mv(file, "#{file}_disabled_by_tetra") end end end |
#format_patch(directory, from_id, destination_path) ⇒ Object
generates patch files to changes to directory in destination_path since from_id
186 187 188 189 190 |
# File 'lib/tetra/facades/git.rb', line 186 def format_patch(directory, from_id, destination_path) Dir.chdir(@directory) do git_cmd("format-patch", "-o", destination_path, "--no-numbered", from_id, "--", directory).split end end |
#init ⇒ Object
inits a repo
18 19 20 21 22 23 24 25 26 |
# File 'lib/tetra/facades/git.rb', line 18 def init Dir.chdir(@directory) do if Dir.exist?(".git") fail GitAlreadyInitedError else git_cmd("init") end end end |
#latest_comment(comment_prefix) ⇒ Object
returns the comment of the most recent commit that has the specified comment prefix in its message returns nil if such commit does not exist
41 42 43 44 45 46 |
# File 'lib/tetra/facades/git.rb', line 41 def latest_comment(comment_prefix) Dir.chdir(@directory) do id = latest_id(comment_prefix) git_cmd("log", "-1", "--format=%B", id) if id end end |
#latest_id(comment_prefix) ⇒ Object
returns the id of the most recent commit that has the specified comment prefix in its message returns nil if such commit does not exist
31 32 33 34 35 36 |
# File 'lib/tetra/facades/git.rb', line 31 def latest_id(comment_prefix) Dir.chdir(@directory) do result = git_cmd("rev-list", "--max-count=1", "--grep", comment_prefix, "--fixed-strings", "HEAD") result.strip unless result.empty? end end |
#merge_with_id(path, new_path, id) ⇒ Object
3-way merges the git file at path with the one in new_path assuming they have a common ancestor at the specified id returns the conflict count
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/tetra/facades/git.rb', line 115 def merge_with_id(path, new_path, id) Dir.chdir(@directory) do content = git_cmd("show", "#{id}:#{path}") # Write the old version file manually using Ruby temp_old_version = "#{path}.old_version" File.write(temp_old_version, content) conflict_count = 0 begin git_cmd("merge-file", path, temp_old_version, new_path, "-L", "newly generated", "-L", "previously generated", "-L", "user edited") rescue ExecutionFailed => e if e.status > 0 conflict_count = e.status else raise e end ensure # Clean up the temporary file File.delete(temp_old_version) if File.exist?(temp_old_version) end conflict_count end end |
#revert_directories(directories, id) ⇒ Object
reverts multiple directories’ contents as per specified id
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/tetra/facades/git.rb', line 73 def revert_directories(directories, id) Dir.chdir(@directory) do directories.each do |directory| git_cmd("checkout", "-f", id, "--", directory) # Returns list of files relative to current dir files_in_commit = git_cmd("ls-tree", "--name-only", "-r", id, "--", directory).split("\n") files_in_head = git_cmd("ls-tree", "--name-only", "-r", "HEAD", "--", directory).split("\n") files_added = git_cmd("ls-files", "-o", "--", directory).split("\n") files_to_delete = (files_in_head - files_in_commit) + files_added files_to_delete.each do |file| FileUtils.rm_rf(file) end end end end |
#undo_last_commit ⇒ Object
reverts the whole repo to the last commit while leaving changes in the working directory
94 95 96 97 98 |
# File 'lib/tetra/facades/git.rb', line 94 def undo_last_commit Dir.chdir(@directory) do git_cmd("reset", "HEAD~") end end |