lab 10 Working with Changes Directly
Goals
- Now that you’ve learned how git works with changes to files rather than files themselves, you will learn how to manipulate changes before staging them.
Git provides rich functionality to choose precisely what changes you want to stage. This includes both choosing individual lines to stage as well as editing the changes before they are staged without changing the existing file. These capabilities allow you to make and commit secondary changes while working on a task with minimal distractions.
First Change: Allow Any Number of Names
Change the “Hello, World” program to allow users to input any number of names.
hello.rb
name = ARGV || ["World"] puts "Hello, #{name.join(" ")}!"
Add and Commit the Change
Now you’ll add the change using git add --patch
. This will present you with an interactive interface to select “hunks” which are sets of changes. For now, you’ll have one hunk. Press the ‘y’ key to select it for staging. You can press the ‘?’ key to get help about the other options.
Execute:
git add --patch
Execute:
git commit -m "Can specify multiple names"
Note: I used a utility called yes
to simulate pressing the ‘y’ key when the git add --patch
command prompted me for it. I recommend you don’t do this and instead enter your input manually.
Output:
$ git add --patch diff --git a/hello.rb b/hello.rb index 437e63c..d6755ed 100644 --- a/hello.rb +++ b/hello.rb @@ -1,4 +1,3 @@ -# Default is "World" -name = ARGV.first || "World" +name = ARGV || ["World"] -puts "Hello, #{name}!" +puts "Hello, #{name.join(" ")}!" (1/1) Stage this hunk [y,n,q,a,d,s,e,?]? $ git commit -m "Can specify multiple names" [main 8cdd2cd] Can specify multiple names 1 file changed, 2 insertions(+), 3 deletions(-)
Second Change: Add Some More Output
Change the “Hello, World” program to print out the number of names a user entered.
hello.rb
name = ARGV || ["World"] puts "Hello, #{name.join(" ")}!" puts "You have #{name.length} names!"
Third Change: Rename the name
Variable
The name
variable is indicating it’s singular when it’s actually plural. Change its name to match its usage.
hello.rb
names = ARGV || ["World"] puts "Hello, #{names.join(" ")}!" puts "You have #{names.length} names!"
Add The Changes
Now you’ve made two changes which should be committed as two commits. Instead of undoing one of the changes, committing it, and redoing it you’ll use git add --patch
to let you do it directly. Run the following command and press the ‘e’ key when prompted.
Execute:
git add --patch
You’ll see the following open up in your editor. It is a description of the changes git will stage when the file is saved and closed. Editing this file will change exactly what is staged.
Output:
# Manual hunk edit mode -- see bottom for a quick guide. @@ -1,3 +1,4 @@ -name = ARGV || ["World"] +names = ARGV || ["World"] -puts "Hello, #{name.join(" ")}!" +puts "Hello, #{names.join(" ")}!" +puts "You have #{names.length} names!" # --- # To remove '-' lines, make them ' ' lines (context). # To remove '+' lines, delete them. # Lines starting with # will be removed. # # If the patch applies cleanly, the edited hunk will immediately be # marked for staging. # If it does not apply cleanly, you will be given an opportunity to # edit again. If all lines of the hunk are removed, then the edit is # aborted and the hunk is left unchanged.
Let’s do the variable rename first. Edit the file so it matches the example below. I just removed the last line starting with a ‘+’.
Output:
# Manual hunk edit mode -- see bottom for a quick guide. @@ -1,3 +1,4 @@ -name = ARGV || ["World"] +names = ARGV || ["World"] -puts "Hello, #{name.join(" ")}!" +puts "Hello, #{names.join(" ")}!" # --- # To remove '-' lines, make them ' ' lines (context). # To remove '+' lines, delete them. # Lines starting with # will be removed. # # If the patch applies cleanly, the edited hunk will immediately be # marked for staging. # If it does not apply cleanly, you will be given an opportunity to # edit again. If all lines of the hunk are removed, then the edit is # aborted and the hunk is left unchanged.
Save and exit, then let’s check that we did everything correctly.
Execute:
git diff --staged
You should see output like below
Note: the --staged
option to git diff
will only show your currently staged changes.
Output:
$ git diff --staged diff --git a/hello.rb b/hello.rb index d6755ed..42754aa 100644 --- a/hello.rb +++ b/hello.rb @@ -1,3 +1,4 @@ -name = ARGV || ["World"] +names = ARGV || ["World"] -puts "Hello, #{name.join(" ")}!" +puts "Hello, #{names.join(" ")}!" +puts "You have #{names.length} names!"
Finally let’s commit the change.
Execute:
git commit -m "Rename variable to match its usage"
Output:
$ git commit -m "Rename variable to match its usage" [main c72af6b] Rename variable to match its usage 1 file changed, 3 insertions(+), 2 deletions(-)
Now you’ll add the new output. This one isn’t necessary to edit, so you can just press the ‘y’ key to add it.
Execute:
git add --patch
Execute:
git commit -m "Tell user how many names they have"
Output:
$ git add --patch diff --git a/hello.rb b/hello.rb index 42754aa..1910891 100644 --- a/hello.rb +++ b/hello.rb @@ -2,3 +2,4 @@ names = ARGV || ["World"] puts "Hello, #{names.join(" ")}!" puts "You have #{names.length} names!" +puts "You have #{names.length} names!" (1/1) Stage this hunk [y,n,q,a,d,e,?]? $ git commit -m "Tell user how many names they have" [main 1dee7f9] Tell user how many names they have 1 file changed, 1 insertion(+)
Wrapping Up
In this lab you learned how to interact directly with the changes to be staged before they are staged. You simply staged some lines independently of others, but you could also have modified the content of the lines as well. Note that while the interface through git can be somewhat cumbersome there are several tools that integrate with your editor to do this for you. Here is an example of one for VSCode