Skip to content

Instantly share code, notes, and snippets.

@jaymcgavren
Last active March 27, 2023 11:41
Show Gist options
  • Save jaymcgavren/5834920 to your computer and use it in GitHub Desktop.
Save jaymcgavren/5834920 to your computer and use it in GitHub Desktop.
"Monkey cherry-picking": Freehand patching via Git and the clipboard...

I run a diff of my current branch versus a different one that has some stuff I want:

$ git diff HEAD subscribers_decorator | cat
diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb
index 245393c..6a1639a 100644
...

Big 'ol list of stuff I don't want...

Followed by a portion that I do want... Which I manually copy.

pbpaste shows you the clipboard contents on OSX. xclip should do the same on Linux.

$ pbpaste
diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb
index 245393c..6a1639a 100644
--- a/app/controllers/posts_controller.rb
+++ b/app/controllers/posts_controller.rb
@@ -22,7 +23,8 @@ class PostsController < ApplicationController
   end

   def create
-    @post = Post.new(post_params)
+    @post = PostDecorator.new(Post.new(post_params))
+    @post.user = User.create
     @post.tag_list = tag_params[:tag_list]
     if @post.save
       redirect_to @post, notice: 'Post was successfully created.'
diff --git a/app/decorators/post_decorator.rb b/app/decorators/post_decorator.rb
new file mode 100644
index 0000000..eea3b86
--- /dev/null
+++ b/app/decorators/post_decorator.rb
@@ -0,0 +1,21 @@
+class PostDecorator
+  def initialize(post)
+    @post = post
+  end
+  def method_missing(method_name, *args, &block)
+    @post.send(method_name, *args, &block)
+  end
+  def respond_to_missing?(method_name, include_private = false)
+    super || @post.respond_to?(method_name, include_private)
+  end
+  def save
+    if @post.save
+      user.subscribers.each do |subscriber|
+        SubscriberMailer.update(subscriber, self).deliver
+      end
+    end
+  end
+  def formatted_date
+    @post.created_at.strftime('%Y-%m-%d')
+  end
+end

Note that it spans multiple files. I even took a one change that I wanted from one file and ignored the rest.

Here's the cool part. git apply - takes a patch from STDIN...

$ pbpaste | git apply -

Now, look: The files are actually updated based on the patch contents from the clipboard!

$ git add .
$ git diff --staged | cat
diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb
index 245393c..0fc053c 100644
--- a/app/controllers/posts_controller.rb
+++ b/app/controllers/posts_controller.rb
@@ -22,7 +22,8 @@ class PostsController < ApplicationController
   end

   def create
-    @post = Post.new(post_params)
+    @post = PostDecorator.new(Post.new(post_params))
+    @post.user = User.create
     @post.tag_list = tag_params[:tag_list]
     if @post.save
       redirect_to @post, notice: 'Post was successfully created.'
diff --git a/app/decorators/post_decorator.rb b/app/decorators/post_decorator.rb
new file mode 100644
index 0000000..eea3b86
--- /dev/null
+++ b/app/decorators/post_decorator.rb
@@ -0,0 +1,21 @@
+class PostDecorator
+  def initialize(post)
+    @post = post
+  end
+  def method_missing(method_name, *args, &block)
+    @post.send(method_name, *args, &block)
+  end
+  def respond_to_missing?(method_name, include_private = false)
+    super || @post.respond_to?(method_name, include_private)
+  end
+  def save
+    if @post.save
+      user.subscribers.each do |subscriber|
+        SubscriberMailer.update(subscriber, self).deliver
+      end
+    end
+  end
+  def formatted_date
+    @post.created_at.strftime('%Y-%m-%d')
+  end
+end

From clipboard to working directory!

@weitzman
Copy link

weitzman commented May 8, 2018

Just what I needed today. "Monkey cherry pick" - love it!

@Izhaki
Copy link

Izhaki commented Sep 25, 2019

Cheerssssssss!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment